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 (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
697 return((MagickOffsetType) -1);
701 for (i=0; i < (MagickOffsetType) length; i+=count)
703 #if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
719 #if !defined(MAGICKCORE_HAVE_PREAD)
720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
725 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
727 const unsigned char *restrict buffer)
729 register MagickOffsetType
735 cache_info->timestamp=time(0);
736 #if !defined(MAGICKCORE_HAVE_PWRITE)
737 LockSemaphoreInfo(cache_info->disk_semaphore);
738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
741 return((MagickOffsetType) -1);
745 for (i=0; i < (MagickOffsetType) length; i+=count)
747 #if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
763 #if !defined(MAGICKCORE_HAVE_PWRITE)
764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
769 static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
815 length=MagickMax(clone_info->columns,cache_info->columns)*
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
830 for (y=0; y < (ssize_t) rows; y++)
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
843 if (y < (ssize_t) rows)
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
850 if (clone_info->columns > cache_info->columns)
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
856 for (y=0; y < (ssize_t) rows; y++)
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
864 if (y < (ssize_t) rows)
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
889 for (y=0; y < (ssize_t) rows; y++)
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
902 if (y < (ssize_t) rows)
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
909 if (clone_info->columns > cache_info->columns)
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
915 for (y=0; y < (ssize_t) rows; y++)
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
923 if (y < (ssize_t) rows)
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
935 static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
976 length=MagickMax(clone_info->columns,cache_info->columns)*
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
990 for (y=0; y < (ssize_t) rows; y++)
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
997 q-=clone_info->columns;
998 (void) memcpy(q,indexes,(size_t) length);
999 if ((MagickSizeType) count != length)
1002 if (y < (ssize_t) rows)
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
1026 for (y=0; y < (ssize_t) rows; y++)
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1033 q-=clone_info->columns;
1034 (void) memcpy(q,pixels,(size_t) length);
1036 if (y < (ssize_t) rows)
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1047 static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1057 register PixelPacket
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1081 register IndexPacket
1086 Clone cache indexes.
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1102 for (y=0; y < (ssize_t) rows; y++)
1104 p-=cache_info->columns;
1105 (void) memcpy(indexes,p,(size_t) length);
1106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1112 if (y < (ssize_t) rows)
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1119 if (clone_info->columns > cache_info->columns)
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1125 for (y=0; y < (ssize_t) rows; y++)
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1133 if (y < (ssize_t) rows)
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1158 for (y=0; y < (ssize_t) rows; y++)
1160 p-=cache_info->columns;
1161 (void) memcpy(pixels,p,(size_t) length);
1162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1168 if (y < (ssize_t) rows)
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1175 if (clone_info->columns > cache_info->columns)
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
1181 for (y=0; y < (ssize_t) rows; y++)
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1189 if (y < (ssize_t) rows)
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1201 static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1204 register PixelPacket
1206 *restrict source_pixels;
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1223 register IndexPacket
1228 Clone cache indexes.
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
1232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
1237 for (y=0; y < (ssize_t) rows; y++)
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
1241 (void) memcpy(indexes,source_indexes,length);
1243 if (clone_info->columns > cache_info->columns)
1245 length=(clone_info->columns-cache_info->columns)*
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
1249 for (y=0; y < (ssize_t) rows; y++)
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
1262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
1267 for (y=0; y < (ssize_t) rows; y++)
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
1271 (void) memcpy(pixels,source_pixels,length);
1273 if (clone_info->columns > cache_info->columns)
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
1278 for (y=0; y < (ssize_t) rows; y++)
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1288 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1291 if (cache_info->type == PingCache)
1293 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1294 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1295 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1296 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1297 if (cache_info->type == DiskCache)
1298 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1299 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 + C l o n e P i x e l C a c h e M e t h o d s %
1311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1316 % The format of the ClonePixelCacheMethods() method is:
1318 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1320 % A description of each parameter follows:
1322 % o clone: Specifies a pointer to a Cache structure.
1324 % o cache: the pixel cache.
1327 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1333 assert(clone != (Cache) NULL);
1334 source_info=(CacheInfo *) clone;
1335 assert(source_info->signature == MagickSignature);
1336 if (source_info->debug != MagickFalse)
1337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1338 source_info->filename);
1339 assert(cache != (Cache) NULL);
1340 cache_info=(CacheInfo *) cache;
1341 assert(cache_info->signature == MagickSignature);
1342 source_info->methods=cache_info->methods;
1346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1350 + D e s t r o y I m a g e P i x e l C a c h e %
1354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1356 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1358 % The format of the DestroyImagePixelCache() method is:
1360 % void DestroyImagePixelCache(Image *image)
1362 % A description of each parameter follows:
1364 % o image: the image.
1367 static void DestroyImagePixelCache(Image *image)
1369 assert(image != (Image *) NULL);
1370 assert(image->signature == MagickSignature);
1371 if (image->debug != MagickFalse)
1372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1373 if (image->cache == (void *) NULL)
1375 image->cache=DestroyPixelCache(image->cache);
1379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383 + D e s t r o y I m a g e P i x e l s %
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1389 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1391 % The format of the DestroyImagePixels() method is:
1393 % void DestroyImagePixels(Image *image)
1395 % A description of each parameter follows:
1397 % o image: the image.
1400 MagickExport void DestroyImagePixels(Image *image)
1405 assert(image != (const Image *) NULL);
1406 assert(image->signature == MagickSignature);
1407 if (image->debug != MagickFalse)
1408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1409 assert(image->cache != (Cache) NULL);
1410 cache_info=(CacheInfo *) image->cache;
1411 assert(cache_info->signature == MagickSignature);
1412 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1414 cache_info->methods.destroy_pixel_handler(image);
1417 image->cache=DestroyPixelCache(image->cache);
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1425 + D e s t r o y P i x e l C a c h e %
1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1431 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1433 % The format of the DestroyPixelCache() method is:
1435 % Cache DestroyPixelCache(Cache cache)
1437 % A description of each parameter follows:
1439 % o cache: the pixel cache.
1443 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1445 switch (cache_info->type)
1449 if (cache_info->mapped == MagickFalse)
1450 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1451 cache_info->pixels);
1453 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1454 (size_t) cache_info->length);
1455 RelinquishMagickResource(MemoryResource,cache_info->length);
1460 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1461 cache_info->length);
1462 RelinquishMagickResource(MapResource,cache_info->length);
1466 if (cache_info->file != -1)
1467 (void) ClosePixelCacheOnDisk(cache_info);
1468 RelinquishMagickResource(DiskResource,cache_info->length);
1474 cache_info->type=UndefinedCache;
1475 cache_info->mapped=MagickFalse;
1476 cache_info->indexes=(IndexPacket *) NULL;
1479 MagickExport Cache DestroyPixelCache(Cache cache)
1484 assert(cache != (Cache) NULL);
1485 cache_info=(CacheInfo *) cache;
1486 assert(cache_info->signature == MagickSignature);
1487 if (cache_info->debug != MagickFalse)
1488 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1489 cache_info->filename);
1490 LockSemaphoreInfo(cache_info->semaphore);
1491 cache_info->reference_count--;
1492 if (cache_info->reference_count != 0)
1494 UnlockSemaphoreInfo(cache_info->semaphore);
1495 return((Cache) NULL);
1497 UnlockSemaphoreInfo(cache_info->semaphore);
1498 if (cache_resources != (SplayTreeInfo *) NULL)
1499 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1500 if (cache_info->debug != MagickFalse)
1503 message[MaxTextExtent];
1505 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1506 cache_info->filename);
1507 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1509 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1510 (cache_info->type != DiskCache)))
1511 RelinquishPixelCachePixels(cache_info);
1514 RelinquishPixelCachePixels(cache_info);
1515 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1517 *cache_info->cache_filename='\0';
1518 if (cache_info->nexus_info != (NexusInfo **) NULL)
1519 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1520 cache_info->number_threads);
1521 if (cache_info->random_info != (RandomInfo *) NULL)
1522 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1523 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1525 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1526 DestroySemaphoreInfo(&cache_info->semaphore);
1527 cache_info->signature=(~MagickSignature);
1528 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1538 + D e s t r o y P i x e l C a c h e N e x u s %
1542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1546 % The format of the DestroyPixelCacheNexus() method is:
1548 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1549 % const size_t number_threads)
1551 % A description of each parameter follows:
1553 % o nexus_info: the nexus to destroy.
1555 % o number_threads: the number of nexus threads.
1559 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1561 if (nexus_info->mapped == MagickFalse)
1562 (void) RelinquishMagickMemory(nexus_info->cache);
1564 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1565 nexus_info->cache=(PixelPacket *) NULL;
1566 nexus_info->pixels=(PixelPacket *) NULL;
1567 nexus_info->indexes=(IndexPacket *) NULL;
1568 nexus_info->length=0;
1569 nexus_info->mapped=MagickFalse;
1572 MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1573 const size_t number_threads)
1578 assert(nexus_info != (NexusInfo **) NULL);
1579 for (i=0; i < (ssize_t) number_threads; i++)
1581 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1582 RelinquishCacheNexusPixels(nexus_info[i]);
1583 nexus_info[i]->signature=(~MagickSignature);
1584 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1586 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595 + 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 %
1599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601 % GetAuthenticIndexesFromCache() returns the indexes associated with the last
1602 % call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1604 % The format of the GetAuthenticIndexesFromCache() method is:
1606 % IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1608 % A description of each parameter follows:
1610 % o image: the image.
1613 static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1619 id = GetOpenMPThreadId();
1621 assert(image != (const Image *) NULL);
1622 assert(image->signature == MagickSignature);
1623 assert(image->cache != (Cache) NULL);
1624 cache_info=(CacheInfo *) image->cache;
1625 assert(cache_info->signature == MagickSignature);
1626 assert(id < (int) cache_info->number_threads);
1627 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
1631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1635 % G e t A u t h e n t i c I n d e x Q u e u e %
1639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641 % GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1642 % indexes associated with the last call to QueueAuthenticPixels() or
1643 % GetVirtualPixels(). NULL is returned if the black channel or colormap
1644 % indexes are not available.
1646 % The format of the GetAuthenticIndexQueue() method is:
1648 % IndexPacket *GetAuthenticIndexQueue(const Image *image)
1650 % A description of each parameter follows:
1652 % o image: the image.
1655 MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1661 id = GetOpenMPThreadId();
1663 assert(image != (const Image *) NULL);
1664 assert(image->signature == MagickSignature);
1665 assert(image->cache != (Cache) NULL);
1666 cache_info=(CacheInfo *) image->cache;
1667 assert(cache_info->signature == MagickSignature);
1668 if (cache_info->methods.get_authentic_indexes_from_handler !=
1669 (GetAuthenticIndexesFromHandler) NULL)
1670 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1671 assert(id < (int) cache_info->number_threads);
1672 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
1676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1680 + 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 %
1684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1686 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1687 % disk pixel cache as defined by the geometry parameters. A pointer to the
1688 % pixels is returned if the pixels are transferred, otherwise a NULL is
1691 % The format of the GetAuthenticPixelCacheNexus() method is:
1693 % PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1694 % const ssize_t y,const size_t columns,const size_t rows,
1695 % NexusInfo *nexus_info,ExceptionInfo *exception)
1697 % A description of each parameter follows:
1699 % o image: the image.
1701 % o x,y,columns,rows: These values define the perimeter of a region of
1704 % o nexus_info: the cache nexus to return.
1706 % o exception: return any errors or warnings in this structure.
1710 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1711 NexusInfo *nexus_info)
1716 if (cache_info->type == PingCache)
1718 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1719 nexus_info->region.x;
1720 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1724 MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1725 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1726 NexusInfo *nexus_info,ExceptionInfo *exception)
1735 Transfer pixels from the cache.
1737 assert(image != (Image *) NULL);
1738 assert(image->signature == MagickSignature);
1739 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1740 if (pixels == (PixelPacket *) NULL)
1741 return((PixelPacket *) NULL);
1742 cache_info=(CacheInfo *) image->cache;
1743 assert(cache_info->signature == MagickSignature);
1744 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1746 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1747 return((PixelPacket *) NULL);
1748 if (cache_info->active_index_channel != MagickFalse)
1749 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1750 return((PixelPacket *) NULL);
1755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759 + 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 %
1763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1766 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1768 % The format of the GetAuthenticPixelsFromCache() method is:
1770 % PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1772 % A description of each parameter follows:
1774 % o image: the image.
1777 static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1783 id = GetOpenMPThreadId();
1785 assert(image != (const Image *) NULL);
1786 assert(image->signature == MagickSignature);
1787 assert(image->cache != (Cache) NULL);
1788 cache_info=(CacheInfo *) image->cache;
1789 assert(cache_info->signature == MagickSignature);
1790 assert(id < (int) cache_info->number_threads);
1791 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1799 % G e t A u t h e n t i c P i x e l Q u e u e %
1803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1805 % GetAuthenticPixelQueue() returns the authentic pixels associated with the
1806 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1808 % The format of the GetAuthenticPixelQueue() method is:
1810 % PixelPacket *GetAuthenticPixelQueue(const Image image)
1812 % A description of each parameter follows:
1814 % o image: the image.
1817 MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1823 id = GetOpenMPThreadId();
1825 assert(image != (const Image *) NULL);
1826 assert(image->signature == MagickSignature);
1827 assert(image->cache != (Cache) NULL);
1828 cache_info=(CacheInfo *) image->cache;
1829 assert(cache_info->signature == MagickSignature);
1830 if (cache_info->methods.get_authentic_pixels_from_handler !=
1831 (GetAuthenticPixelsFromHandler) NULL)
1832 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1833 assert(id < (int) cache_info->number_threads);
1834 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1842 % G e t A u t h e n t i c P i x e l s %
1846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1848 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1849 % region is successfully accessed, a pointer to a PixelPacket array
1850 % representing the region is returned, otherwise NULL is returned.
1852 % The returned pointer may point to a temporary working copy of the pixels
1853 % or it may point to the original pixels in memory. Performance is maximized
1854 % if the selected region is part of one row, or one or more full rows, since
1855 % then there is opportunity to access the pixels in-place (without a copy)
1856 % if the image is in memory, or in a memory-mapped file. The returned pointer
1857 % must *never* be deallocated by the user.
1859 % Pixels accessed via the returned pointer represent a simple array of type
1860 % PixelPacket. If the image type is CMYK or if the storage class is
1861 % PseduoClass, call GetAuthenticIndexQueue() after invoking
1862 % GetAuthenticPixels() to obtain the black color component or colormap indexes
1863 % (of type IndexPacket) corresponding to the region. Once the PixelPacket
1864 % (and/or IndexPacket) array has been updated, the changes must be saved back
1865 % to the underlying image using SyncAuthenticPixels() or they may be lost.
1867 % The format of the GetAuthenticPixels() method is:
1869 % PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1870 % const ssize_t y,const size_t columns,const size_t rows,
1871 % ExceptionInfo *exception)
1873 % A description of each parameter follows:
1875 % o image: the image.
1877 % o x,y,columns,rows: These values define the perimeter of a region of
1880 % o exception: return any errors or warnings in this structure.
1883 MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1884 const ssize_t y,const size_t columns,const size_t rows,
1885 ExceptionInfo *exception)
1891 id = GetOpenMPThreadId();
1893 assert(image != (Image *) NULL);
1894 assert(image->signature == MagickSignature);
1895 assert(image->cache != (Cache) NULL);
1896 cache_info=(CacheInfo *) image->cache;
1897 assert(cache_info->signature == MagickSignature);
1898 if (cache_info->methods.get_authentic_pixels_handler !=
1899 (GetAuthenticPixelsHandler) NULL)
1900 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1902 assert(id < (int) cache_info->number_threads);
1903 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1904 cache_info->nexus_info[id],exception));
1908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1912 + G e t A u t h e n t i c P i x e l s C a c h e %
1916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1918 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1919 % as defined by the geometry parameters. A pointer to the pixels is returned
1920 % if the pixels are transferred, otherwise a NULL is returned.
1922 % The format of the GetAuthenticPixelsCache() method is:
1924 % PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1925 % const ssize_t y,const size_t columns,const size_t rows,
1926 % ExceptionInfo *exception)
1928 % A description of each parameter follows:
1930 % o image: the image.
1932 % o x,y,columns,rows: These values define the perimeter of a region of
1935 % o exception: return any errors or warnings in this structure.
1938 static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1939 const ssize_t y,const size_t columns,const size_t rows,
1940 ExceptionInfo *exception)
1946 id = GetOpenMPThreadId();
1948 assert(image != (const Image *) NULL);
1949 assert(image->signature == MagickSignature);
1950 assert(image->cache != (Cache) NULL);
1951 cache_info=(CacheInfo *) image->cache;
1952 if (cache_info == (Cache) NULL)
1953 return((PixelPacket *) NULL);
1954 assert(cache_info->signature == MagickSignature);
1955 assert(id < (int) cache_info->number_threads);
1956 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1957 cache_info->nexus_info[id],exception));
1961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965 + G e t I m a g e E x t e n t %
1969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1971 % GetImageExtent() returns the extent of the pixels associated with the
1972 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1974 % The format of the GetImageExtent() method is:
1976 % MagickSizeType GetImageExtent(const Image *image)
1978 % A description of each parameter follows:
1980 % o image: the image.
1983 MagickExport MagickSizeType GetImageExtent(const Image *image)
1989 id = GetOpenMPThreadId();
1991 assert(image != (Image *) NULL);
1992 assert(image->signature == MagickSignature);
1993 if (image->debug != MagickFalse)
1994 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1995 assert(image->cache != (Cache) NULL);
1996 cache_info=(CacheInfo *) image->cache;
1997 assert(cache_info->signature == MagickSignature);
1998 assert(id < (int) cache_info->number_threads);
1999 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
2003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007 + G e t I m a g e P i x e l C a c h e %
2011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013 % GetImagePixelCache() ensures that there is only a single reference to the
2014 % pixel cache to be modified, updating the provided cache pointer to point to
2015 % a clone of the original pixel cache if necessary.
2017 % The format of the GetImagePixelCache method is:
2019 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2020 % ExceptionInfo *exception)
2022 % A description of each parameter follows:
2024 % o image: the image.
2026 % o clone: any value other than MagickFalse clones the cache pixels.
2028 % o exception: return any errors or warnings in this structure.
2031 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2037 Does the image match the pixel cache morphology?
2039 cache_info=(CacheInfo *) image->cache;
2040 if ((image->storage_class != cache_info->storage_class) ||
2041 (image->colorspace != cache_info->colorspace) ||
2042 (image->columns != cache_info->columns) ||
2043 (image->rows != cache_info->rows) ||
2044 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2045 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2046 return(MagickFalse);
2050 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2051 ExceptionInfo *exception)
2060 static MagickSizeType
2069 LockSemaphoreInfo(image->semaphore);
2070 if (cpu_throttle == 0)
2076 Set CPU throttle in milleseconds.
2078 cpu_throttle=MagickResourceInfinity;
2079 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2080 if (limit == (char *) NULL)
2081 limit=GetPolicyValue("throttle");
2082 if (limit != (char *) NULL)
2084 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2085 limit=DestroyString(limit);
2088 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2089 MagickDelay(cpu_throttle);
2090 if (time_limit == 0)
2093 Set the exire time in seconds.
2095 time_limit=GetMagickResourceLimit(TimeResource);
2096 cache_genesis=time((time_t *) NULL);
2098 if ((time_limit != MagickResourceInfinity) &&
2099 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
2100 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2101 assert(image->cache != (Cache) NULL);
2102 cache_info=(CacheInfo *) image->cache;
2103 destroy=MagickFalse;
2104 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2106 LockSemaphoreInfo(cache_info->semaphore);
2107 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2118 clone_image=(*image);
2119 clone_image.semaphore=AllocateSemaphoreInfo();
2120 clone_image.reference_count=1;
2121 clone_image.cache=ClonePixelCache(cache_info);
2122 clone_info=(CacheInfo *) clone_image.cache;
2123 status=OpenPixelCache(&clone_image,IOMode,exception);
2124 if (status != MagickFalse)
2126 if (clone != MagickFalse)
2127 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2128 if (status != MagickFalse)
2131 image->cache=clone_image.cache;
2134 DestroySemaphoreInfo(&clone_image.semaphore);
2136 UnlockSemaphoreInfo(cache_info->semaphore);
2138 if (destroy != MagickFalse)
2139 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2140 if (status != MagickFalse)
2143 Ensure the image matches the pixel cache morphology.
2145 image->taint=MagickTrue;
2146 image->type=UndefinedType;
2147 if (image->colorspace == GRAYColorspace)
2148 image->colorspace=RGBColorspace;
2149 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2150 status=OpenPixelCache(image,IOMode,exception);
2152 UnlockSemaphoreInfo(image->semaphore);
2153 if (status == MagickFalse)
2154 return((Cache) NULL);
2155 return(image->cache);
2159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163 % G e t O n e A u t h e n t i c P i x e l %
2167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2169 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2170 % location. The image background color is returned if an error occurs.
2172 % The format of the GetOneAuthenticPixel() method is:
2174 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2175 % const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2177 % A description of each parameter follows:
2179 % o image: the image.
2181 % o x,y: These values define the location of the pixel to return.
2183 % o pixel: return a pixel at the specified (x,y) location.
2185 % o exception: return any errors or warnings in this structure.
2188 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2189 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2197 assert(image != (Image *) NULL);
2198 assert(image->signature == MagickSignature);
2199 assert(image->cache != (Cache) NULL);
2200 cache_info=(CacheInfo *) image->cache;
2201 assert(cache_info->signature == MagickSignature);
2202 *pixel=image->background_color;
2203 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2204 (GetOneAuthenticPixelFromHandler) NULL)
2205 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2207 *pixel=image->background_color;
2208 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2209 if (pixels == (PixelPacket *) NULL)
2210 return(MagickFalse);
2216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220 + 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 %
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2226 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2227 % location. The image background color is returned if an error occurs.
2229 % The format of the GetOneAuthenticPixelFromCache() method is:
2231 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2232 % const ssize_t x,const ssize_t y,PixelPacket *pixel,
2233 % ExceptionInfo *exception)
2235 % A description of each parameter follows:
2237 % o image: the image.
2239 % o x,y: These values define the location of the pixel to return.
2241 % o pixel: return a pixel at the specified (x,y) location.
2243 % o exception: return any errors or warnings in this structure.
2246 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2247 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2253 id = GetOpenMPThreadId();
2258 assert(image != (const Image *) NULL);
2259 assert(image->signature == MagickSignature);
2260 assert(image->cache != (Cache) NULL);
2261 cache_info=(CacheInfo *) image->cache;
2262 assert(cache_info->signature == MagickSignature);
2263 *pixel=image->background_color;
2264 assert(id < (int) cache_info->number_threads);
2265 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2266 cache_info->nexus_info[id],exception);
2267 if (pixels == (PixelPacket *) NULL)
2268 return(MagickFalse);
2274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 % G e t O n e V i r t u a l M a g i c k P i x e l %
2282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284 % GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2285 % location. The image background color is returned if an error occurs. If
2286 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2288 % The format of the GetOneVirtualMagickPixel() method is:
2290 % MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2291 % const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2292 % ExceptionInfo exception)
2294 % A description of each parameter follows:
2296 % o image: the image.
2298 % o x,y: these values define the location of the pixel to return.
2300 % o pixel: return a pixel at the specified (x,y) location.
2302 % o exception: return any errors or warnings in this structure.
2305 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2306 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2307 ExceptionInfo *exception)
2313 id = GetOpenMPThreadId();
2315 register const IndexPacket
2318 register const PixelPacket
2321 assert(image != (const Image *) NULL);
2322 assert(image->signature == MagickSignature);
2323 assert(image->cache != (Cache) NULL);
2324 cache_info=(CacheInfo *) image->cache;
2325 assert(cache_info->signature == MagickSignature);
2326 assert(id < (int) cache_info->number_threads);
2327 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2328 1UL,1UL,cache_info->nexus_info[id],exception);
2329 GetMagickPixelPacket(image,pixel);
2330 if (pixels == (const PixelPacket *) NULL)
2331 return(MagickFalse);
2332 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2333 SetMagickPixelPacket(image,pixels,indexes,pixel);
2338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2342 % G e t O n e V i r t u a l M e t h o d P i x e l %
2346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2348 % GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2349 % location as defined by specified pixel method. The image background color
2350 % is returned if an error occurs. If you plan to modify the pixel, use
2351 % GetOneAuthenticPixel() instead.
2353 % The format of the GetOneVirtualMethodPixel() method is:
2355 % MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2356 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2357 % const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
2359 % A description of each parameter follows:
2361 % o image: the image.
2363 % o virtual_pixel_method: the virtual pixel method.
2365 % o x,y: These values define the location of the pixel to return.
2367 % o pixel: return a pixel at the specified (x,y) location.
2369 % o exception: return any errors or warnings in this structure.
2372 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2373 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2374 PixelPacket *pixel,ExceptionInfo *exception)
2380 id = GetOpenMPThreadId();
2385 assert(image != (const Image *) NULL);
2386 assert(image->signature == MagickSignature);
2387 assert(image->cache != (Cache) NULL);
2388 cache_info=(CacheInfo *) image->cache;
2389 assert(cache_info->signature == MagickSignature);
2390 *pixel=image->background_color;
2391 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2392 (GetOneVirtualPixelFromHandler) NULL)
2393 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2394 virtual_pixel_method,x,y,pixel,exception));
2395 assert(id < (int) cache_info->number_threads);
2396 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2397 cache_info->nexus_info[id],exception);
2398 if (pixels == (const PixelPacket *) NULL)
2399 return(MagickFalse);
2405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2409 % G e t O n e V i r t u a l P i x e l %
2413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2415 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2416 % (x,y) location. The image background color is returned if an error occurs.
2417 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2419 % The format of the GetOneVirtualPixel() method is:
2421 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2422 % const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2424 % A description of each parameter follows:
2426 % o image: the image.
2428 % o x,y: These values define the location of the pixel to return.
2430 % o pixel: return a pixel at the specified (x,y) location.
2432 % o exception: return any errors or warnings in this structure.
2435 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2436 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2442 id = GetOpenMPThreadId();
2447 assert(image != (const Image *) NULL);
2448 assert(image->signature == MagickSignature);
2449 assert(image->cache != (Cache) NULL);
2450 cache_info=(CacheInfo *) image->cache;
2451 assert(cache_info->signature == MagickSignature);
2452 *pixel=image->background_color;
2453 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2454 (GetOneVirtualPixelFromHandler) NULL)
2455 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2456 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2457 assert(id < (int) cache_info->number_threads);
2458 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2459 1UL,1UL,cache_info->nexus_info[id],exception);
2460 if (pixels == (const PixelPacket *) NULL)
2461 return(MagickFalse);
2467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471 + 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 %
2475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2477 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2478 % specified (x,y) location. The image background color is returned if an
2481 % The format of the GetOneVirtualPixelFromCache() method is:
2483 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2484 % const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
2485 % PixelPacket *pixel,ExceptionInfo *exception)
2487 % A description of each parameter follows:
2489 % o image: the image.
2491 % o virtual_pixel_method: the virtual pixel method.
2493 % o x,y: These values define the location of the pixel to return.
2495 % o pixel: return a pixel at the specified (x,y) location.
2497 % o exception: return any errors or warnings in this structure.
2500 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2501 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2502 PixelPacket *pixel,ExceptionInfo *exception)
2508 id = GetOpenMPThreadId();
2513 assert(image != (const Image *) NULL);
2514 assert(image->signature == MagickSignature);
2515 assert(image->cache != (Cache) NULL);
2516 cache_info=(CacheInfo *) image->cache;
2517 assert(cache_info->signature == MagickSignature);
2518 assert(id < (int) cache_info->number_threads);
2519 *pixel=image->background_color;
2520 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2521 cache_info->nexus_info[id],exception);
2522 if (pixels == (const PixelPacket *) NULL)
2523 return(MagickFalse);
2529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2533 + G e t P i x e l C a c h e C o l o r s p a c e %
2537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2539 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2541 % The format of the GetPixelCacheColorspace() method is:
2543 % Colorspace GetPixelCacheColorspace(Cache cache)
2545 % A description of each parameter follows:
2547 % o cache: the pixel cache.
2550 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2555 assert(cache != (Cache) NULL);
2556 cache_info=(CacheInfo *) cache;
2557 assert(cache_info->signature == MagickSignature);
2558 if (cache_info->debug != MagickFalse)
2559 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2560 cache_info->filename);
2561 return(cache_info->colorspace);
2565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2569 + G e t P i x e l C a c h e M e t h o d s %
2573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2575 % GetPixelCacheMethods() initializes the CacheMethods structure.
2577 % The format of the GetPixelCacheMethods() method is:
2579 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2581 % A description of each parameter follows:
2583 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2586 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2588 assert(cache_methods != (CacheMethods *) NULL);
2589 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2590 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2591 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2592 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2593 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2594 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2595 cache_methods->get_authentic_indexes_from_handler=
2596 GetAuthenticIndexesFromCache;
2597 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2598 cache_methods->get_one_authentic_pixel_from_handler=
2599 GetOneAuthenticPixelFromCache;
2600 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2601 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2602 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610 + G e t P i x e l C a c h e N e x u s E x t e n t %
2614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2616 % GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2617 % the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2619 % The format of the GetPixelCacheNexusExtent() method is:
2621 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2622 % NexusInfo *nexus_info)
2624 % A description of each parameter follows:
2626 % o nexus_info: the nexus info.
2629 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2630 NexusInfo *nexus_info)
2638 assert(cache != (const Cache) NULL);
2639 cache_info=(CacheInfo *) cache;
2640 assert(cache_info->signature == MagickSignature);
2641 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2643 return((MagickSizeType) cache_info->columns*cache_info->rows);
2648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2652 + 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 %
2656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2658 % GetPixelCacheNexusIndexes() returns the indexes associated with the
2659 % specified cache nexus.
2661 % The format of the GetPixelCacheNexusIndexes() method is:
2663 % IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2664 % NexusInfo *nexus_info)
2666 % A description of each parameter follows:
2668 % o cache: the pixel cache.
2670 % o nexus_info: the cache nexus to return the colormap indexes.
2673 MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2674 NexusInfo *nexus_info)
2679 assert(cache != (const Cache) NULL);
2680 cache_info=(CacheInfo *) cache;
2681 assert(cache_info->signature == MagickSignature);
2682 if (cache_info->storage_class == UndefinedClass)
2683 return((IndexPacket *) NULL);
2684 return(nexus_info->indexes);
2688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2692 + G e t P i x e l C a c h e N e x u s P i x e l s %
2696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2698 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2701 % The format of the GetPixelCacheNexusPixels() method is:
2703 % PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2704 % NexusInfo *nexus_info)
2706 % A description of each parameter follows:
2708 % o cache: the pixel cache.
2710 % o nexus_info: the cache nexus to return the pixels.
2713 MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2714 NexusInfo *nexus_info)
2719 assert(cache != (const Cache) NULL);
2720 cache_info=(CacheInfo *) cache;
2721 assert(cache_info->signature == MagickSignature);
2722 if (cache_info->storage_class == UndefinedClass)
2723 return((PixelPacket *) NULL);
2724 return(nexus_info->pixels);
2728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2732 + G e t P i x e l C a c h e P i x e l s %
2736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2738 % GetPixelCachePixels() returns the pixels associated with the specified image.
2740 % The format of the GetPixelCachePixels() method is:
2742 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2743 % ExceptionInfo *exception)
2745 % A description of each parameter follows:
2747 % o image: the image.
2749 % o length: the pixel cache length.
2751 % o exception: return any errors or warnings in this structure.
2754 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2755 ExceptionInfo *exception)
2760 assert(image != (const Image *) NULL);
2761 assert(image->signature == MagickSignature);
2762 assert(image->cache != (Cache) NULL);
2763 cache_info=(CacheInfo *) image->cache;
2764 assert(cache_info->signature == MagickSignature);
2766 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2767 return((void *) NULL);
2768 *length=cache_info->length;
2769 return((void *) cache_info->pixels);
2773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777 + 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 %
2781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2783 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2785 % The format of the GetPixelCacheStorageClass() method is:
2787 % ClassType GetPixelCacheStorageClass(Cache cache)
2789 % A description of each parameter follows:
2791 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2793 % o cache: the pixel cache.
2796 MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2801 assert(cache != (Cache) NULL);
2802 cache_info=(CacheInfo *) cache;
2803 assert(cache_info->signature == MagickSignature);
2804 if (cache_info->debug != MagickFalse)
2805 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2806 cache_info->filename);
2807 return(cache_info->storage_class);
2811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2815 + G e t P i x e l C a c h e T i l e S i z e %
2819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2821 % GetPixelCacheTileSize() returns the pixel cache tile size.
2823 % The format of the GetPixelCacheTileSize() method is:
2825 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2828 % A description of each parameter follows:
2830 % o image: the image.
2832 % o width: the optimize cache tile width in pixels.
2834 % o height: the optimize cache tile height in pixels.
2837 MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2840 assert(image != (Image *) NULL);
2841 assert(image->signature == MagickSignature);
2842 if (image->debug != MagickFalse)
2843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2844 *width=2048UL/sizeof(PixelPacket);
2845 if (GetPixelCacheType(image) == DiskCache)
2846 *width=8192UL/sizeof(PixelPacket);
2851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2855 + G e t P i x e l C a c h e T y p e %
2859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2861 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2863 % The format of the GetPixelCacheType() method is:
2865 % CacheType GetPixelCacheType(const Image *image)
2867 % A description of each parameter follows:
2869 % o image: the image.
2872 MagickExport CacheType GetPixelCacheType(const Image *image)
2877 assert(image != (Image *) NULL);
2878 assert(image->signature == MagickSignature);
2879 assert(image->cache != (Cache) NULL);
2880 cache_info=(CacheInfo *) image->cache;
2881 assert(cache_info->signature == MagickSignature);
2882 return(cache_info->type);
2886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2890 + 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 %
2894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2896 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2897 % pixel cache. A virtual pixel is any pixel access that is outside the
2898 % boundaries of the image cache.
2900 % The format of the GetPixelCacheVirtualMethod() method is:
2902 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2904 % A description of each parameter follows:
2906 % o image: the image.
2909 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2914 assert(image != (Image *) NULL);
2915 assert(image->signature == MagickSignature);
2916 assert(image->cache != (Cache) NULL);
2917 cache_info=(CacheInfo *) image->cache;
2918 assert(cache_info->signature == MagickSignature);
2919 return(cache_info->virtual_pixel_method);
2923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927 + 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 %
2931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2933 % GetVirtualIndexesFromCache() returns the indexes associated with the last
2934 % call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2936 % The format of the GetVirtualIndexesFromCache() method is:
2938 % IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2940 % A description of each parameter follows:
2942 % o image: the image.
2945 static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2951 id = GetOpenMPThreadId();
2953 assert(image != (const Image *) NULL);
2954 assert(image->signature == MagickSignature);
2955 assert(image->cache != (Cache) NULL);
2956 cache_info=(CacheInfo *) image->cache;
2957 assert(cache_info->signature == MagickSignature);
2958 assert(id < (int) cache_info->number_threads);
2959 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
2963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2967 + 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 %
2971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2973 % GetVirtualIndexesFromNexus() returns the indexes associated with the
2974 % specified cache nexus.
2976 % The format of the GetVirtualIndexesFromNexus() method is:
2978 % const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2979 % NexusInfo *nexus_info)
2981 % A description of each parameter follows:
2983 % o cache: the pixel cache.
2985 % o nexus_info: the cache nexus to return the colormap indexes.
2988 MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2989 NexusInfo *nexus_info)
2994 assert(cache != (Cache) NULL);
2995 cache_info=(CacheInfo *) cache;
2996 assert(cache_info->signature == MagickSignature);
2997 if (cache_info->storage_class == UndefinedClass)
2998 return((IndexPacket *) NULL);
2999 return(nexus_info->indexes);
3003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007 % G e t V i r t u a l I n d e x Q u e u e %
3011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3013 % GetVirtualIndexQueue() returns the virtual black channel or the
3014 % colormap indexes associated with the last call to QueueAuthenticPixels() or
3015 % GetVirtualPixels(). NULL is returned if the black channel or colormap
3016 % indexes are not available.
3018 % The format of the GetVirtualIndexQueue() method is:
3020 % const IndexPacket *GetVirtualIndexQueue(const Image *image)
3022 % A description of each parameter follows:
3024 % o image: the image.
3027 MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3033 id = GetOpenMPThreadId();
3035 assert(image != (const Image *) NULL);
3036 assert(image->signature == MagickSignature);
3037 assert(image->cache != (Cache) NULL);
3038 cache_info=(CacheInfo *) image->cache;
3039 assert(cache_info->signature == MagickSignature);
3040 if (cache_info->methods.get_virtual_indexes_from_handler !=
3041 (GetVirtualIndexesFromHandler) NULL)
3042 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3043 assert(id < (int) cache_info->number_threads);
3044 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
3048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3052 + 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 %
3056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3058 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3059 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3060 % is returned if the pixels are transferred, otherwise a NULL is returned.
3062 % The format of the GetVirtualPixelsFromNexus() method is:
3064 % PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3065 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3066 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3067 % ExceptionInfo *exception)
3069 % A description of each parameter follows:
3071 % o image: the image.
3073 % o virtual_pixel_method: the virtual pixel method.
3075 % o x,y,columns,rows: These values define the perimeter of a region of
3078 % o nexus_info: the cache nexus to acquire.
3080 % o exception: return any errors or warnings in this structure.
3087 0, 48, 12, 60, 3, 51, 15, 63,
3088 32, 16, 44, 28, 35, 19, 47, 31,
3089 8, 56, 4, 52, 11, 59, 7, 55,
3090 40, 24, 36, 20, 43, 27, 39, 23,
3091 2, 50, 14, 62, 1, 49, 13, 61,
3092 34, 18, 46, 30, 33, 17, 45, 29,
3093 10, 58, 6, 54, 9, 57, 5, 53,
3094 42, 26, 38, 22, 41, 25, 37, 21
3097 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3102 index=x+DitherMatrix[x & 0x07]-32L;
3105 if (index >= (ssize_t) columns)
3106 return((ssize_t) columns-1L);
3110 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3115 index=y+DitherMatrix[y & 0x07]-32L;
3118 if (index >= (ssize_t) rows)
3119 return((ssize_t) rows-1L);
3123 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3127 if (x >= (ssize_t) columns)
3128 return((ssize_t) (columns-1));
3132 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3136 if (y >= (ssize_t) rows)
3137 return((ssize_t) (rows-1));
3141 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3143 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3146 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3148 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3152 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3153 returns not only the quotient (tile the offset falls in) but also the positive
3154 remainer within that tile such that 0 <= remainder < extent. This method is
3155 essentially a ldiv() using a floored modulo division rather than the normal
3156 default truncated modulo division.
3158 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3159 const size_t extent)
3164 modulo.quotient=offset/(ssize_t) extent;
3167 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3171 MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3172 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3173 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3174 ExceptionInfo *exception)
3199 register const IndexPacket
3200 *restrict virtual_indexes;
3202 register const PixelPacket
3205 register IndexPacket
3208 register PixelPacket
3218 assert(image != (const Image *) NULL);
3219 assert(image->signature == MagickSignature);
3220 assert(image->cache != (Cache) NULL);
3221 cache_info=(CacheInfo *) image->cache;
3222 assert(cache_info->signature == MagickSignature);
3223 if (cache_info->type == UndefinedCache)
3224 return((const PixelPacket *) NULL);
3227 region.width=columns;
3229 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3230 if (pixels == (PixelPacket *) NULL)
3231 return((const PixelPacket *) NULL);
3232 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3233 nexus_info->region.x;
3234 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3235 nexus_info->region.width-1L;
3236 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3237 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3238 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3239 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3245 Pixel request is inside cache extents.
3247 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3249 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3250 if (status == MagickFalse)
3251 return((const PixelPacket *) NULL);
3252 if ((cache_info->storage_class == PseudoClass) ||
3253 (cache_info->colorspace == CMYKColorspace))
3255 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3256 if (status == MagickFalse)
3257 return((const PixelPacket *) NULL);
3262 Pixel request is outside cache extents.
3265 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3266 virtual_nexus=AcquirePixelCacheNexus(1);
3267 if (virtual_nexus == (NexusInfo **) NULL)
3269 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3270 "UnableToGetCacheNexus","`%s'",image->filename);
3271 return((const PixelPacket *) NULL);
3273 switch (virtual_pixel_method)
3275 case BlackVirtualPixelMethod:
3277 SetRedPixelComponent(&virtual_pixel,0);
3278 SetGreenPixelComponent(&virtual_pixel,0);
3279 SetBluePixelComponent(&virtual_pixel,0);
3280 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3283 case GrayVirtualPixelMethod:
3285 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3286 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3287 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3288 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3291 case TransparentVirtualPixelMethod:
3293 SetRedPixelComponent(&virtual_pixel,0);
3294 SetGreenPixelComponent(&virtual_pixel,0);
3295 SetBluePixelComponent(&virtual_pixel,0);
3296 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
3299 case MaskVirtualPixelMethod:
3300 case WhiteVirtualPixelMethod:
3302 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3303 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3304 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3305 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3310 virtual_pixel=image->background_color;
3315 for (v=0; v < (ssize_t) rows; v++)
3317 for (u=0; u < (ssize_t) columns; u+=length)
3319 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3320 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3321 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3329 Transfer a single pixel.
3331 length=(MagickSizeType) 1;
3332 switch (virtual_pixel_method)
3334 case BackgroundVirtualPixelMethod:
3335 case ConstantVirtualPixelMethod:
3336 case BlackVirtualPixelMethod:
3337 case GrayVirtualPixelMethod:
3338 case TransparentVirtualPixelMethod:
3339 case MaskVirtualPixelMethod:
3340 case WhiteVirtualPixelMethod:
3343 virtual_indexes=(&virtual_index);
3346 case EdgeVirtualPixelMethod:
3349 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3350 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3351 1UL,1UL,*virtual_nexus,exception);
3352 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3356 case RandomVirtualPixelMethod:
3358 if (cache_info->random_info == (RandomInfo *) NULL)
3359 cache_info->random_info=AcquireRandomInfo();
3360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3361 RandomX(cache_info->random_info,cache_info->columns),
3362 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3363 *virtual_nexus,exception);
3364 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3368 case DitherVirtualPixelMethod:
3370 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3371 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3372 1UL,1UL,*virtual_nexus,exception);
3373 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3377 case TileVirtualPixelMethod:
3379 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3380 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3381 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3382 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3384 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3388 case MirrorVirtualPixelMethod:
3390 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3391 if ((x_modulo.quotient & 0x01) == 1L)
3392 x_modulo.remainder=(ssize_t) cache_info->columns-
3393 x_modulo.remainder-1L;
3394 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3395 if ((y_modulo.quotient & 0x01) == 1L)
3396 y_modulo.remainder=(ssize_t) cache_info->rows-
3397 y_modulo.remainder-1L;
3398 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3399 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3401 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3405 case CheckerTileVirtualPixelMethod:
3407 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3408 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3409 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3412 virtual_indexes=(&virtual_index);
3415 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3416 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3418 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3422 case HorizontalTileVirtualPixelMethod:
3424 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3427 virtual_indexes=(&virtual_index);
3430 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3431 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3433 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3435 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3439 case VerticalTileVirtualPixelMethod:
3441 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3444 virtual_indexes=(&virtual_index);
3447 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3448 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3449 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3450 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3452 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3456 case HorizontalTileEdgeVirtualPixelMethod:
3458 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3459 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3460 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3461 *virtual_nexus,exception);
3462 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3466 case VerticalTileEdgeVirtualPixelMethod:
3468 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3469 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3470 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3471 *virtual_nexus,exception);
3472 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3477 if (p == (const PixelPacket *) NULL)
3480 if ((indexes != (IndexPacket *) NULL) &&
3481 (virtual_indexes != (const IndexPacket *) NULL))
3482 *indexes++=(*virtual_indexes);
3486 Transfer a run of pixels.
3488 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3489 (size_t) length,1UL,*virtual_nexus,exception);
3490 if (p == (const PixelPacket *) NULL)
3492 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
3493 (void) memcpy(q,p,(size_t) length*sizeof(*p));
3495 if ((indexes != (IndexPacket *) NULL) &&
3496 (virtual_indexes != (const IndexPacket *) NULL))
3498 (void) memcpy(indexes,virtual_indexes,(size_t) length*
3499 sizeof(*virtual_indexes));
3504 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513 + G e t V i r t u a l P i x e l C a c h e %
3517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3519 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3520 % cache as defined by the geometry parameters. A pointer to the pixels
3521 % is returned if the pixels are transferred, otherwise a NULL is returned.
3523 % The format of the GetVirtualPixelCache() method is:
3525 % const PixelPacket *GetVirtualPixelCache(const Image *image,
3526 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3527 % const ssize_t y,const size_t columns,const size_t rows,
3528 % ExceptionInfo *exception)
3530 % A description of each parameter follows:
3532 % o image: the image.
3534 % o virtual_pixel_method: the virtual pixel method.
3536 % o x,y,columns,rows: These values define the perimeter of a region of
3539 % o exception: return any errors or warnings in this structure.
3542 static const PixelPacket *GetVirtualPixelCache(const Image *image,
3543 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3544 const size_t columns,const size_t rows,ExceptionInfo *exception)
3550 id = GetOpenMPThreadId();
3552 assert(image != (const Image *) NULL);
3553 assert(image->signature == MagickSignature);
3554 assert(image->cache != (Cache) NULL);
3555 cache_info=(CacheInfo *) image->cache;
3556 assert(cache_info->signature == MagickSignature);
3557 assert(id < (int) cache_info->number_threads);
3558 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3559 cache_info->nexus_info[id],exception));
3563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3567 % G e t V i r t u a l P i x e l Q u e u e %
3571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3573 % GetVirtualPixelQueue() returns the virtual pixels associated with the
3574 % last call to QueueAuthenticPixels() or GetVirtualPixels().
3576 % The format of the GetVirtualPixelQueue() method is:
3578 % const PixelPacket *GetVirtualPixelQueue(const Image image)
3580 % A description of each parameter follows:
3582 % o image: the image.
3585 MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3591 id = GetOpenMPThreadId();
3593 assert(image != (const Image *) NULL);
3594 assert(image->signature == MagickSignature);
3595 assert(image->cache != (Cache) NULL);
3596 cache_info=(CacheInfo *) image->cache;
3597 assert(cache_info->signature == MagickSignature);
3598 if (cache_info->methods.get_virtual_pixels_handler !=
3599 (GetVirtualPixelsHandler) NULL)
3600 return(cache_info->methods.get_virtual_pixels_handler(image));
3601 assert(id < (int) cache_info->number_threads);
3602 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610 % G e t V i r t u a l P i x e l s %
3614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3616 % GetVirtualPixels() returns an immutable pixel region. If the
3617 % region is successfully accessed, a pointer to it is returned, otherwise
3618 % NULL is returned. The returned pointer may point to a temporary working
3619 % copy of the pixels or it may point to the original pixels in memory.
3620 % Performance is maximized if the selected region is part of one row, or one
3621 % or more full rows, since there is opportunity to access the pixels in-place
3622 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3623 % returned pointer must *never* be deallocated by the user.
3625 % Pixels accessed via the returned pointer represent a simple array of type
3626 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3627 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3628 % the black color component or to obtain the colormap indexes (of type
3629 % IndexPacket) corresponding to the region.
3631 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3633 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3634 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3635 % GetCacheViewAuthenticPixels() instead.
3637 % The format of the GetVirtualPixels() method is:
3639 % const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3640 % const ssize_t y,const size_t columns,const size_t rows,
3641 % ExceptionInfo *exception)
3643 % A description of each parameter follows:
3645 % o image: the image.
3647 % o x,y,columns,rows: These values define the perimeter of a region of
3650 % o exception: return any errors or warnings in this structure.
3653 MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3654 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3655 ExceptionInfo *exception)
3661 id = GetOpenMPThreadId();
3663 assert(image != (const Image *) NULL);
3664 assert(image->signature == MagickSignature);
3665 assert(image->cache != (Cache) NULL);
3666 cache_info=(CacheInfo *) image->cache;
3667 assert(cache_info->signature == MagickSignature);
3668 if (cache_info->methods.get_virtual_pixel_handler !=
3669 (GetVirtualPixelHandler) NULL)
3670 return(cache_info->methods.get_virtual_pixel_handler(image,
3671 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3672 assert(id < (int) cache_info->number_threads);
3673 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3674 columns,rows,cache_info->nexus_info[id],exception));
3678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3682 + 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 %
3686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3688 % GetVirtualPixelsCache() returns the pixels associated with the last call
3689 % to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3691 % The format of the GetVirtualPixelsCache() method is:
3693 % PixelPacket *GetVirtualPixelsCache(const Image *image)
3695 % A description of each parameter follows:
3697 % o image: the image.
3700 static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3706 id = GetOpenMPThreadId();
3708 assert(image != (const Image *) NULL);
3709 assert(image->signature == MagickSignature);
3710 assert(image->cache != (Cache) NULL);
3711 cache_info=(CacheInfo *) image->cache;
3712 assert(cache_info->signature == MagickSignature);
3713 assert(id < (int) cache_info->number_threads);
3714 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3722 + G e t V i r t u a l P i x e l s N e x u s %
3726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3728 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3731 % The format of the GetVirtualPixelsNexus() method is:
3733 % const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3734 % NexusInfo *nexus_info)
3736 % A description of each parameter follows:
3738 % o cache: the pixel cache.
3740 % o nexus_info: the cache nexus to return the colormap pixels.
3743 MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3744 NexusInfo *nexus_info)
3749 assert(cache != (Cache) NULL);
3750 cache_info=(CacheInfo *) cache;
3751 assert(cache_info->signature == MagickSignature);
3752 if (cache_info->storage_class == UndefinedClass)
3753 return((PixelPacket *) NULL);
3754 return((const PixelPacket *) nexus_info->pixels);
3758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3762 + M a s k P i x e l C a c h e N e x u s %
3766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3768 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3769 % The method returns MagickTrue if the pixel region is masked, otherwise
3772 % The format of the MaskPixelCacheNexus() method is:
3774 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3775 % NexusInfo *nexus_info,ExceptionInfo *exception)
3777 % A description of each parameter follows:
3779 % o image: the image.
3781 % o nexus_info: the cache nexus to clip.
3783 % o exception: return any errors or warnings in this structure.
3787 static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3788 const MagickRealType alpha,const MagickPixelPacket *q,
3789 const MagickRealType beta,MagickPixelPacket *composite)
3794 if (alpha == TransparentOpacity)
3799 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3800 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3801 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3802 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3803 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3804 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3805 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3808 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3809 ExceptionInfo *exception)
3825 register const PixelPacket
3828 register IndexPacket
3829 *restrict nexus_indexes,
3832 register PixelPacket
3842 if (image->debug != MagickFalse)
3843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3844 if (image->mask == (Image *) NULL)
3845 return(MagickFalse);
3846 cache_info=(CacheInfo *) image->cache;
3847 if (cache_info == (Cache) NULL)
3848 return(MagickFalse);
3849 image_nexus=AcquirePixelCacheNexus(1);
3850 clip_nexus=AcquirePixelCacheNexus(1);
3851 if ((image_nexus == (NexusInfo **) NULL) ||
3852 (clip_nexus == (NexusInfo **) NULL))
3853 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3854 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3855 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3856 image_nexus[0],exception);
3857 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3858 q=nexus_info->pixels;
3859 nexus_indexes=nexus_info->indexes;
3860 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3861 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3862 nexus_info->region.height,clip_nexus[0],&image->exception);
3863 GetMagickPixelPacket(image,&alpha);
3864 GetMagickPixelPacket(image,&beta);
3865 number_pixels=(MagickSizeType) nexus_info->region.width*
3866 nexus_info->region.height;
3867 for (i=0; i < (ssize_t) number_pixels; i++)
3869 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3871 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3872 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3873 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3874 &alpha,alpha.opacity,&beta);
3875 q->red=ClampToQuantum(beta.red);
3876 q->green=ClampToQuantum(beta.green);
3877 q->blue=ClampToQuantum(beta.blue);
3878 q->opacity=ClampToQuantum(beta.opacity);
3879 if (cache_info->active_index_channel != MagickFalse)
3880 nexus_indexes[i]=indexes[i];
3885 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3886 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3887 if (i < (ssize_t) number_pixels)
3888 return(MagickFalse);
3893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3897 + O p e n P i x e l C a c h e %
3901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3903 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3904 % dimensions, allocating space for the image pixels and optionally the
3905 % colormap indexes, and memory mapping the cache if it is disk based. The
3906 % cache nexus array is initialized as well.
3908 % The format of the OpenPixelCache() method is:
3910 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3911 % ExceptionInfo *exception)
3913 % A description of each parameter follows:
3915 % o image: the image.
3917 % o mode: ReadMode, WriteMode, or IOMode.
3919 % o exception: return any errors or warnings in this structure.
3923 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3925 cache_info->mapped=MagickFalse;
3926 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3927 cache_info->length);
3928 if (cache_info->pixels == (PixelPacket *) NULL)
3930 cache_info->mapped=MagickTrue;
3931 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3932 cache_info->length);
3936 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3946 cache_info=(CacheInfo *) image->cache;
3947 if (image->debug != MagickFalse)
3950 format[MaxTextExtent],
3951 message[MaxTextExtent];
3953 (void) FormatMagickSize(length,MagickFalse,format);
3954 (void) FormatMagickString(message,MaxTextExtent,
3955 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
3956 cache_info->cache_filename,cache_info->file,format);
3957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3959 if (length != (MagickSizeType) ((MagickOffsetType) length))
3960 return(MagickFalse);
3961 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3963 return(MagickFalse);
3964 if ((MagickSizeType) extent >= length)
3966 offset=(MagickOffsetType) length-1;
3967 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3968 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3971 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3972 ExceptionInfo *exception)
3979 format[MaxTextExtent],
3980 message[MaxTextExtent];
3993 assert(image != (const Image *) NULL);
3994 assert(image->signature == MagickSignature);
3995 assert(image->cache != (Cache) NULL);
3996 if (image->debug != MagickFalse)
3997 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3998 if ((image->columns == 0) || (image->rows == 0))
3999 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4000 cache_info=(CacheInfo *) image->cache;
4001 assert(cache_info->signature == MagickSignature);
4002 source_info=(*cache_info);
4003 source_info.file=(-1);
4004 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4005 image->filename,(double) GetImageIndexInList(image));
4006 cache_info->mode=mode;
4007 cache_info->rows=image->rows;
4008 cache_info->columns=image->columns;
4009 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4010 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4011 if (image->ping != MagickFalse)
4013 cache_info->storage_class=image->storage_class;
4014 cache_info->colorspace=image->colorspace;
4015 cache_info->type=PingCache;
4016 cache_info->pixels=(PixelPacket *) NULL;
4017 cache_info->indexes=(IndexPacket *) NULL;
4018 cache_info->length=0;
4021 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4022 packet_size=sizeof(PixelPacket);
4023 if (cache_info->active_index_channel != MagickFalse)
4024 packet_size+=sizeof(IndexPacket);
4025 length=number_pixels*packet_size;
4026 columns=(size_t) (length/cache_info->rows/packet_size);
4027 if (cache_info->columns != columns)
4028 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4030 cache_info->length=length;
4031 status=AcquireMagickResource(AreaResource,cache_info->length);
4032 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4033 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4035 status=AcquireMagickResource(MemoryResource,cache_info->length);
4036 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4037 (cache_info->type == MemoryCache))
4039 AllocatePixelCachePixels(cache_info);
4040 if (cache_info->pixels == (PixelPacket *) NULL)
4041 cache_info->pixels=source_info.pixels;
4045 Create memory pixel cache.
4047 if (image->debug != MagickFalse)
4049 (void) FormatMagickSize(cache_info->length,MagickTrue,
4051 (void) FormatMagickString(message,MaxTextExtent,
4052 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
4053 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4054 (double) cache_info->columns,(double) cache_info->rows,
4056 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4059 cache_info->storage_class=image->storage_class;
4060 cache_info->colorspace=image->colorspace;
4061 cache_info->type=MemoryCache;
4062 cache_info->indexes=(IndexPacket *) NULL;
4063 if (cache_info->active_index_channel != MagickFalse)
4064 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4066 if (source_info.storage_class != UndefinedClass)
4068 status|=ClonePixelCachePixels(cache_info,&source_info,
4070 RelinquishPixelCachePixels(&source_info);
4075 RelinquishMagickResource(MemoryResource,cache_info->length);
4078 Create pixel cache on disk.
4080 status=AcquireMagickResource(DiskResource,cache_info->length);
4081 if (status == MagickFalse)
4083 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4084 "CacheResourcesExhausted","`%s'",image->filename);
4085 return(MagickFalse);
4087 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4089 RelinquishMagickResource(DiskResource,cache_info->length);
4090 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4092 return(MagickFalse);
4094 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4095 cache_info->length);
4096 if (status == MagickFalse)
4098 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4100 return(MagickFalse);
4102 cache_info->storage_class=image->storage_class;
4103 cache_info->colorspace=image->colorspace;
4104 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4105 status=AcquireMagickResource(AreaResource,cache_info->length);
4106 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4107 cache_info->type=DiskCache;
4110 status=AcquireMagickResource(MapResource,cache_info->length);
4111 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4112 (cache_info->type != MemoryCache))
4113 cache_info->type=DiskCache;
4116 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4117 cache_info->offset,(size_t) cache_info->length);
4118 if (cache_info->pixels == (PixelPacket *) NULL)
4120 cache_info->pixels=source_info.pixels;
4121 cache_info->type=DiskCache;
4126 Create file-backed memory-mapped pixel cache.
4128 (void) ClosePixelCacheOnDisk(cache_info);
4129 cache_info->type=MapCache;
4130 cache_info->mapped=MagickTrue;
4131 cache_info->indexes=(IndexPacket *) NULL;
4132 if (cache_info->active_index_channel != MagickFalse)
4133 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4135 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4137 status=ClonePixelCachePixels(cache_info,&source_info,
4139 RelinquishPixelCachePixels(&source_info);
4141 if (image->debug != MagickFalse)
4143 (void) FormatMagickSize(cache_info->length,MagickTrue,
4145 (void) FormatMagickString(message,MaxTextExtent,
4146 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
4147 cache_info->filename,cache_info->cache_filename,
4148 cache_info->file,(double) cache_info->columns,(double)
4149 cache_info->rows,format);
4150 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4156 RelinquishMagickResource(MapResource,cache_info->length);
4158 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4160 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4161 RelinquishPixelCachePixels(&source_info);
4163 if (image->debug != MagickFalse)
4165 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4166 (void) FormatMagickString(message,MaxTextExtent,
4167 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4168 cache_info->cache_filename,cache_info->file,(double)
4169 cache_info->columns,(double) cache_info->rows,format);
4170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4180 + P e r s i s t P i x e l C a c h e %
4184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4186 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4187 % persistent pixel cache is one that resides on disk and is not destroyed
4188 % when the program exits.
4190 % The format of the PersistPixelCache() method is:
4192 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4193 % const MagickBooleanType attach,MagickOffsetType *offset,
4194 % ExceptionInfo *exception)
4196 % A description of each parameter follows:
4198 % o image: the image.
4200 % o filename: the persistent pixel cache filename.
4202 % o attach: A value other than zero initializes the persistent pixel cache.
4204 % o initialize: A value other than zero initializes the persistent pixel
4207 % o offset: the offset in the persistent cache to store pixels.
4209 % o exception: return any errors or warnings in this structure.
4212 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4213 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4214 ExceptionInfo *exception)
4229 assert(image != (Image *) NULL);
4230 assert(image->signature == MagickSignature);
4231 if (image->debug != MagickFalse)
4232 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4233 assert(image->cache != (void *) NULL);
4234 assert(filename != (const char *) NULL);
4235 assert(offset != (MagickOffsetType *) NULL);
4236 page_size=GetMagickPageSize();
4237 cache_info=(CacheInfo *) image->cache;
4238 assert(cache_info->signature == MagickSignature);
4239 if (attach != MagickFalse)
4242 Attach existing persistent pixel cache.
4244 if (image->debug != MagickFalse)
4245 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4246 "attach persistent cache");
4247 (void) CopyMagickString(cache_info->cache_filename,filename,
4249 cache_info->type=DiskCache;
4250 cache_info->offset=(*offset);
4251 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4252 return(MagickFalse);
4253 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4256 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4257 (cache_info->reference_count == 1))
4259 LockSemaphoreInfo(cache_info->semaphore);
4260 if ((cache_info->mode != ReadMode) &&
4261 (cache_info->type != MemoryCache) &&
4262 (cache_info->reference_count == 1))
4268 Usurp existing persistent pixel cache.
4270 status=rename(cache_info->cache_filename,filename);
4273 (void) CopyMagickString(cache_info->cache_filename,filename,
4275 *offset+=cache_info->length+page_size-(cache_info->length %
4277 UnlockSemaphoreInfo(cache_info->semaphore);
4278 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4279 if (image->debug != MagickFalse)
4280 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4281 "Usurp resident persistent cache");
4285 UnlockSemaphoreInfo(cache_info->semaphore);
4288 Clone persistent pixel cache.
4290 clone_image=(*image);
4291 clone_info=(CacheInfo *) clone_image.cache;
4292 image->cache=ClonePixelCache(cache_info);
4293 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4294 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4295 cache_info->type=DiskCache;
4296 cache_info->offset=(*offset);
4297 cache_info=(CacheInfo *) image->cache;
4298 status=OpenPixelCache(image,IOMode,exception);
4299 if (status != MagickFalse)
4300 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4301 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4302 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4311 + Q u e u e A u t h e n t i c N e x u s %
4315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4317 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4318 % by the region rectangle and returns a pointer to the region. This region is
4319 % subsequently transferred from the pixel cache with
4320 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4321 % pixels are transferred, otherwise a NULL is returned.
4323 % The format of the QueueAuthenticNexus() method is:
4325 % PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4326 % const ssize_t y,const size_t columns,const size_t rows,
4327 % NexusInfo *nexus_info,ExceptionInfo *exception)
4329 % A description of each parameter follows:
4331 % o image: the image.
4333 % o x,y,columns,rows: These values define the perimeter of a region of
4336 % o nexus_info: the cache nexus to set.
4338 % o exception: return any errors or warnings in this structure.
4341 MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4342 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4343 ExceptionInfo *exception)
4358 Validate pixel cache geometry.
4360 assert(image != (const Image *) NULL);
4361 assert(image->signature == MagickSignature);
4362 assert(image->cache != (Cache) NULL);
4363 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4364 assert(cache_info->signature == MagickSignature);
4365 if (cache_info == (Cache) NULL)
4366 return((PixelPacket *) NULL);
4367 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4369 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4370 "NoPixelsDefinedInCache","`%s'",image->filename);
4371 return((PixelPacket *) NULL);
4373 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4374 (y >= (ssize_t) cache_info->rows))
4376 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4377 "PixelsAreNotAuthentic","`%s'",image->filename);
4378 return((PixelPacket *) NULL);
4380 offset=(MagickOffsetType) y*cache_info->columns+x;
4382 return((PixelPacket *) NULL);
4383 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4384 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4385 if ((MagickSizeType) offset >= number_pixels)
4386 return((PixelPacket *) NULL);
4392 region.width=columns;
4394 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4402 + 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 %
4406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4408 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4409 % defined by the region rectangle and returns a pointer to the region. This
4410 % region is subsequently transferred from the pixel cache with
4411 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4412 % pixels are transferred, otherwise a NULL is returned.
4414 % The format of the QueueAuthenticPixelsCache() method is:
4416 % PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4417 % const ssize_t y,const size_t columns,const size_t rows,
4418 % ExceptionInfo *exception)
4420 % A description of each parameter follows:
4422 % o image: the image.
4424 % o x,y,columns,rows: These values define the perimeter of a region of
4427 % o exception: return any errors or warnings in this structure.
4430 static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4431 const ssize_t y,const size_t columns,const size_t rows,
4432 ExceptionInfo *exception)
4438 id = GetOpenMPThreadId();
4440 assert(image != (const Image *) NULL);
4441 assert(image->signature == MagickSignature);
4442 assert(image->cache != (Cache) NULL);
4443 cache_info=(CacheInfo *) image->cache;
4444 assert(cache_info->signature == MagickSignature);
4445 assert(id < (int) cache_info->number_threads);
4446 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4455 % Q u e u e A u t h e n t i c P i x e l s %
4459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4461 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4462 % successfully intialized a pointer to a PixelPacket array representing the
4463 % region is returned, otherwise NULL is returned. The returned pointer may
4464 % point to a temporary working buffer for the pixels or it may point to the
4465 % final location of the pixels in memory.
4467 % Write-only access means that any existing pixel values corresponding to
4468 % the region are ignored. This is useful if the initial image is being
4469 % created from scratch, or if the existing pixel values are to be
4470 % completely replaced without need to refer to their pre-existing values.
4471 % The application is free to read and write the pixel buffer returned by
4472 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4473 % initialize the pixel array values. Initializing pixel array values is the
4474 % application's responsibility.
4476 % Performance is maximized if the selected region is part of one row, or
4477 % one or more full rows, since then there is opportunity to access the
4478 % pixels in-place (without a copy) if the image is in memory, or in a
4479 % memory-mapped file. The returned pointer must *never* be deallocated
4482 % Pixels accessed via the returned pointer represent a simple array of type
4483 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4484 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4485 % the black color component or the colormap indexes (of type IndexPacket)
4486 % corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4487 % array has been updated, the changes must be saved back to the underlying
4488 % image using SyncAuthenticPixels() or they may be lost.
4490 % The format of the QueueAuthenticPixels() method is:
4492 % PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4493 % const ssize_t y,const size_t columns,const size_t rows,
4494 % ExceptionInfo *exception)
4496 % A description of each parameter follows:
4498 % o image: the image.
4500 % o x,y,columns,rows: These values define the perimeter of a region of
4503 % o exception: return any errors or warnings in this structure.
4506 MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4507 const ssize_t y,const size_t columns,const size_t rows,
4508 ExceptionInfo *exception)
4514 id = GetOpenMPThreadId();
4516 assert(image != (Image *) NULL);
4517 assert(image->signature == MagickSignature);
4518 assert(image->cache != (Cache) NULL);
4519 cache_info=(CacheInfo *) image->cache;
4520 assert(cache_info->signature == MagickSignature);
4521 if (cache_info->methods.queue_authentic_pixels_handler !=
4522 (QueueAuthenticPixelsHandler) NULL)
4523 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4525 assert(id < (int) cache_info->number_threads);
4526 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4535 + R e a d P i x e l C a c h e I n d e x e s %
4539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4541 % ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4544 % The format of the ReadPixelCacheIndexes() method is:
4546 % MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4547 % NexusInfo *nexus_info,ExceptionInfo *exception)
4549 % A description of each parameter follows:
4551 % o cache_info: the pixel cache.
4553 % o nexus_info: the cache nexus to read the colormap indexes.
4555 % o exception: return any errors or warnings in this structure.
4558 static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4559 NexusInfo *nexus_info,ExceptionInfo *exception)
4569 register IndexPacket
4578 if (cache_info->active_index_channel == MagickFalse)
4579 return(MagickFalse);
4580 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4582 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4583 nexus_info->region.x;
4584 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4585 rows=nexus_info->region.height;
4587 q=nexus_info->indexes;
4588 switch (cache_info->type)
4593 register IndexPacket
4597 Read indexes from memory.
4599 if ((cache_info->columns == nexus_info->region.width) &&
4600 (extent == (MagickSizeType) ((size_t) extent)))
4605 p=cache_info->indexes+offset;
4606 for (y=0; y < (ssize_t) rows; y++)
4608 (void) memcpy(q,p,(size_t) length);
4609 p+=cache_info->columns;
4610 q+=nexus_info->region.width;
4617 Read indexes from disk.
4619 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4621 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4622 cache_info->cache_filename);
4623 return(MagickFalse);
4625 if ((cache_info->columns == nexus_info->region.width) &&
4626 (extent <= MagickMaxBufferExtent))
4631 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4632 for (y=0; y < (ssize_t) rows; y++)
4634 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4635 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4636 if ((MagickSizeType) count < length)
4638 offset+=cache_info->columns;
4639 q+=nexus_info->region.width;
4641 if (y < (ssize_t) rows)
4643 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4644 cache_info->cache_filename);
4645 return(MagickFalse);
4652 if ((cache_info->debug != MagickFalse) &&
4653 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4654 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4655 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4656 nexus_info->region.width,(double) nexus_info->region.height,(double)
4657 nexus_info->region.x,(double) nexus_info->region.y);
4662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4666 + R e a d P i x e l C a c h e P i x e l s %
4670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4672 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4675 % The format of the ReadPixelCachePixels() method is:
4677 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4678 % NexusInfo *nexus_info,ExceptionInfo *exception)
4680 % A description of each parameter follows:
4682 % o cache_info: the pixel cache.
4684 % o nexus_info: the cache nexus to read the pixels.
4686 % o exception: return any errors or warnings in this structure.
4689 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4690 NexusInfo *nexus_info,ExceptionInfo *exception)
4700 register PixelPacket
4709 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4711 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4712 nexus_info->region.x;
4713 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4714 rows=nexus_info->region.height;
4716 q=nexus_info->pixels;
4717 switch (cache_info->type)
4722 register PixelPacket
4726 Read pixels from memory.
4728 if ((cache_info->columns == nexus_info->region.width) &&
4729 (extent == (MagickSizeType) ((size_t) extent)))
4734 p=cache_info->pixels+offset;
4735 for (y=0; y < (ssize_t) rows; y++)
4737 (void) memcpy(q,p,(size_t) length);
4738 p+=cache_info->columns;
4739 q+=nexus_info->region.width;
4746 Read pixels from disk.
4748 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4750 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4751 cache_info->cache_filename);
4752 return(MagickFalse);
4754 if ((cache_info->columns == nexus_info->region.width) &&
4755 (extent <= MagickMaxBufferExtent))
4760 for (y=0; y < (ssize_t) rows; y++)
4762 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4763 sizeof(*q),length,(unsigned char *) q);
4764 if ((MagickSizeType) count < length)
4766 offset+=cache_info->columns;
4767 q+=nexus_info->region.width;
4769 if (y < (ssize_t) rows)
4771 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4772 cache_info->cache_filename);
4773 return(MagickFalse);
4780 if ((cache_info->debug != MagickFalse) &&
4781 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4782 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4783 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4784 nexus_info->region.width,(double) nexus_info->region.height,(double)
4785 nexus_info->region.x,(double) nexus_info->region.y);
4790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4794 + R e f e r e n c e P i x e l C a c h e %
4798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4800 % ReferencePixelCache() increments the reference count associated with the
4801 % pixel cache returning a pointer to the cache.
4803 % The format of the ReferencePixelCache method is:
4805 % Cache ReferencePixelCache(Cache cache_info)
4807 % A description of each parameter follows:
4809 % o cache_info: the pixel cache.
4812 MagickExport Cache ReferencePixelCache(Cache cache)
4817 assert(cache != (Cache *) NULL);
4818 cache_info=(CacheInfo *) cache;
4819 assert(cache_info->signature == MagickSignature);
4820 LockSemaphoreInfo(cache_info->semaphore);
4821 cache_info->reference_count++;
4822 UnlockSemaphoreInfo(cache_info->semaphore);
4827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4831 + S e t P i x e l C a c h e M e t h o d s %
4835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4837 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4839 % The format of the SetPixelCacheMethods() method is:
4841 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4843 % A description of each parameter follows:
4845 % o cache: the pixel cache.
4847 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4850 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4855 GetOneAuthenticPixelFromHandler
4856 get_one_authentic_pixel_from_handler;
4858 GetOneVirtualPixelFromHandler
4859 get_one_virtual_pixel_from_handler;
4862 Set cache pixel methods.
4864 assert(cache != (Cache) NULL);
4865 assert(cache_methods != (CacheMethods *) NULL);
4866 cache_info=(CacheInfo *) cache;
4867 assert(cache_info->signature == MagickSignature);
4868 if (cache_info->debug != MagickFalse)
4869 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4870 cache_info->filename);
4871 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4872 cache_info->methods.get_virtual_pixel_handler=
4873 cache_methods->get_virtual_pixel_handler;
4874 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4875 cache_info->methods.destroy_pixel_handler=
4876 cache_methods->destroy_pixel_handler;
4877 if (cache_methods->get_virtual_indexes_from_handler !=
4878 (GetVirtualIndexesFromHandler) NULL)
4879 cache_info->methods.get_virtual_indexes_from_handler=
4880 cache_methods->get_virtual_indexes_from_handler;
4881 if (cache_methods->get_authentic_pixels_handler !=
4882 (GetAuthenticPixelsHandler) NULL)
4883 cache_info->methods.get_authentic_pixels_handler=
4884 cache_methods->get_authentic_pixels_handler;
4885 if (cache_methods->queue_authentic_pixels_handler !=
4886 (QueueAuthenticPixelsHandler) NULL)
4887 cache_info->methods.queue_authentic_pixels_handler=
4888 cache_methods->queue_authentic_pixels_handler;
4889 if (cache_methods->sync_authentic_pixels_handler !=
4890 (SyncAuthenticPixelsHandler) NULL)
4891 cache_info->methods.sync_authentic_pixels_handler=
4892 cache_methods->sync_authentic_pixels_handler;
4893 if (cache_methods->get_authentic_pixels_from_handler !=
4894 (GetAuthenticPixelsFromHandler) NULL)
4895 cache_info->methods.get_authentic_pixels_from_handler=
4896 cache_methods->get_authentic_pixels_from_handler;
4897 if (cache_methods->get_authentic_indexes_from_handler !=
4898 (GetAuthenticIndexesFromHandler) NULL)
4899 cache_info->methods.get_authentic_indexes_from_handler=
4900 cache_methods->get_authentic_indexes_from_handler;
4901 get_one_virtual_pixel_from_handler=
4902 cache_info->methods.get_one_virtual_pixel_from_handler;
4903 if (get_one_virtual_pixel_from_handler !=
4904 (GetOneVirtualPixelFromHandler) NULL)
4905 cache_info->methods.get_one_virtual_pixel_from_handler=
4906 cache_methods->get_one_virtual_pixel_from_handler;
4907 get_one_authentic_pixel_from_handler=
4908 cache_methods->get_one_authentic_pixel_from_handler;
4909 if (get_one_authentic_pixel_from_handler !=
4910 (GetOneAuthenticPixelFromHandler) NULL)
4911 cache_info->methods.get_one_authentic_pixel_from_handler=
4912 cache_methods->get_one_authentic_pixel_from_handler;
4916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4920 + S e t P i x e l C a c h e N e x u s P i x e l s %
4924 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4926 % SetPixelCacheNexusPixels() defines the region of the cache for the
4927 % specified cache nexus.
4929 % The format of the SetPixelCacheNexusPixels() method is:
4931 % PixelPacket SetPixelCacheNexusPixels(const Image *image,
4932 % const RectangleInfo *region,NexusInfo *nexus_info,
4933 % ExceptionInfo *exception)
4935 % A description of each parameter follows:
4937 % o image: the image.
4939 % o region: A pointer to the RectangleInfo structure that defines the
4940 % region of this particular cache nexus.
4942 % o nexus_info: the cache nexus to set.
4944 % o exception: return any errors or warnings in this structure.
4948 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4949 NexusInfo *nexus_info,ExceptionInfo *exception)
4951 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4952 return(MagickFalse);
4953 nexus_info->mapped=MagickFalse;
4954 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4955 nexus_info->length);
4956 if (nexus_info->cache == (PixelPacket *) NULL)
4958 nexus_info->mapped=MagickTrue;
4959 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4960 nexus_info->length);
4962 if (nexus_info->cache == (PixelPacket *) NULL)
4964 (void) ThrowMagickException(exception,GetMagickModule(),
4965 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4966 cache_info->filename);
4967 return(MagickFalse);
4972 static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4973 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4985 cache_info=(CacheInfo *) image->cache;
4986 assert(cache_info->signature == MagickSignature);
4987 if (cache_info->type == UndefinedCache)
4988 return((PixelPacket *) NULL);
4989 nexus_info->region=(*region);
4990 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4991 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
4997 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4998 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4999 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5000 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5001 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5002 ((nexus_info->region.width == cache_info->columns) ||
5003 ((nexus_info->region.width % cache_info->columns) == 0)))))
5009 Pixels are accessed directly from memory.
5011 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5012 nexus_info->region.x;
5013 nexus_info->pixels=cache_info->pixels+offset;
5014 nexus_info->indexes=(IndexPacket *) NULL;
5015 if (cache_info->active_index_channel != MagickFalse)
5016 nexus_info->indexes=cache_info->indexes+offset;
5017 return(nexus_info->pixels);
5021 Pixels are stored in a cache region until they are synced to the cache.
5023 number_pixels=(MagickSizeType) nexus_info->region.width*
5024 nexus_info->region.height;
5025 length=number_pixels*sizeof(PixelPacket);
5026 if (cache_info->active_index_channel != MagickFalse)
5027 length+=number_pixels*sizeof(IndexPacket);
5028 if (nexus_info->cache == (PixelPacket *) NULL)
5030 nexus_info->length=length;
5031 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5032 if (status == MagickFalse)
5034 nexus_info->length=0;
5035 return((PixelPacket *) NULL);
5039 if (nexus_info->length != length)
5041 RelinquishCacheNexusPixels(nexus_info);
5042 nexus_info->length=length;
5043 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5044 if (status == MagickFalse)
5046 nexus_info->length=0;
5047 return((PixelPacket *) NULL);
5050 nexus_info->pixels=nexus_info->cache;
5051 nexus_info->indexes=(IndexPacket *) NULL;
5052 if (cache_info->active_index_channel != MagickFalse)
5053 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5054 return(nexus_info->pixels);
5058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5062 % 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 %
5066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5068 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5069 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5070 % access that is outside the boundaries of the image cache.
5072 % The format of the SetPixelCacheVirtualMethod() method is:
5074 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5075 % const VirtualPixelMethod virtual_pixel_method)
5077 % A description of each parameter follows:
5079 % o image: the image.
5081 % o virtual_pixel_method: choose the type of virtual pixel.
5084 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5085 const VirtualPixelMethod virtual_pixel_method)
5093 assert(image != (Image *) NULL);
5094 assert(image->signature == MagickSignature);
5095 if (image->debug != MagickFalse)
5096 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5097 assert(image->cache != (Cache) NULL);
5098 cache_info=(CacheInfo *) image->cache;
5099 assert(cache_info->signature == MagickSignature);
5100 method=cache_info->virtual_pixel_method;
5101 cache_info->virtual_pixel_method=virtual_pixel_method;
5106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5110 + 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 %
5114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5116 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5117 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5118 % is synced, otherwise MagickFalse.
5120 % The format of the SyncAuthenticPixelCacheNexus() method is:
5122 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5123 % NexusInfo *nexus_info,ExceptionInfo *exception)
5125 % A description of each parameter follows:
5127 % o image: the image.
5129 % o nexus_info: the cache nexus to sync.
5131 % o exception: return any errors or warnings in this structure.
5134 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5135 NexusInfo *nexus_info,ExceptionInfo *exception)
5144 Transfer pixels to the cache.
5146 assert(image != (Image *) NULL);
5147 assert(image->signature == MagickSignature);
5148 if (image->cache == (Cache) NULL)
5149 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5150 cache_info=(CacheInfo *) image->cache;
5151 assert(cache_info->signature == MagickSignature);
5152 if (cache_info->type == UndefinedCache)
5153 return(MagickFalse);
5154 if ((image->clip_mask != (Image *) NULL) &&
5155 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5156 return(MagickFalse);
5157 if ((image->mask != (Image *) NULL) &&
5158 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5159 return(MagickFalse);
5160 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5162 assert(cache_info->signature == MagickSignature);
5163 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5164 if ((cache_info->active_index_channel != MagickFalse) &&
5165 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5166 return(MagickFalse);
5171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175 + S y n c A u t h e n t i c P i x e l C a c h e %
5179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5182 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5183 % otherwise MagickFalse.
5185 % The format of the SyncAuthenticPixelsCache() method is:
5187 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5188 % ExceptionInfo *exception)
5190 % A description of each parameter follows:
5192 % o image: the image.
5194 % o exception: return any errors or warnings in this structure.
5197 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5198 ExceptionInfo *exception)
5204 id = GetOpenMPThreadId();
5206 assert(image != (Image *) NULL);
5207 assert(image->signature == MagickSignature);
5208 assert(image->cache != (Cache) NULL);
5209 cache_info=(CacheInfo *) image->cache;
5210 assert(cache_info->signature == MagickSignature);
5211 assert(id < (int) cache_info->number_threads);
5212 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5221 % S y n c A u t h e n t i c P i x e l s %
5225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5227 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5228 % The method returns MagickTrue if the pixel region is flushed, otherwise
5231 % The format of the SyncAuthenticPixels() method is:
5233 % MagickBooleanType SyncAuthenticPixels(Image *image,
5234 % ExceptionInfo *exception)
5236 % A description of each parameter follows:
5238 % o image: the image.
5240 % o exception: return any errors or warnings in this structure.
5243 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5244 ExceptionInfo *exception)
5250 id = GetOpenMPThreadId();
5252 assert(image != (Image *) NULL);
5253 assert(image->signature == MagickSignature);
5254 assert(image->cache != (Cache) NULL);
5255 cache_info=(CacheInfo *) image->cache;
5256 assert(cache_info->signature == MagickSignature);
5257 if (cache_info->methods.sync_authentic_pixels_handler !=
5258 (SyncAuthenticPixelsHandler) NULL)
5259 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5260 assert(id < (int) cache_info->number_threads);
5261 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5270 + W r i t e P i x e l C a c h e I n d e x e s %
5274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5276 % WritePixelCacheIndexes() writes the colormap indexes to the specified
5277 % region of the pixel cache.
5279 % The format of the WritePixelCacheIndexes() method is:
5281 % MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5282 % NexusInfo *nexus_info,ExceptionInfo *exception)
5284 % A description of each parameter follows:
5286 % o cache_info: the pixel cache.
5288 % o nexus_info: the cache nexus to write the colormap indexes.
5290 % o exception: return any errors or warnings in this structure.
5293 static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5294 NexusInfo *nexus_info,ExceptionInfo *exception)
5304 register const IndexPacket
5313 if (cache_info->active_index_channel == MagickFalse)
5314 return(MagickFalse);
5315 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5317 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5318 nexus_info->region.x;
5319 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5320 rows=nexus_info->region.height;
5321 extent=(MagickSizeType) length*rows;
5322 p=nexus_info->indexes;
5323 switch (cache_info->type)
5328 register IndexPacket
5332 Write indexes to memory.
5334 if ((cache_info->columns == nexus_info->region.width) &&
5335 (extent == (MagickSizeType) ((size_t) extent)))
5340 q=cache_info->indexes+offset;
5341 for (y=0; y < (ssize_t) rows; y++)
5343 (void) memcpy(q,p,(size_t) length);
5344 p+=nexus_info->region.width;
5345 q+=cache_info->columns;
5352 Write indexes to disk.
5354 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5356 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5357 cache_info->cache_filename);
5358 return(MagickFalse);
5360 if ((cache_info->columns == nexus_info->region.width) &&
5361 (extent <= MagickMaxBufferExtent))
5366 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5367 for (y=0; y < (ssize_t) rows; y++)
5369 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5370 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5372 if ((MagickSizeType) count < length)
5374 p+=nexus_info->region.width;
5375 offset+=cache_info->columns;
5377 if (y < (ssize_t) rows)
5379 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5380 cache_info->cache_filename);
5381 return(MagickFalse);
5388 if ((cache_info->debug != MagickFalse) &&
5389 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5390 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5391 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5392 nexus_info->region.width,(double) nexus_info->region.height,(double)
5393 nexus_info->region.x,(double) nexus_info->region.y);
5398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5402 + W r i t e C a c h e P i x e l s %
5406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5408 % WritePixelCachePixels() writes image pixels to the specified region of the
5411 % The format of the WritePixelCachePixels() method is:
5413 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5414 % NexusInfo *nexus_info,ExceptionInfo *exception)
5416 % A description of each parameter follows:
5418 % o cache_info: the pixel cache.
5420 % o nexus_info: the cache nexus to write the pixels.
5422 % o exception: return any errors or warnings in this structure.
5425 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5426 NexusInfo *nexus_info,ExceptionInfo *exception)
5436 register const PixelPacket
5445 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5447 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5448 nexus_info->region.x;
5449 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5450 rows=nexus_info->region.height;
5452 p=nexus_info->pixels;
5453 switch (cache_info->type)
5458 register PixelPacket
5462 Write pixels to memory.
5464 if ((cache_info->columns == nexus_info->region.width) &&
5465 (extent == (MagickSizeType) ((size_t) extent)))
5470 q=cache_info->pixels+offset;
5471 for (y=0; y < (ssize_t) rows; y++)
5473 (void) memcpy(q,p,(size_t) length);
5474 p+=nexus_info->region.width;
5475 q+=cache_info->columns;
5482 Write pixels to disk.
5484 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5486 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5487 cache_info->cache_filename);
5488 return(MagickFalse);
5490 if ((cache_info->columns == nexus_info->region.width) &&
5491 (extent <= MagickMaxBufferExtent))
5496 for (y=0; y < (ssize_t) rows; y++)
5498 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5499 sizeof(*p),length,(const unsigned char *) p);
5500 if ((MagickSizeType) count < length)
5502 p+=nexus_info->region.width;
5503 offset+=cache_info->columns;
5505 if (y < (ssize_t) rows)
5507 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5508 cache_info->cache_filename);
5509 return(MagickFalse);
5516 if ((cache_info->debug != MagickFalse) &&
5517 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5518 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5519 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5520 nexus_info->region.width,(double) nexus_info->region.height,(double)
5521 nexus_info->region.x,(double) nexus_info->region.y);