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-2013 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 "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
120 Forward declarations.
122 #if defined(__cplusplus) || defined(c_plusplus)
127 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
131 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
132 const ssize_t,const size_t,const size_t,ExceptionInfo *),
133 *GetVirtualPixelsCache(const Image *);
136 *GetVirtualMetacontentFromCache(const Image *);
138 static MagickBooleanType
139 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
141 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
142 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
143 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
144 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
146 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
147 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
148 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
151 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
152 const size_t,ExceptionInfo *),
153 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
154 const size_t,ExceptionInfo *),
155 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
156 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
158 #if defined(__cplusplus) || defined(c_plusplus)
165 static volatile MagickBooleanType
166 instantiate_cache = MagickFalse;
169 *cache_semaphore = (SemaphoreInfo *) NULL;
172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 + A c q u i r e P i x e l C a c h e %
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 % AcquirePixelCache() acquires a pixel cache.
184 % The format of the AcquirePixelCache() method is:
186 % Cache AcquirePixelCache(const size_t number_threads)
188 % A description of each parameter follows:
190 % o number_threads: the number of nexus threads.
193 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
201 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
202 if (cache_info == (CacheInfo *) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
205 cache_info->type=UndefinedCache;
206 cache_info->mode=IOMode;
207 cache_info->colorspace=sRGBColorspace;
208 cache_info->file=(-1);
209 cache_info->id=GetMagickThreadId();
210 cache_info->number_threads=number_threads;
211 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
212 cache_info->number_threads=GetOpenMPMaximumThreads();
213 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
214 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
215 if (cache_info->number_threads == 0)
216 cache_info->number_threads=1;
217 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
218 if (cache_info->nexus_info == (NexusInfo **) NULL)
219 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
220 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
221 if (synchronize != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(synchronize);
224 synchronize=DestroyString(synchronize);
226 cache_info->semaphore=AllocateSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AllocateSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickSignature;
231 return((Cache ) cache_info);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % A c q u i r e P i x e l C a c h e N e x u s %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
247 % The format of the AcquirePixelCacheNexus method is:
249 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 % A description of each parameter follows:
253 % o number_threads: the number of nexus threads.
256 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
264 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
265 number_threads,sizeof(*nexus_info)));
266 if (nexus_info == (NexusInfo **) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
269 sizeof(**nexus_info));
270 if (nexus_info[0] == (NexusInfo *) NULL)
271 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
272 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
273 for (i=0; i < (ssize_t) number_threads; i++)
275 nexus_info[i]=(&nexus_info[0][i]);
276 nexus_info[i]->signature=MagickSignature;
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 + A c q u i r e P i x e l C a c h e P i x e l s %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % AcquirePixelCachePixels() returns the pixels associated with the specified
295 % The format of the AcquirePixelCachePixels() method is:
297 % const void *AcquirePixelCachePixels(const Image *image,
298 % MagickSizeType *length,ExceptionInfo *exception)
300 % A description of each parameter follows:
302 % o image: the image.
304 % o length: the pixel cache length.
306 % o exception: return any errors or warnings in this structure.
309 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
310 MagickSizeType *length,ExceptionInfo *exception)
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickSignature);
323 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
324 return((const void *) NULL);
325 *length=cache_info->length;
326 return((const void *) cache_info->pixels);
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 + C a c h e C o m p o n e n t G e n e s i s %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % CacheComponentGenesis() instantiates the cache component.
342 % The format of the CacheComponentGenesis method is:
344 % MagickBooleanType CacheComponentGenesis(void)
347 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
349 AcquireSemaphoreInfo(&cache_semaphore);
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 + C a c h e C o m p o n e n t T e r m i n u s %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 % CacheComponentTerminus() destroys the cache component.
366 % The format of the CacheComponentTerminus() method is:
368 % CacheComponentTerminus(void)
371 MagickPrivate void CacheComponentTerminus(void)
373 if (cache_semaphore == (SemaphoreInfo *) NULL)
374 AcquireSemaphoreInfo(&cache_semaphore);
375 LockSemaphoreInfo(cache_semaphore);
376 instantiate_cache=MagickFalse;
377 UnlockSemaphoreInfo(cache_semaphore);
378 DestroySemaphoreInfo(&cache_semaphore);
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 + C l o n e P i x e l C a c h e %
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 % ClonePixelCache() clones a pixel cache.
394 % The format of the ClonePixelCache() method is:
396 % Cache ClonePixelCache(const Cache cache)
398 % A description of each parameter follows:
400 % o cache: the pixel cache.
403 MagickPrivate Cache ClonePixelCache(const Cache cache)
411 assert(cache != (const Cache) NULL);
412 cache_info=(const CacheInfo *) cache;
413 assert(cache_info->signature == MagickSignature);
414 if (cache_info->debug != MagickFalse)
415 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
416 cache_info->filename);
417 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
418 if (clone_info == (Cache) NULL)
419 return((Cache) NULL);
420 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
421 return((Cache ) clone_info);
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 + C l o n e P i x e l C a c h e M e t h o d s %
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
438 % The format of the ClonePixelCacheMethods() method is:
440 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
442 % A description of each parameter follows:
444 % o clone: Specifies a pointer to a Cache structure.
446 % o cache: the pixel cache.
449 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
455 assert(clone != (Cache) NULL);
456 source_info=(CacheInfo *) clone;
457 assert(source_info->signature == MagickSignature);
458 if (source_info->debug != MagickFalse)
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
460 source_info->filename);
461 assert(cache != (Cache) NULL);
462 cache_info=(CacheInfo *) cache;
463 assert(cache_info->signature == MagickSignature);
464 source_info->methods=cache_info->methods;
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 + C l o n e P i x e l C a c h e R e p o s i t o r y %
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
477 % ClonePixelCacheRepository() clones the source pixel cache to the destination
480 % The format of the ClonePixelCacheRepository() method is:
482 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
483 % CacheInfo *source_info,ExceptionInfo *exception)
485 % A description of each parameter follows:
487 % o cache_info: the pixel cache.
489 % o source_info: the source pixel cache.
491 % o exception: return any errors or warnings in this structure.
495 static inline MagickSizeType MagickMin(const MagickSizeType x,
496 const MagickSizeType y)
503 static MagickBooleanType ClonePixelCacheRepository(CacheInfo *clone_info,
504 CacheInfo *cache_info,ExceptionInfo *exception)
506 #define MaxCacheThreads 2
507 #define cache_threads(source,destination,chunk) \
508 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
509 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
510 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
526 assert(cache_info != (CacheInfo *) NULL);
527 assert(clone_info != (CacheInfo *) NULL);
528 assert(exception != (ExceptionInfo *) NULL);
529 if (cache_info->type == PingCache)
531 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
532 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
533 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
534 (cache_info->columns == clone_info->columns) &&
535 (cache_info->rows == clone_info->rows) &&
536 (cache_info->number_channels == clone_info->number_channels) &&
537 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
538 (cache_info->metacontent_extent == clone_info->metacontent_extent))
541 Identical pixel cache morphology.
543 (void) memcpy(clone_info->pixels,cache_info->pixels,cache_info->columns*
544 cache_info->number_channels*cache_info->rows*
545 sizeof(*cache_info->pixels));
546 if (cache_info->metacontent_extent != 0)
547 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
548 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
549 sizeof(*cache_info->metacontent));
553 Mismatched pixel cache morphology.
555 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
556 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
557 if ((cache_nexus == (NexusInfo **) NULL) ||
558 (clone_nexus == (NexusInfo **) NULL))
559 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
560 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
561 optimize=(cache_info->number_channels == clone_info->number_channels) &&
562 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
563 MagickTrue : MagickFalse;
564 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
565 clone_info->columns*clone_info->number_channels);
567 #if defined(MAGICKCORE_OPENMP_SUPPORT)
568 #pragma omp parallel for schedule(static,4) shared(status) \
569 cache_threads(cache_info,clone_info,cache_info->rows)
571 for (y=0; y < (ssize_t) cache_info->rows; y++)
574 id = GetOpenMPThreadId();
585 if (status == MagickFalse)
587 if (y >= (ssize_t) clone_info->rows)
589 region.width=cache_info->columns;
593 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
595 if (pixels == (Quantum *) NULL)
597 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
598 if (status == MagickFalse)
600 region.width=clone_info->columns;
601 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
602 clone_nexus[id],exception);
603 if (pixels == (Quantum *) NULL)
605 if (optimize != MagickFalse)
606 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
610 register const Quantum
617 Mismatched pixel channel map.
619 p=cache_nexus[id]->pixels;
620 q=clone_nexus[id]->pixels;
621 for (x=0; x < (ssize_t) cache_info->columns; x++)
626 if (x == (ssize_t) clone_info->columns)
628 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
636 channel=clone_info->channel_map[i].channel;
637 traits=cache_info->channel_map[channel].traits;
638 if (traits != UndefinedPixelTrait)
639 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
643 p+=cache_info->number_channels;
646 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
648 if ((cache_info->metacontent_extent != 0) &&
649 (clone_info->metacontent_extent != 0))
654 length=(size_t) MagickMin(cache_info->metacontent_extent,
655 clone_info->metacontent_extent);
656 #if defined(MAGICKCORE_OPENMP_SUPPORT)
657 #pragma omp parallel for schedule(static,4) shared(status) \
658 cache_threads(cache_info,clone_info,cache_info->rows)
660 for (y=0; y < (ssize_t) cache_info->rows; y++)
663 id = GetOpenMPThreadId();
671 if (status == MagickFalse)
673 if (y >= (ssize_t) clone_info->rows)
675 region.width=cache_info->columns;
679 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
680 cache_nexus[id],exception);
681 if (pixels == (Quantum *) NULL)
683 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
684 if (status == MagickFalse)
686 region.width=clone_info->columns;
687 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
688 clone_nexus[id],exception);
689 if (pixels == (Quantum *) NULL)
691 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
692 length*sizeof(*cache_nexus[id]->metacontent));
693 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
696 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
697 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
698 if (cache_info->debug != MagickFalse)
701 message[MaxTextExtent];
703 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
704 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
705 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 + D e s t r o y I m a g e P i x e l C a c h e %
720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
724 % The format of the DestroyImagePixelCache() method is:
726 % void DestroyImagePixelCache(Image *image)
728 % A description of each parameter follows:
730 % o image: the image.
733 static void DestroyImagePixelCache(Image *image)
735 assert(image != (Image *) NULL);
736 assert(image->signature == MagickSignature);
737 if (image->debug != MagickFalse)
738 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
739 if (image->cache == (void *) NULL)
741 image->cache=DestroyPixelCache(image->cache);
745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749 + D e s t r o y I m a g e P i x e l s %
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755 % DestroyImagePixels() deallocates memory associated with the pixel cache.
757 % The format of the DestroyImagePixels() method is:
759 % void DestroyImagePixels(Image *image)
761 % A description of each parameter follows:
763 % o image: the image.
766 MagickExport void DestroyImagePixels(Image *image)
771 assert(image != (const Image *) NULL);
772 assert(image->signature == MagickSignature);
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
775 assert(image->cache != (Cache) NULL);
776 cache_info=(CacheInfo *) image->cache;
777 assert(cache_info->signature == MagickSignature);
778 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
780 cache_info->methods.destroy_pixel_handler(image);
783 image->cache=DestroyPixelCache(image->cache);
787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
791 + D e s t r o y P i x e l C a c h e %
795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797 % DestroyPixelCache() deallocates memory associated with the pixel cache.
799 % The format of the DestroyPixelCache() method is:
801 % Cache DestroyPixelCache(Cache cache)
803 % A description of each parameter follows:
805 % o cache: the pixel cache.
809 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
815 if (cache_info->file != -1)
817 status=close(cache_info->file);
818 cache_info->file=(-1);
819 RelinquishMagickResource(FileResource,1);
821 return(status == -1 ? MagickFalse : MagickTrue);
824 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
826 switch (cache_info->type)
830 if (cache_info->mapped == MagickFalse)
831 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
834 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
835 (size_t) cache_info->length);
836 RelinquishMagickResource(MemoryResource,cache_info->length);
841 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
843 if (cache_info->mode != ReadMode)
844 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
845 *cache_info->cache_filename='\0';
846 RelinquishMagickResource(MapResource,cache_info->length);
850 if (cache_info->file != -1)
851 (void) ClosePixelCacheOnDisk(cache_info);
852 if (cache_info->mode != ReadMode)
853 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
854 *cache_info->cache_filename='\0';
855 RelinquishMagickResource(DiskResource,cache_info->length);
858 case DistributedCache:
860 *cache_info->cache_filename='\0';
861 (void) RelinquishDistributePixelCache(cache_info->server_info);
867 cache_info->type=UndefinedCache;
868 cache_info->mapped=MagickFalse;
869 cache_info->metacontent=(void *) NULL;
872 MagickPrivate Cache DestroyPixelCache(Cache cache)
877 assert(cache != (Cache) NULL);
878 cache_info=(CacheInfo *) cache;
879 assert(cache_info->signature == MagickSignature);
880 if (cache_info->debug != MagickFalse)
881 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
882 cache_info->filename);
883 LockSemaphoreInfo(cache_info->semaphore);
884 cache_info->reference_count--;
885 if (cache_info->reference_count != 0)
887 UnlockSemaphoreInfo(cache_info->semaphore);
888 return((Cache) NULL);
890 UnlockSemaphoreInfo(cache_info->semaphore);
891 if (cache_info->debug != MagickFalse)
894 message[MaxTextExtent];
896 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
897 cache_info->filename);
898 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
900 RelinquishPixelCachePixels(cache_info);
901 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
902 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
903 if (cache_info->nexus_info != (NexusInfo **) NULL)
904 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
905 cache_info->number_threads);
906 if (cache_info->random_info != (RandomInfo *) NULL)
907 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
908 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
909 DestroySemaphoreInfo(&cache_info->file_semaphore);
910 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
911 DestroySemaphoreInfo(&cache_info->semaphore);
912 cache_info->signature=(~MagickSignature);
913 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923 + D e s t r o y P i x e l C a c h e N e x u s %
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
931 % The format of the DestroyPixelCacheNexus() method is:
933 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
934 % const size_t number_threads)
936 % A description of each parameter follows:
938 % o nexus_info: the nexus to destroy.
940 % o number_threads: the number of nexus threads.
944 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
946 if (nexus_info->mapped == MagickFalse)
947 (void) RelinquishAlignedMemory(nexus_info->cache);
949 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
950 nexus_info->cache=(Quantum *) NULL;
951 nexus_info->pixels=(Quantum *) NULL;
952 nexus_info->metacontent=(void *) NULL;
953 nexus_info->length=0;
954 nexus_info->mapped=MagickFalse;
957 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
958 const size_t number_threads)
963 assert(nexus_info != (NexusInfo **) NULL);
964 for (i=0; i < (ssize_t) number_threads; i++)
966 if (nexus_info[i]->cache != (Quantum *) NULL)
967 RelinquishCacheNexusPixels(nexus_info[i]);
968 nexus_info[i]->signature=(~MagickSignature);
970 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
971 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980 % G e t A u t h e n t i c M e t a c o n t e n t %
984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
987 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
988 % returned if the associated pixels are not available.
990 % The format of the GetAuthenticMetacontent() method is:
992 % void *GetAuthenticMetacontent(const Image *image)
994 % A description of each parameter follows:
996 % o image: the image.
999 MagickExport void *GetAuthenticMetacontent(const Image *image)
1005 id = GetOpenMPThreadId();
1010 assert(image != (const Image *) NULL);
1011 assert(image->signature == MagickSignature);
1012 assert(image->cache != (Cache) NULL);
1013 cache_info=(CacheInfo *) image->cache;
1014 assert(cache_info->signature == MagickSignature);
1015 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1016 (GetAuthenticMetacontentFromHandler) NULL)
1018 metacontent=cache_info->methods.
1019 get_authentic_metacontent_from_handler(image);
1020 return(metacontent);
1022 assert(id < (int) cache_info->number_threads);
1023 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1024 cache_info->nexus_info[id]);
1025 return(metacontent);
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 + G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
1037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1039 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1040 % with the last call to QueueAuthenticPixelsCache() or
1041 % GetAuthenticPixelsCache().
1043 % The format of the GetAuthenticMetacontentFromCache() method is:
1045 % void *GetAuthenticMetacontentFromCache(const Image *image)
1047 % A description of each parameter follows:
1049 % o image: the image.
1052 static void *GetAuthenticMetacontentFromCache(const Image *image)
1058 id = GetOpenMPThreadId();
1063 assert(image != (const Image *) NULL);
1064 assert(image->signature == MagickSignature);
1065 assert(image->cache != (Cache) NULL);
1066 cache_info=(CacheInfo *) image->cache;
1067 assert(cache_info->signature == MagickSignature);
1068 assert(id < (int) cache_info->number_threads);
1069 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1070 cache_info->nexus_info[id]);
1071 return(metacontent);
1075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079 + 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 %
1083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1086 % disk pixel cache as defined by the geometry parameters. A pointer to the
1087 % pixels is returned if the pixels are transferred, otherwise a NULL is
1090 % The format of the GetAuthenticPixelCacheNexus() method is:
1092 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1093 % const ssize_t y,const size_t columns,const size_t rows,
1094 % NexusInfo *nexus_info,ExceptionInfo *exception)
1096 % A description of each parameter follows:
1098 % o image: the image.
1100 % o x,y,columns,rows: These values define the perimeter of a region of
1103 % o nexus_info: the cache nexus to return.
1105 % o exception: return any errors or warnings in this structure.
1109 static inline MagickBooleanType IsPixelAuthentic(
1110 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1118 if (cache_info->type == PingCache)
1120 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1121 nexus_info->region.x;
1122 status=nexus_info->pixels == (cache_info->pixels+offset*
1123 cache_info->number_channels) ? MagickTrue : MagickFalse;
1127 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1128 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1129 NexusInfo *nexus_info,ExceptionInfo *exception)
1138 Transfer pixels from the cache.
1140 assert(image != (Image *) NULL);
1141 assert(image->signature == MagickSignature);
1142 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1144 if (q == (Quantum *) NULL)
1145 return((Quantum *) NULL);
1146 cache_info=(CacheInfo *) image->cache;
1147 assert(cache_info->signature == MagickSignature);
1148 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1150 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1151 return((Quantum *) NULL);
1152 if (cache_info->metacontent_extent != 0)
1153 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1154 return((Quantum *) NULL);
1159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1163 + 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 %
1167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1170 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1172 % The format of the GetAuthenticPixelsFromCache() method is:
1174 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1176 % A description of each parameter follows:
1178 % o image: the image.
1181 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1187 id = GetOpenMPThreadId();
1189 assert(image != (const Image *) NULL);
1190 assert(image->signature == MagickSignature);
1191 assert(image->cache != (Cache) NULL);
1192 cache_info=(CacheInfo *) image->cache;
1193 assert(cache_info->signature == MagickSignature);
1194 assert(id < (int) cache_info->number_threads);
1195 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203 % G e t A u t h e n t i c P i x e l Q u e u e %
1207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209 % GetAuthenticPixelQueue() returns the authentic pixels associated
1210 % corresponding with the last call to QueueAuthenticPixels() or
1211 % GetAuthenticPixels().
1213 % The format of the GetAuthenticPixelQueue() method is:
1215 % Quantum *GetAuthenticPixelQueue(const Image image)
1217 % A description of each parameter follows:
1219 % o image: the image.
1222 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1228 id = GetOpenMPThreadId();
1230 assert(image != (const Image *) NULL);
1231 assert(image->signature == MagickSignature);
1232 assert(image->cache != (Cache) NULL);
1233 cache_info=(CacheInfo *) image->cache;
1234 assert(cache_info->signature == MagickSignature);
1235 if (cache_info->methods.get_authentic_pixels_from_handler !=
1236 (GetAuthenticPixelsFromHandler) NULL)
1237 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1238 assert(id < (int) cache_info->number_threads);
1239 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247 % G e t A u t h e n t i c P i x e l s %
1250 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1253 % region is successfully accessed, a pointer to a Quantum array
1254 % representing the region is returned, otherwise NULL is returned.
1256 % The returned pointer may point to a temporary working copy of the pixels
1257 % or it may point to the original pixels in memory. Performance is maximized
1258 % if the selected region is part of one row, or one or more full rows, since
1259 % then there is opportunity to access the pixels in-place (without a copy)
1260 % if the image is in memory, or in a memory-mapped file. The returned pointer
1261 % must *never* be deallocated by the user.
1263 % Pixels accessed via the returned pointer represent a simple array of type
1264 % Quantum. If the image has corresponding metacontent,call
1265 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1266 % meta-content corresponding to the region. Once the Quantum array has
1267 % been updated, the changes must be saved back to the underlying image using
1268 % SyncAuthenticPixels() or they may be lost.
1270 % The format of the GetAuthenticPixels() method is:
1272 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1273 % const ssize_t y,const size_t columns,const size_t rows,
1274 % ExceptionInfo *exception)
1276 % A description of each parameter follows:
1278 % o image: the image.
1280 % o x,y,columns,rows: These values define the perimeter of a region of
1283 % o exception: return any errors or warnings in this structure.
1286 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1287 const ssize_t y,const size_t columns,const size_t rows,
1288 ExceptionInfo *exception)
1294 id = GetOpenMPThreadId();
1299 assert(image != (Image *) NULL);
1300 assert(image->signature == MagickSignature);
1301 assert(image->cache != (Cache) NULL);
1302 cache_info=(CacheInfo *) image->cache;
1303 assert(cache_info->signature == MagickSignature);
1304 if (cache_info->methods.get_authentic_pixels_handler !=
1305 (GetAuthenticPixelsHandler) NULL)
1307 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1311 assert(id < (int) cache_info->number_threads);
1312 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1313 cache_info->nexus_info[id],exception);
1318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 + G e t A u t h e n t i c P i x e l s C a c h e %
1326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1328 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1329 % as defined by the geometry parameters. A pointer to the pixels is returned
1330 % if the pixels are transferred, otherwise a NULL is returned.
1332 % The format of the GetAuthenticPixelsCache() method is:
1334 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1335 % const ssize_t y,const size_t columns,const size_t rows,
1336 % ExceptionInfo *exception)
1338 % A description of each parameter follows:
1340 % o image: the image.
1342 % o x,y,columns,rows: These values define the perimeter of a region of
1345 % o exception: return any errors or warnings in this structure.
1348 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1349 const ssize_t y,const size_t columns,const size_t rows,
1350 ExceptionInfo *exception)
1356 id = GetOpenMPThreadId();
1361 assert(image != (const Image *) NULL);
1362 assert(image->signature == MagickSignature);
1363 assert(image->cache != (Cache) NULL);
1364 cache_info=(CacheInfo *) image->cache;
1365 if (cache_info == (Cache) NULL)
1366 return((Quantum *) NULL);
1367 assert(cache_info->signature == MagickSignature);
1368 assert(id < (int) cache_info->number_threads);
1369 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1370 cache_info->nexus_info[id],exception);
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379 + G e t I m a g e E x t e n t %
1383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385 % GetImageExtent() returns the extent of the pixels associated corresponding
1386 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1388 % The format of the GetImageExtent() method is:
1390 % MagickSizeType GetImageExtent(const Image *image)
1392 % A description of each parameter follows:
1394 % o image: the image.
1397 MagickExport MagickSizeType GetImageExtent(const Image *image)
1403 id = GetOpenMPThreadId();
1405 assert(image != (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 assert(id < (int) cache_info->number_threads);
1413 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 + G e t I m a g e P i x e l C a c h e %
1425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427 % GetImagePixelCache() ensures that there is only a single reference to the
1428 % pixel cache to be modified, updating the provided cache pointer to point to
1429 % a clone of the original pixel cache if necessary.
1431 % The format of the GetImagePixelCache method is:
1433 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1434 % ExceptionInfo *exception)
1436 % A description of each parameter follows:
1438 % o image: the image.
1440 % o clone: any value other than MagickFalse clones the cache pixels.
1442 % o exception: return any errors or warnings in this structure.
1446 static inline MagickBooleanType ValidatePixelCacheMorphology(
1447 const Image *restrict image)
1450 *restrict cache_info;
1452 const PixelChannelMap
1457 Does the image match the pixel cache morphology?
1459 cache_info=(CacheInfo *) image->cache;
1460 p=image->channel_map;
1461 q=cache_info->channel_map;
1462 if ((image->storage_class != cache_info->storage_class) ||
1463 (image->colorspace != cache_info->colorspace) ||
1464 (image->alpha_trait != cache_info->alpha_trait) ||
1465 (image->mask != cache_info->mask) ||
1466 (image->columns != cache_info->columns) ||
1467 (image->rows != cache_info->rows) ||
1468 (image->number_channels != cache_info->number_channels) ||
1469 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1470 (image->metacontent_extent != cache_info->metacontent_extent) ||
1471 (cache_info->nexus_info == (NexusInfo **) NULL))
1472 return(MagickFalse);
1476 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1477 ExceptionInfo *exception)
1486 static MagickSizeType
1492 cache_timestamp = 0;
1495 LockSemaphoreInfo(image->semaphore);
1496 if (cpu_throttle == 0)
1502 Set CPU throttle in milleseconds.
1504 cpu_throttle=MagickResourceInfinity;
1505 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1506 if (limit == (char *) NULL)
1507 limit=GetPolicyValue("throttle");
1508 if (limit != (char *) NULL)
1510 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1511 limit=DestroyString(limit);
1514 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1515 MagickDelay(cpu_throttle);
1516 if (time_limit == 0)
1519 Set the expire time in seconds.
1521 time_limit=GetMagickResourceLimit(TimeResource);
1522 cache_timestamp=time((time_t *) NULL);
1524 if ((time_limit != MagickResourceInfinity) &&
1525 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1526 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1527 assert(image->cache != (Cache) NULL);
1528 cache_info=(CacheInfo *) image->cache;
1529 destroy=MagickFalse;
1530 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1532 LockSemaphoreInfo(cache_info->semaphore);
1533 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1544 clone_image=(*image);
1545 clone_image.semaphore=AllocateSemaphoreInfo();
1546 clone_image.reference_count=1;
1547 clone_image.cache=ClonePixelCache(cache_info);
1548 clone_info=(CacheInfo *) clone_image.cache;
1549 status=OpenPixelCache(&clone_image,IOMode,exception);
1550 if (status != MagickFalse)
1552 if (clone != MagickFalse)
1553 status=ClonePixelCacheRepository(clone_info,cache_info,
1555 if (status != MagickFalse)
1557 if (cache_info->reference_count == 1)
1558 cache_info->nexus_info=(NexusInfo **) NULL;
1560 image->cache=clone_image.cache;
1563 DestroySemaphoreInfo(&clone_image.semaphore);
1565 UnlockSemaphoreInfo(cache_info->semaphore);
1567 if (destroy != MagickFalse)
1568 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1569 if (status != MagickFalse)
1572 Ensure the image matches the pixel cache morphology.
1574 image->taint=MagickTrue;
1575 image->type=UndefinedType;
1576 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1578 status=OpenPixelCache(image,IOMode,exception);
1579 cache_info=(CacheInfo *) image->cache;
1580 if (cache_info->type == DiskCache)
1581 (void) ClosePixelCacheOnDisk(cache_info);
1584 UnlockSemaphoreInfo(image->semaphore);
1585 if (status == MagickFalse)
1586 return((Cache) NULL);
1587 return(image->cache);
1591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595 + G e t I m a g e P i x e l C a c h e T y p e %
1599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1602 % DiskCache, MemoryCache, MapCache, or PingCache.
1604 % The format of the GetImagePixelCacheType() method is:
1606 % CacheType GetImagePixelCacheType(const Image *image)
1608 % A description of each parameter follows:
1610 % o image: the image.
1613 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1618 assert(image != (Image *) NULL);
1619 assert(image->signature == MagickSignature);
1620 assert(image->cache != (Cache) NULL);
1621 cache_info=(CacheInfo *) image->cache;
1622 assert(cache_info->signature == MagickSignature);
1623 return(cache_info->type);
1627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 % G e t O n e A u t h e n t i c P i x e l %
1635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1638 % location. The image background color is returned if an error occurs.
1640 % The format of the GetOneAuthenticPixel() method is:
1642 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1643 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1645 % A description of each parameter follows:
1647 % o image: the image.
1649 % o x,y: These values define the location of the pixel to return.
1651 % o pixel: return a pixel at the specified (x,y) location.
1653 % o exception: return any errors or warnings in this structure.
1656 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1657 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1668 assert(image != (Image *) NULL);
1669 assert(image->signature == MagickSignature);
1670 assert(image->cache != (Cache) NULL);
1671 cache_info=(CacheInfo *) image->cache;
1672 assert(cache_info->signature == MagickSignature);
1673 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1674 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1675 (GetOneAuthenticPixelFromHandler) NULL)
1676 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1678 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1679 if (q == (Quantum *) NULL)
1681 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1682 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1683 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1684 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1685 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1686 return(MagickFalse);
1688 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1693 channel=GetPixelChannelChannel(image,i);
1694 pixel[channel]=q[i];
1700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1704 + 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 %
1708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1710 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1711 % location. The image background color is returned if an error occurs.
1713 % The format of the GetOneAuthenticPixelFromCache() method is:
1715 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1716 % const ssize_t x,const ssize_t y,Quantum *pixel,
1717 % ExceptionInfo *exception)
1719 % A description of each parameter follows:
1721 % o image: the image.
1723 % o x,y: These values define the location of the pixel to return.
1725 % o pixel: return a pixel at the specified (x,y) location.
1727 % o exception: return any errors or warnings in this structure.
1730 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1731 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1737 id = GetOpenMPThreadId();
1745 assert(image != (const Image *) NULL);
1746 assert(image->signature == MagickSignature);
1747 assert(image->cache != (Cache) NULL);
1748 cache_info=(CacheInfo *) image->cache;
1749 assert(cache_info->signature == MagickSignature);
1750 assert(id < (int) cache_info->number_threads);
1751 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1752 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1754 if (q == (Quantum *) NULL)
1756 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1757 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1758 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1759 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1760 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1761 return(MagickFalse);
1763 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1768 channel=GetPixelChannelChannel(image,i);
1769 pixel[channel]=q[i];
1775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1779 % G e t O n e V i r t u a l P i x e l %
1783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1785 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1786 % (x,y) location. The image background color is returned if an error occurs.
1787 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1789 % The format of the GetOneVirtualPixel() method is:
1791 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1792 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1794 % A description of each parameter follows:
1796 % o image: the image.
1798 % o x,y: These values define the location of the pixel to return.
1800 % o pixel: return a pixel at the specified (x,y) location.
1802 % o exception: return any errors or warnings in this structure.
1805 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1806 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1812 id = GetOpenMPThreadId();
1820 assert(image != (const Image *) NULL);
1821 assert(image->signature == MagickSignature);
1822 assert(image->cache != (Cache) NULL);
1823 cache_info=(CacheInfo *) image->cache;
1824 assert(cache_info->signature == MagickSignature);
1825 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1826 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1827 (GetOneVirtualPixelFromHandler) NULL)
1828 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1829 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1830 assert(id < (int) cache_info->number_threads);
1831 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1832 1UL,1UL,cache_info->nexus_info[id],exception);
1833 if (p == (const Quantum *) NULL)
1835 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1836 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1837 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1838 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1839 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1840 return(MagickFalse);
1842 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1847 channel=GetPixelChannelChannel(image,i);
1848 pixel[channel]=p[i];
1854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1858 + 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 %
1862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1864 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1865 % specified (x,y) location. The image background color is returned if an
1868 % The format of the GetOneVirtualPixelFromCache() method is:
1870 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1871 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1872 % Quantum *pixel,ExceptionInfo *exception)
1874 % A description of each parameter follows:
1876 % o image: the image.
1878 % o virtual_pixel_method: the virtual pixel method.
1880 % o x,y: These values define the location of the pixel to return.
1882 % o pixel: return a pixel at the specified (x,y) location.
1884 % o exception: return any errors or warnings in this structure.
1887 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1888 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1889 Quantum *pixel,ExceptionInfo *exception)
1895 id = GetOpenMPThreadId();
1903 assert(image != (const Image *) NULL);
1904 assert(image->signature == MagickSignature);
1905 assert(image->cache != (Cache) NULL);
1906 cache_info=(CacheInfo *) image->cache;
1907 assert(cache_info->signature == MagickSignature);
1908 assert(id < (int) cache_info->number_threads);
1909 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1910 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1911 cache_info->nexus_info[id],exception);
1912 if (p == (const Quantum *) NULL)
1914 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1915 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1916 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1917 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1918 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1919 return(MagickFalse);
1921 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1926 channel=GetPixelChannelChannel(image,i);
1927 pixel[channel]=p[i];
1933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937 % G e t O n e V i r t u a l P i x e l I n f o %
1941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1944 % location. The image background color is returned if an error occurs. If
1945 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1947 % The format of the GetOneVirtualPixelInfo() method is:
1949 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1950 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1951 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1953 % A description of each parameter follows:
1955 % o image: the image.
1957 % o virtual_pixel_method: the virtual pixel method.
1959 % o x,y: these values define the location of the pixel to return.
1961 % o pixel: return a pixel at the specified (x,y) location.
1963 % o exception: return any errors or warnings in this structure.
1966 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1967 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1968 PixelInfo *pixel,ExceptionInfo *exception)
1974 id = GetOpenMPThreadId();
1976 register const Quantum
1979 assert(image != (const Image *) NULL);
1980 assert(image->signature == MagickSignature);
1981 assert(image->cache != (Cache) NULL);
1982 cache_info=(CacheInfo *) image->cache;
1983 assert(cache_info->signature == MagickSignature);
1984 assert(id < (int) cache_info->number_threads);
1985 GetPixelInfo(image,pixel);
1986 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1987 cache_info->nexus_info[id],exception);
1988 if (p == (const Quantum *) NULL)
1989 return(MagickFalse);
1990 GetPixelInfoPixel(image,p,pixel);
1995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999 + G e t P i x e l C a c h e C o l o r s p a c e %
2003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2005 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2007 % The format of the GetPixelCacheColorspace() method is:
2009 % Colorspace GetPixelCacheColorspace(Cache cache)
2011 % A description of each parameter follows:
2013 % o cache: the pixel cache.
2016 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2021 assert(cache != (Cache) NULL);
2022 cache_info=(CacheInfo *) cache;
2023 assert(cache_info->signature == MagickSignature);
2024 if (cache_info->debug != MagickFalse)
2025 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2026 cache_info->filename);
2027 return(cache_info->colorspace);
2031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2035 + G e t P i x e l C a c h e M e t h o d s %
2039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2041 % GetPixelCacheMethods() initializes the CacheMethods structure.
2043 % The format of the GetPixelCacheMethods() method is:
2045 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2047 % A description of each parameter follows:
2049 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2052 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2054 assert(cache_methods != (CacheMethods *) NULL);
2055 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2056 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2057 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2058 cache_methods->get_virtual_metacontent_from_handler=
2059 GetVirtualMetacontentFromCache;
2060 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2061 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2062 cache_methods->get_authentic_metacontent_from_handler=
2063 GetAuthenticMetacontentFromCache;
2064 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2065 cache_methods->get_one_authentic_pixel_from_handler=
2066 GetOneAuthenticPixelFromCache;
2067 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2068 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2069 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2077 + G e t P i x e l C a c h e N e x u s E x t e n t %
2081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2083 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2084 % corresponding with the last call to SetPixelCacheNexusPixels() or
2085 % GetPixelCacheNexusPixels().
2087 % The format of the GetPixelCacheNexusExtent() method is:
2089 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2090 % NexusInfo *nexus_info)
2092 % A description of each parameter follows:
2094 % o nexus_info: the nexus info.
2097 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2098 NexusInfo *nexus_info)
2106 assert(cache != NULL);
2107 cache_info=(CacheInfo *) cache;
2108 assert(cache_info->signature == MagickSignature);
2109 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2111 return((MagickSizeType) cache_info->columns*cache_info->rows);
2116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2120 + G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
2124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2126 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2129 % The format of the GetPixelCacheNexusMetacontent() method is:
2131 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2132 % NexusInfo *nexus_info)
2134 % A description of each parameter follows:
2136 % o cache: the pixel cache.
2138 % o nexus_info: the cache nexus to return the meta-content.
2141 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2142 NexusInfo *nexus_info)
2147 assert(cache != NULL);
2148 cache_info=(CacheInfo *) cache;
2149 assert(cache_info->signature == MagickSignature);
2150 if (cache_info->storage_class == UndefinedClass)
2151 return((void *) NULL);
2152 return(nexus_info->metacontent);
2156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160 + G e t P i x e l C a c h e N e x u s P i x e l s %
2164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2169 % The format of the GetPixelCacheNexusPixels() method is:
2171 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2172 % NexusInfo *nexus_info)
2174 % A description of each parameter follows:
2176 % o cache: the pixel cache.
2178 % o nexus_info: the cache nexus to return the pixels.
2181 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2182 NexusInfo *nexus_info)
2187 assert(cache != NULL);
2188 cache_info=(CacheInfo *) cache;
2189 assert(cache_info->signature == MagickSignature);
2190 if (cache_info->storage_class == UndefinedClass)
2191 return((Quantum *) NULL);
2192 return(nexus_info->pixels);
2196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2200 + G e t P i x e l C a c h e P i x e l s %
2204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2206 % GetPixelCachePixels() returns the pixels associated with the specified image.
2208 % The format of the GetPixelCachePixels() method is:
2210 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2211 % ExceptionInfo *exception)
2213 % A description of each parameter follows:
2215 % o image: the image.
2217 % o length: the pixel cache length.
2219 % o exception: return any errors or warnings in this structure.
2222 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2223 ExceptionInfo *exception)
2228 assert(image != (const Image *) NULL);
2229 assert(image->signature == MagickSignature);
2230 assert(image->cache != (Cache) NULL);
2231 assert(length != (MagickSizeType *) NULL);
2232 assert(exception != (ExceptionInfo *) NULL);
2233 assert(exception->signature == MagickSignature);
2234 cache_info=(CacheInfo *) image->cache;
2235 assert(cache_info->signature == MagickSignature);
2237 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2238 return((void *) NULL);
2239 *length=cache_info->length;
2240 return((void *) cache_info->pixels);
2244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2248 + 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 %
2252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2254 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2256 % The format of the GetPixelCacheStorageClass() method is:
2258 % ClassType GetPixelCacheStorageClass(Cache cache)
2260 % A description of each parameter follows:
2262 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2264 % o cache: the pixel cache.
2267 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2272 assert(cache != (Cache) NULL);
2273 cache_info=(CacheInfo *) cache;
2274 assert(cache_info->signature == MagickSignature);
2275 if (cache_info->debug != MagickFalse)
2276 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2277 cache_info->filename);
2278 return(cache_info->storage_class);
2282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2286 + G e t P i x e l C a c h e T i l e S i z e %
2290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2292 % GetPixelCacheTileSize() returns the pixel cache tile size.
2294 % The format of the GetPixelCacheTileSize() method is:
2296 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2299 % A description of each parameter follows:
2301 % o image: the image.
2303 % o width: the optimize cache tile width in pixels.
2305 % o height: the optimize cache tile height in pixels.
2308 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2314 assert(image != (Image *) NULL);
2315 assert(image->signature == MagickSignature);
2316 if (image->debug != MagickFalse)
2317 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2318 cache_info=(CacheInfo *) image->cache;
2319 assert(cache_info->signature == MagickSignature);
2320 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2321 if (GetImagePixelCacheType(image) == DiskCache)
2322 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2331 + 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 %
2335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2338 % pixel cache. A virtual pixel is any pixel access that is outside the
2339 % boundaries of the image cache.
2341 % The format of the GetPixelCacheVirtualMethod() method is:
2343 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2345 % A description of each parameter follows:
2347 % o image: the image.
2350 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2355 assert(image != (Image *) NULL);
2356 assert(image->signature == MagickSignature);
2357 assert(image->cache != (Cache) NULL);
2358 cache_info=(CacheInfo *) image->cache;
2359 assert(cache_info->signature == MagickSignature);
2360 return(cache_info->virtual_pixel_method);
2364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2368 + G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
2372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2374 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2375 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2377 % The format of the GetVirtualMetacontentFromCache() method is:
2379 % void *GetVirtualMetacontentFromCache(const Image *image)
2381 % A description of each parameter follows:
2383 % o image: the image.
2386 static const void *GetVirtualMetacontentFromCache(const Image *image)
2392 id = GetOpenMPThreadId();
2397 assert(image != (const Image *) NULL);
2398 assert(image->signature == MagickSignature);
2399 assert(image->cache != (Cache) NULL);
2400 cache_info=(CacheInfo *) image->cache;
2401 assert(cache_info->signature == MagickSignature);
2402 assert(id < (int) cache_info->number_threads);
2403 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2404 cache_info->nexus_info[id]);
2405 return(metacontent);
2409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413 + G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
2417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2419 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2422 % The format of the GetVirtualMetacontentFromNexus() method is:
2424 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2425 % NexusInfo *nexus_info)
2427 % A description of each parameter follows:
2429 % o cache: the pixel cache.
2431 % o nexus_info: the cache nexus to return the meta-content.
2434 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2435 NexusInfo *nexus_info)
2440 assert(cache != (Cache) NULL);
2441 cache_info=(CacheInfo *) cache;
2442 assert(cache_info->signature == MagickSignature);
2443 if (cache_info->storage_class == UndefinedClass)
2444 return((void *) NULL);
2445 return(nexus_info->metacontent);
2449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2453 % G e t V i r t u a l M e t a c o n t e n t %
2457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2460 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2461 % returned if the meta-content are not available.
2463 % The format of the GetVirtualMetacontent() method is:
2465 % const void *GetVirtualMetacontent(const Image *image)
2467 % A description of each parameter follows:
2469 % o image: the image.
2472 MagickExport const void *GetVirtualMetacontent(const Image *image)
2478 id = GetOpenMPThreadId();
2483 assert(image != (const Image *) NULL);
2484 assert(image->signature == MagickSignature);
2485 assert(image->cache != (Cache) NULL);
2486 cache_info=(CacheInfo *) image->cache;
2487 assert(cache_info->signature == MagickSignature);
2488 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2489 if (metacontent != (void *) NULL)
2490 return(metacontent);
2491 assert(id < (int) cache_info->number_threads);
2492 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2493 cache_info->nexus_info[id]);
2494 return(metacontent);
2498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2502 + 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 %
2506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2509 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2510 % is returned if the pixels are transferred, otherwise a NULL is returned.
2512 % The format of the GetVirtualPixelsFromNexus() method is:
2514 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2515 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2516 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2517 % ExceptionInfo *exception)
2519 % A description of each parameter follows:
2521 % o image: the image.
2523 % o virtual_pixel_method: the virtual pixel method.
2525 % o x,y,columns,rows: These values define the perimeter of a region of
2528 % o nexus_info: the cache nexus to acquire.
2530 % o exception: return any errors or warnings in this structure.
2537 0, 48, 12, 60, 3, 51, 15, 63,
2538 32, 16, 44, 28, 35, 19, 47, 31,
2539 8, 56, 4, 52, 11, 59, 7, 55,
2540 40, 24, 36, 20, 43, 27, 39, 23,
2541 2, 50, 14, 62, 1, 49, 13, 61,
2542 34, 18, 46, 30, 33, 17, 45, 29,
2543 10, 58, 6, 54, 9, 57, 5, 53,
2544 42, 26, 38, 22, 41, 25, 37, 21
2547 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2552 index=x+DitherMatrix[x & 0x07]-32L;
2555 if (index >= (ssize_t) columns)
2556 return((ssize_t) columns-1L);
2560 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2565 index=y+DitherMatrix[y & 0x07]-32L;
2568 if (index >= (ssize_t) rows)
2569 return((ssize_t) rows-1L);
2573 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2577 if (x >= (ssize_t) columns)
2578 return((ssize_t) (columns-1));
2582 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2586 if (y >= (ssize_t) rows)
2587 return((ssize_t) (rows-1));
2591 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2593 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2596 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2598 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2601 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2602 const size_t extent)
2608 Compute the remainder of dividing offset by extent. It returns not only
2609 the quotient (tile the offset falls in) but also the positive remainer
2610 within that tile such that 0 <= remainder < extent. This method is
2611 essentially a ldiv() using a floored modulo division rather than the
2612 normal default truncated modulo division.
2614 modulo.quotient=offset/(ssize_t) extent;
2617 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2621 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2622 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2623 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2624 ExceptionInfo *exception)
2641 virtual_pixel[CompositePixelChannel];
2646 register const Quantum
2659 register unsigned char
2666 *virtual_metacontent;
2671 assert(image != (const Image *) NULL);
2672 assert(image->signature == MagickSignature);
2673 assert(image->cache != (Cache) NULL);
2674 cache_info=(CacheInfo *) image->cache;
2675 assert(cache_info->signature == MagickSignature);
2676 if (cache_info->type == UndefinedCache)
2677 return((const Quantum *) NULL);
2680 region.width=columns;
2682 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2684 if (pixels == (Quantum *) NULL)
2685 return((const Quantum *) NULL);
2687 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2688 nexus_info->region.x;
2689 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2690 nexus_info->region.width-1L;
2691 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2692 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2693 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2694 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2700 Pixel request is inside cache extents.
2702 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2704 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2705 if (status == MagickFalse)
2706 return((const Quantum *) NULL);
2707 if (cache_info->metacontent_extent != 0)
2709 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2710 if (status == MagickFalse)
2711 return((const Quantum *) NULL);
2716 Pixel request is outside cache extents.
2718 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2719 virtual_nexus=AcquirePixelCacheNexus(1);
2720 if (virtual_nexus == (NexusInfo **) NULL)
2722 if (virtual_nexus != (NexusInfo **) NULL)
2723 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2724 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2725 "UnableToGetCacheNexus","`%s'",image->filename);
2726 return((const Quantum *) NULL);
2728 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2729 sizeof(*virtual_pixel));
2730 virtual_metacontent=(void *) NULL;
2731 switch (virtual_pixel_method)
2733 case BackgroundVirtualPixelMethod:
2734 case BlackVirtualPixelMethod:
2735 case GrayVirtualPixelMethod:
2736 case TransparentVirtualPixelMethod:
2737 case MaskVirtualPixelMethod:
2738 case WhiteVirtualPixelMethod:
2739 case EdgeVirtualPixelMethod:
2740 case CheckerTileVirtualPixelMethod:
2741 case HorizontalTileVirtualPixelMethod:
2742 case VerticalTileVirtualPixelMethod:
2744 if (cache_info->metacontent_extent != 0)
2747 Acquire a metacontent buffer.
2749 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2750 cache_info->metacontent_extent);
2751 if (virtual_metacontent == (void *) NULL)
2753 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2754 (void) ThrowMagickException(exception,GetMagickModule(),
2755 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2756 return((const Quantum *) NULL);
2758 (void) ResetMagickMemory(virtual_metacontent,0,
2759 cache_info->metacontent_extent);
2761 switch (virtual_pixel_method)
2763 case BlackVirtualPixelMethod:
2765 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2766 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2767 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2770 case GrayVirtualPixelMethod:
2772 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2773 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2775 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2778 case TransparentVirtualPixelMethod:
2780 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2781 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2782 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2785 case MaskVirtualPixelMethod:
2786 case WhiteVirtualPixelMethod:
2788 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2789 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2790 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2795 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2797 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2799 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2801 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2803 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2813 for (v=0; v < (ssize_t) rows; v++)
2815 for (u=0; u < (ssize_t) columns; u+=length)
2817 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
2818 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
2819 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
2827 Transfer a single pixel.
2829 length=(MagickSizeType) 1;
2830 switch (virtual_pixel_method)
2834 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2835 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
2836 1UL,1UL,*virtual_nexus,exception);
2837 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2840 case RandomVirtualPixelMethod:
2842 if (cache_info->random_info == (RandomInfo *) NULL)
2843 cache_info->random_info=AcquireRandomInfo();
2844 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2845 RandomX(cache_info->random_info,cache_info->columns),
2846 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2847 *virtual_nexus,exception);
2848 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2851 case DitherVirtualPixelMethod:
2853 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2854 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
2855 1UL,1UL,*virtual_nexus,exception);
2856 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2859 case TileVirtualPixelMethod:
2861 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2862 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2863 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2864 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2866 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2869 case MirrorVirtualPixelMethod:
2871 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2872 if ((x_modulo.quotient & 0x01) == 1L)
2873 x_modulo.remainder=(ssize_t) cache_info->columns-
2874 x_modulo.remainder-1L;
2875 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2876 if ((y_modulo.quotient & 0x01) == 1L)
2877 y_modulo.remainder=(ssize_t) cache_info->rows-
2878 y_modulo.remainder-1L;
2879 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2880 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2882 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2885 case HorizontalTileEdgeVirtualPixelMethod:
2887 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2888 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2889 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
2890 *virtual_nexus,exception);
2891 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2894 case VerticalTileEdgeVirtualPixelMethod:
2896 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2897 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2898 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
2899 *virtual_nexus,exception);
2900 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2903 case BackgroundVirtualPixelMethod:
2904 case BlackVirtualPixelMethod:
2905 case GrayVirtualPixelMethod:
2906 case TransparentVirtualPixelMethod:
2907 case MaskVirtualPixelMethod:
2908 case WhiteVirtualPixelMethod:
2911 r=virtual_metacontent;
2914 case EdgeVirtualPixelMethod:
2915 case CheckerTileVirtualPixelMethod:
2917 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2918 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2919 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2922 r=virtual_metacontent;
2925 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2926 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2928 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2931 case HorizontalTileVirtualPixelMethod:
2933 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
2936 r=virtual_metacontent;
2939 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2940 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2941 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2942 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2944 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2947 case VerticalTileVirtualPixelMethod:
2949 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
2952 r=virtual_metacontent;
2955 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2956 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2957 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2958 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2960 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2964 if (p == (const Quantum *) NULL)
2966 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2968 q+=cache_info->number_channels;
2969 if ((s != (void *) NULL) && (r != (const void *) NULL))
2971 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2972 s+=cache_info->metacontent_extent;
2977 Transfer a run of pixels.
2979 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
2980 length,1UL,*virtual_nexus,exception);
2981 if (p == (const Quantum *) NULL)
2983 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2984 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2985 q+=length*cache_info->number_channels;
2986 if ((r != (void *) NULL) && (s != (const void *) NULL))
2988 (void) memcpy(s,r,(size_t) length);
2989 s+=length*cache_info->metacontent_extent;
2996 if (virtual_metacontent != (void *) NULL)
2997 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2998 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007 + G e t V i r t u a l P i x e l C a c h e %
3011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3013 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3014 % cache as defined by the geometry parameters. A pointer to the pixels
3015 % is returned if the pixels are transferred, otherwise a NULL is returned.
3017 % The format of the GetVirtualPixelCache() method is:
3019 % const Quantum *GetVirtualPixelCache(const Image *image,
3020 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3021 % const ssize_t y,const size_t columns,const size_t rows,
3022 % ExceptionInfo *exception)
3024 % A description of each parameter follows:
3026 % o image: the image.
3028 % o virtual_pixel_method: the virtual pixel method.
3030 % o x,y,columns,rows: These values define the perimeter of a region of
3033 % o exception: return any errors or warnings in this structure.
3036 static const Quantum *GetVirtualPixelCache(const Image *image,
3037 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3038 const size_t columns,const size_t rows,ExceptionInfo *exception)
3044 id = GetOpenMPThreadId();
3049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
3051 assert(image->cache != (Cache) NULL);
3052 cache_info=(CacheInfo *) image->cache;
3053 assert(cache_info->signature == MagickSignature);
3054 assert(id < (int) cache_info->number_threads);
3055 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3056 cache_info->nexus_info[id],exception);
3061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3065 % G e t V i r t u a l P i x e l Q u e u e %
3069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3071 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3072 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3074 % The format of the GetVirtualPixelQueue() method is:
3076 % const Quantum *GetVirtualPixelQueue(const Image image)
3078 % A description of each parameter follows:
3080 % o image: the image.
3083 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3089 id = GetOpenMPThreadId();
3091 assert(image != (const Image *) NULL);
3092 assert(image->signature == MagickSignature);
3093 assert(image->cache != (Cache) NULL);
3094 cache_info=(CacheInfo *) image->cache;
3095 assert(cache_info->signature == MagickSignature);
3096 if (cache_info->methods.get_virtual_pixels_handler !=
3097 (GetVirtualPixelsHandler) NULL)
3098 return(cache_info->methods.get_virtual_pixels_handler(image));
3099 assert(id < (int) cache_info->number_threads);
3100 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3108 % G e t V i r t u a l P i x e l s %
3112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3114 % GetVirtualPixels() returns an immutable pixel region. If the
3115 % region is successfully accessed, a pointer to it is returned, otherwise
3116 % NULL is returned. The returned pointer may point to a temporary working
3117 % copy of the pixels or it may point to the original pixels in memory.
3118 % Performance is maximized if the selected region is part of one row, or one
3119 % or more full rows, since there is opportunity to access the pixels in-place
3120 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3121 % returned pointer must *never* be deallocated by the user.
3123 % Pixels accessed via the returned pointer represent a simple array of type
3124 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3125 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3126 % access the meta-content (of type void) corresponding to the the
3129 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3131 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3132 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3133 % GetCacheViewAuthenticPixels() instead.
3135 % The format of the GetVirtualPixels() method is:
3137 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3138 % const ssize_t y,const size_t columns,const size_t rows,
3139 % ExceptionInfo *exception)
3141 % A description of each parameter follows:
3143 % o image: the image.
3145 % o x,y,columns,rows: These values define the perimeter of a region of
3148 % o exception: return any errors or warnings in this structure.
3151 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3152 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3153 ExceptionInfo *exception)
3159 id = GetOpenMPThreadId();
3164 assert(image != (const Image *) NULL);
3165 assert(image->signature == MagickSignature);
3166 assert(image->cache != (Cache) NULL);
3167 cache_info=(CacheInfo *) image->cache;
3168 assert(cache_info->signature == MagickSignature);
3169 if (cache_info->methods.get_virtual_pixel_handler !=
3170 (GetVirtualPixelHandler) NULL)
3171 return(cache_info->methods.get_virtual_pixel_handler(image,
3172 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3173 assert(id < (int) cache_info->number_threads);
3174 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3175 columns,rows,cache_info->nexus_info[id],exception);
3180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3184 + 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 %
3188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3190 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3191 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3193 % The format of the GetVirtualPixelsCache() method is:
3195 % Quantum *GetVirtualPixelsCache(const Image *image)
3197 % A description of each parameter follows:
3199 % o image: the image.
3202 static const Quantum *GetVirtualPixelsCache(const Image *image)
3208 id = GetOpenMPThreadId();
3210 assert(image != (const Image *) NULL);
3211 assert(image->signature == MagickSignature);
3212 assert(image->cache != (Cache) NULL);
3213 cache_info=(CacheInfo *) image->cache;
3214 assert(cache_info->signature == MagickSignature);
3215 assert(id < (int) cache_info->number_threads);
3216 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3224 + G e t V i r t u a l P i x e l s N e x u s %
3228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3230 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3233 % The format of the GetVirtualPixelsNexus() method is:
3235 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3236 % NexusInfo *nexus_info)
3238 % A description of each parameter follows:
3240 % o cache: the pixel cache.
3242 % o nexus_info: the cache nexus to return the colormap pixels.
3245 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3246 NexusInfo *nexus_info)
3251 assert(cache != (Cache) NULL);
3252 cache_info=(CacheInfo *) cache;
3253 assert(cache_info->signature == MagickSignature);
3254 if (cache_info->storage_class == UndefinedClass)
3255 return((Quantum *) NULL);
3256 return((const Quantum *) nexus_info->pixels);
3260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3264 + O p e n P i x e l C a c h e %
3268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3270 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3271 % dimensions, allocating space for the image pixels and optionally the
3272 % metacontent, and memory mapping the cache if it is disk based. The cache
3273 % nexus array is initialized as well.
3275 % The format of the OpenPixelCache() method is:
3277 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3278 % ExceptionInfo *exception)
3280 % A description of each parameter follows:
3282 % o image: the image.
3284 % o mode: ReadMode, WriteMode, or IOMode.
3286 % o exception: return any errors or warnings in this structure.
3290 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3292 cache_info->mapped=MagickFalse;
3293 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3294 (size_t) cache_info->length));
3295 if (cache_info->pixels == (Quantum *) NULL)
3297 cache_info->mapped=MagickTrue;
3298 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3299 cache_info->length);
3303 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3310 Open pixel cache on disk.
3312 if (cache_info->file != -1)
3313 return(MagickTrue); /* cache already open */
3314 if (*cache_info->cache_filename == '\0')
3315 file=AcquireUniqueFileResource(cache_info->cache_filename);
3321 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3326 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3327 O_BINARY | O_EXCL,S_MODE);
3329 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3335 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3338 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3343 return(MagickFalse);
3344 (void) AcquireMagickResource(FileResource,1);
3345 cache_info->file=file;
3346 cache_info->mode=mode;
3350 static inline MagickOffsetType WritePixelCacheRegion(
3351 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3352 const MagickSizeType length,const unsigned char *restrict buffer)
3354 register MagickOffsetType
3360 #if !defined(MAGICKCORE_HAVE_PWRITE)
3361 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3362 return((MagickOffsetType) -1);
3365 for (i=0; i < (MagickOffsetType) length; i+=count)
3367 #if !defined(MAGICKCORE_HAVE_PWRITE)
3368 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3369 (MagickSizeType) SSIZE_MAX));
3371 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3372 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3384 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3394 cache_info=(CacheInfo *) image->cache;
3395 if (image->debug != MagickFalse)
3398 format[MaxTextExtent],
3399 message[MaxTextExtent];
3401 (void) FormatMagickSize(length,MagickFalse,format);
3402 (void) FormatLocaleString(message,MaxTextExtent,
3403 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3404 cache_info->cache_filename,cache_info->file,format);
3405 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3407 if (length != (MagickSizeType) ((MagickOffsetType) length))
3408 return(MagickFalse);
3409 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3411 return(MagickFalse);
3412 if ((MagickSizeType) offset >= length)
3414 extent=(MagickOffsetType) length-1;
3415 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3416 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3417 if (cache_info->synchronize != MagickFalse)
3422 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3424 return(MagickFalse);
3427 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3430 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3431 ExceptionInfo *exception)
3438 format[MaxTextExtent],
3439 message[MaxTextExtent];
3455 assert(image != (const Image *) NULL);
3456 assert(image->signature == MagickSignature);
3457 assert(image->cache != (Cache) NULL);
3458 if (image->debug != MagickFalse)
3459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3460 if ((image->columns == 0) || (image->rows == 0))
3461 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3462 cache_info=(CacheInfo *) image->cache;
3463 assert(cache_info->signature == MagickSignature);
3464 source_info=(*cache_info);
3465 source_info.file=(-1);
3466 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3467 image->filename,(double) GetImageIndexInList(image));
3468 cache_info->storage_class=image->storage_class;
3469 cache_info->colorspace=image->colorspace;
3470 cache_info->alpha_trait=image->alpha_trait;
3471 cache_info->mask=image->mask;
3472 cache_info->rows=image->rows;
3473 cache_info->columns=image->columns;
3474 InitializePixelChannelMap(image);
3475 cache_info->number_channels=GetPixelChannels(image);
3476 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3477 sizeof(*image->channel_map));
3478 cache_info->metacontent_extent=image->metacontent_extent;
3479 cache_info->mode=mode;
3480 if (image->ping != MagickFalse)
3482 cache_info->type=PingCache;
3483 cache_info->pixels=(Quantum *) NULL;
3484 cache_info->metacontent=(void *) NULL;
3485 cache_info->length=0;
3488 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3489 packet_size=cache_info->number_channels*sizeof(Quantum);
3490 if (image->metacontent_extent != 0)
3491 packet_size+=cache_info->metacontent_extent;
3492 length=number_pixels*packet_size;
3493 columns=(size_t) (length/cache_info->rows/packet_size);
3494 if (cache_info->columns != columns)
3495 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3497 cache_info->length=length;
3498 status=AcquireMagickResource(AreaResource,cache_info->length);
3499 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3500 cache_info->metacontent_extent);
3501 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3503 status=AcquireMagickResource(MemoryResource,cache_info->length);
3504 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3505 (cache_info->type == MemoryCache))
3507 AllocatePixelCachePixels(cache_info);
3508 if (cache_info->pixels == (Quantum *) NULL)
3509 cache_info->pixels=source_info.pixels;
3513 Create memory pixel cache.
3516 cache_info->type=MemoryCache;
3517 cache_info->metacontent=(void *) NULL;
3518 if (cache_info->metacontent_extent != 0)
3519 cache_info->metacontent=(void *) (cache_info->pixels+
3520 number_pixels*cache_info->number_channels);
3521 if ((source_info.storage_class != UndefinedClass) &&
3524 status=ClonePixelCacheRepository(cache_info,&source_info,
3526 RelinquishPixelCachePixels(&source_info);
3528 if (image->debug != MagickFalse)
3530 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3531 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3533 (void) FormatLocaleString(message,MaxTextExtent,
3534 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3535 cache_info->filename,cache_info->mapped != MagickFalse ?
3536 "Anonymous" : "Heap",type,(double) cache_info->columns,
3537 (double) cache_info->rows,(double)
3538 cache_info->number_channels,format);
3539 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3545 RelinquishMagickResource(MemoryResource,cache_info->length);
3548 Create pixel cache on disk.
3550 status=AcquireMagickResource(DiskResource,cache_info->length);
3551 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3556 if (cache_info->type == DistributedCache)
3557 RelinquishMagickResource(DiskResource,cache_info->length);
3558 server_info=AcquireDistributeCacheInfo(exception);
3559 if (server_info != (DistributeCacheInfo *) NULL)
3561 status=OpenDistributePixelCache(server_info,image);
3562 if (status == MagickFalse)
3564 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3565 GetDistributeCacheHostname(server_info));
3566 server_info=DestroyDistributeCacheInfo(server_info);
3571 Create a distributed pixel cache.
3573 cache_info->type=DistributedCache;
3574 cache_info->server_info=server_info;
3575 (void) FormatLocaleString(cache_info->cache_filename,
3576 MaxTextExtent,"%s:%d",
3577 GetDistributeCacheHostname(cache_info->server_info),
3578 GetDistributeCachePort(cache_info->server_info));
3579 if ((source_info.storage_class != UndefinedClass) &&
3582 status=ClonePixelCacheRepository(cache_info,&source_info,
3584 RelinquishPixelCachePixels(&source_info);
3586 if (image->debug != MagickFalse)
3588 (void) FormatMagickSize(cache_info->length,MagickFalse,
3590 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3592 (void) FormatLocaleString(message,MaxTextExtent,
3593 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3594 cache_info->filename,cache_info->cache_filename,
3595 GetDistributeCacheFile(cache_info->server_info),type,
3596 (double) cache_info->columns,(double) cache_info->rows,
3597 (double) cache_info->number_channels,format);
3598 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3604 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3605 "CacheResourcesExhausted","`%s'",image->filename);
3606 return(MagickFalse);
3608 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3610 (void) ClosePixelCacheOnDisk(cache_info);
3611 *cache_info->cache_filename='\0';
3613 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3615 RelinquishMagickResource(DiskResource,cache_info->length);
3616 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3618 return(MagickFalse);
3620 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3621 cache_info->length);
3622 if (status == MagickFalse)
3624 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3626 return(MagickFalse);
3628 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3629 cache_info->metacontent_extent);
3630 if (length != (MagickSizeType) ((size_t) length))
3631 cache_info->type=DiskCache;
3634 status=AcquireMagickResource(MapResource,cache_info->length);
3635 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3636 (cache_info->type != MemoryCache))
3637 cache_info->type=DiskCache;
3640 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3641 cache_info->offset,(size_t) cache_info->length);
3642 if (cache_info->pixels == (Quantum *) NULL)
3644 cache_info->type=DiskCache;
3645 cache_info->pixels=source_info.pixels;
3650 Create file-backed memory-mapped pixel cache.
3653 (void) ClosePixelCacheOnDisk(cache_info);
3654 cache_info->type=MapCache;
3655 cache_info->mapped=MagickTrue;
3656 cache_info->metacontent=(void *) NULL;
3657 if (cache_info->metacontent_extent != 0)
3658 cache_info->metacontent=(void *) (cache_info->pixels+
3659 number_pixels*cache_info->number_channels);
3660 if ((source_info.storage_class != UndefinedClass) &&
3663 status=ClonePixelCacheRepository(cache_info,&source_info,
3665 RelinquishPixelCachePixels(&source_info);
3667 if (image->debug != MagickFalse)
3669 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3670 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3672 (void) FormatLocaleString(message,MaxTextExtent,
3673 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3674 cache_info->filename,cache_info->cache_filename,
3675 cache_info->file,type,(double) cache_info->columns,(double)
3676 cache_info->rows,(double) cache_info->number_channels,
3678 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3684 RelinquishMagickResource(MapResource,cache_info->length);
3687 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3689 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3690 RelinquishPixelCachePixels(&source_info);
3692 if (image->debug != MagickFalse)
3694 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3695 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3697 (void) FormatLocaleString(message,MaxTextExtent,
3698 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3699 cache_info->cache_filename,cache_info->file,type,(double)
3700 cache_info->columns,(double) cache_info->rows,(double)
3701 cache_info->number_channels,format);
3702 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3712 + P e r s i s t P i x e l C a c h e %
3716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3718 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3719 % persistent pixel cache is one that resides on disk and is not destroyed
3720 % when the program exits.
3722 % The format of the PersistPixelCache() method is:
3724 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3725 % const MagickBooleanType attach,MagickOffsetType *offset,
3726 % ExceptionInfo *exception)
3728 % A description of each parameter follows:
3730 % o image: the image.
3732 % o filename: the persistent pixel cache filename.
3734 % o attach: A value other than zero initializes the persistent pixel cache.
3736 % o initialize: A value other than zero initializes the persistent pixel
3739 % o offset: the offset in the persistent cache to store pixels.
3741 % o exception: return any errors or warnings in this structure.
3744 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3745 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3746 ExceptionInfo *exception)
3761 assert(image != (Image *) NULL);
3762 assert(image->signature == MagickSignature);
3763 if (image->debug != MagickFalse)
3764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3765 assert(image->cache != (void *) NULL);
3766 assert(filename != (const char *) NULL);
3767 assert(offset != (MagickOffsetType *) NULL);
3768 page_size=GetMagickPageSize();
3769 cache_info=(CacheInfo *) image->cache;
3770 assert(cache_info->signature == MagickSignature);
3771 if (attach != MagickFalse)
3774 Attach existing persistent pixel cache.
3776 if (image->debug != MagickFalse)
3777 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3778 "attach persistent cache");
3779 (void) CopyMagickString(cache_info->cache_filename,filename,
3781 cache_info->type=DiskCache;
3782 cache_info->offset=(*offset);
3783 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3784 return(MagickFalse);
3785 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3788 if ((cache_info->mode != ReadMode) &&
3789 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3790 (cache_info->reference_count == 1))
3792 LockSemaphoreInfo(cache_info->semaphore);
3793 if ((cache_info->mode != ReadMode) &&
3794 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3795 (cache_info->reference_count == 1))
3801 Usurp existing persistent pixel cache.
3803 status=rename_utf8(cache_info->cache_filename,filename);
3806 (void) CopyMagickString(cache_info->cache_filename,filename,
3808 *offset+=cache_info->length+page_size-(cache_info->length %
3810 UnlockSemaphoreInfo(cache_info->semaphore);
3811 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3812 if (image->debug != MagickFalse)
3813 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3814 "Usurp resident persistent cache");
3818 UnlockSemaphoreInfo(cache_info->semaphore);
3821 Clone persistent pixel cache.
3823 clone_image=(*image);
3824 clone_info=(CacheInfo *) clone_image.cache;
3825 image->cache=ClonePixelCache(cache_info);
3826 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3827 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3828 cache_info->type=DiskCache;
3829 cache_info->offset=(*offset);
3830 cache_info=(CacheInfo *) image->cache;
3831 status=OpenPixelCache(image,IOMode,exception);
3832 if (status != MagickFalse)
3833 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3834 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3835 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3844 + Q u e u e A u t h e n t i c P i x e l C a c h e N e x u s %
3848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3850 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3851 % defined by the region rectangle and returns a pointer to the region. This
3852 % region is subsequently transferred from the pixel cache with
3853 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3854 % pixels are transferred, otherwise a NULL is returned.
3856 % The format of the QueueAuthenticPixelCacheNexus() method is:
3858 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3859 % const ssize_t y,const size_t columns,const size_t rows,
3860 % const MagickBooleanType clone,NexusInfo *nexus_info,
3861 % ExceptionInfo *exception)
3863 % A description of each parameter follows:
3865 % o image: the image.
3867 % o x,y,columns,rows: These values define the perimeter of a region of
3870 % o nexus_info: the cache nexus to set.
3872 % o clone: clone the pixel cache.
3874 % o exception: return any errors or warnings in this structure.
3877 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3878 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3879 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3897 Validate pixel cache geometry.
3899 assert(image != (const Image *) NULL);
3900 assert(image->signature == MagickSignature);
3901 assert(image->cache != (Cache) NULL);
3902 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3903 if (cache_info == (Cache) NULL)
3904 return((Quantum *) NULL);
3905 assert(cache_info->signature == MagickSignature);
3906 if ((cache_info->columns == 0) && (cache_info->rows == 0))
3908 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3909 "NoPixelsDefinedInCache","`%s'",image->filename);
3910 return((Quantum *) NULL);
3912 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3913 (y >= (ssize_t) cache_info->rows))
3915 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3916 "PixelsAreNotAuthentic","`%s'",image->filename);
3917 return((Quantum *) NULL);
3919 offset=(MagickOffsetType) y*cache_info->columns+x;
3921 return((Quantum *) NULL);
3922 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3923 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3924 if ((MagickSizeType) offset >= number_pixels)
3925 return((Quantum *) NULL);
3931 region.width=columns;
3933 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3943 + 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 %
3947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3949 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3950 % defined by the region rectangle and returns a pointer to the region. This
3951 % region is subsequently transferred from the pixel cache with
3952 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3953 % pixels are transferred, otherwise a NULL is returned.
3955 % The format of the QueueAuthenticPixelsCache() method is:
3957 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3958 % const ssize_t y,const size_t columns,const size_t rows,
3959 % ExceptionInfo *exception)
3961 % A description of each parameter follows:
3963 % o image: the image.
3965 % o x,y,columns,rows: These values define the perimeter of a region of
3968 % o exception: return any errors or warnings in this structure.
3971 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3972 const ssize_t y,const size_t columns,const size_t rows,
3973 ExceptionInfo *exception)
3979 id = GetOpenMPThreadId();
3984 assert(image != (const Image *) NULL);
3985 assert(image->signature == MagickSignature);
3986 assert(image->cache != (Cache) NULL);
3987 cache_info=(CacheInfo *) image->cache;
3988 assert(cache_info->signature == MagickSignature);
3989 assert(id < (int) cache_info->number_threads);
3990 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3991 cache_info->nexus_info[id],exception);
3996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4000 % Q u e u e A u t h e n t i c P i x e l s %
4004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4006 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4007 % successfully initialized a pointer to a Quantum array representing the
4008 % region is returned, otherwise NULL is returned. The returned pointer may
4009 % point to a temporary working buffer for the pixels or it may point to the
4010 % final location of the pixels in memory.
4012 % Write-only access means that any existing pixel values corresponding to
4013 % the region are ignored. This is useful if the initial image is being
4014 % created from scratch, or if the existing pixel values are to be
4015 % completely replaced without need to refer to their pre-existing values.
4016 % The application is free to read and write the pixel buffer returned by
4017 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4018 % initialize the pixel array values. Initializing pixel array values is the
4019 % application's responsibility.
4021 % Performance is maximized if the selected region is part of one row, or
4022 % one or more full rows, since then there is opportunity to access the
4023 % pixels in-place (without a copy) if the image is in memory, or in a
4024 % memory-mapped file. The returned pointer must *never* be deallocated
4027 % Pixels accessed via the returned pointer represent a simple array of type
4028 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4029 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4030 % obtain the meta-content (of type void) corresponding to the region.
4031 % Once the Quantum (and/or Quantum) array has been updated, the
4032 % changes must be saved back to the underlying image using
4033 % SyncAuthenticPixels() or they may be lost.
4035 % The format of the QueueAuthenticPixels() method is:
4037 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4038 % const ssize_t y,const size_t columns,const size_t rows,
4039 % ExceptionInfo *exception)
4041 % A description of each parameter follows:
4043 % o image: the image.
4045 % o x,y,columns,rows: These values define the perimeter of a region of
4048 % o exception: return any errors or warnings in this structure.
4051 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4052 const ssize_t y,const size_t columns,const size_t rows,
4053 ExceptionInfo *exception)
4059 id = GetOpenMPThreadId();
4064 assert(image != (Image *) NULL);
4065 assert(image->signature == MagickSignature);
4066 assert(image->cache != (Cache) NULL);
4067 cache_info=(CacheInfo *) image->cache;
4068 assert(cache_info->signature == MagickSignature);
4069 if (cache_info->methods.queue_authentic_pixels_handler !=
4070 (QueueAuthenticPixelsHandler) NULL)
4072 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4076 assert(id < (int) cache_info->number_threads);
4077 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4078 cache_info->nexus_info[id],exception);
4083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4087 + R e a d P i x e l C a c h e M e t a c o n t e n t %
4091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4093 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4096 % The format of the ReadPixelCacheMetacontent() method is:
4098 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4099 % NexusInfo *nexus_info,ExceptionInfo *exception)
4101 % A description of each parameter follows:
4103 % o cache_info: the pixel cache.
4105 % o nexus_info: the cache nexus to read the metacontent.
4107 % o exception: return any errors or warnings in this structure.
4111 static inline MagickOffsetType ReadPixelCacheRegion(
4112 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4113 const MagickSizeType length,unsigned char *restrict buffer)
4115 register MagickOffsetType
4121 #if !defined(MAGICKCORE_HAVE_PREAD)
4122 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4123 return((MagickOffsetType) -1);
4126 for (i=0; i < (MagickOffsetType) length; i+=count)
4128 #if !defined(MAGICKCORE_HAVE_PREAD)
4129 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4130 (MagickSizeType) SSIZE_MAX));
4132 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4133 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4145 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4146 NexusInfo *nexus_info,ExceptionInfo *exception)
4159 register unsigned char
4165 if (cache_info->metacontent_extent == 0)
4166 return(MagickFalse);
4167 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4169 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4170 nexus_info->region.x;
4171 length=(MagickSizeType) nexus_info->region.width*
4172 cache_info->metacontent_extent;
4173 extent=length*nexus_info->region.height;
4174 rows=nexus_info->region.height;
4176 q=(unsigned char *) nexus_info->metacontent;
4177 switch (cache_info->type)
4182 register unsigned char
4186 Read meta-content from memory.
4188 if ((cache_info->columns == nexus_info->region.width) &&
4189 (extent == (MagickSizeType) ((size_t) extent)))
4194 p=(unsigned char *) cache_info->metacontent+offset*
4195 cache_info->metacontent_extent;
4196 for (y=0; y < (ssize_t) rows; y++)
4198 (void) memcpy(q,p,(size_t) length);
4199 p+=cache_info->metacontent_extent*cache_info->columns;
4200 q+=cache_info->metacontent_extent*nexus_info->region.width;
4207 Read meta content from disk.
4209 LockSemaphoreInfo(cache_info->file_semaphore);
4210 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4212 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4213 cache_info->cache_filename);
4214 UnlockSemaphoreInfo(cache_info->file_semaphore);
4215 return(MagickFalse);
4217 if ((cache_info->columns == nexus_info->region.width) &&
4218 (extent <= MagickMaxBufferExtent))
4223 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4224 for (y=0; y < (ssize_t) rows; y++)
4226 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4227 cache_info->number_channels*sizeof(Quantum)+offset*
4228 cache_info->metacontent_extent,length,(unsigned char *) q);
4229 if (count != (MagickOffsetType) length)
4231 offset+=cache_info->columns;
4232 q+=cache_info->metacontent_extent*nexus_info->region.width;
4234 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4235 (void) ClosePixelCacheOnDisk(cache_info);
4236 UnlockSemaphoreInfo(cache_info->file_semaphore);
4239 case DistributedCache:
4245 Read metacontent from distributed cache.
4247 LockSemaphoreInfo(cache_info->file_semaphore);
4248 region=nexus_info->region;
4249 if ((cache_info->columns != nexus_info->region.width) ||
4250 (extent > MagickMaxBufferExtent))
4257 for (y=0; y < (ssize_t) rows; y++)
4259 count=ReadDistributePixelCacheMetacontent(cache_info->server_info,
4260 ®ion,length,(unsigned char *) q);
4261 if (count != (MagickOffsetType) length)
4263 q+=cache_info->metacontent_extent*nexus_info->region.width;
4266 UnlockSemaphoreInfo(cache_info->file_semaphore);
4272 if (y < (ssize_t) rows)
4274 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4275 cache_info->cache_filename);
4276 return(MagickFalse);
4278 if ((cache_info->debug != MagickFalse) &&
4279 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4280 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4281 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4282 nexus_info->region.width,(double) nexus_info->region.height,(double)
4283 nexus_info->region.x,(double) nexus_info->region.y);
4288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4292 + R e a d P i x e l C a c h e P i x e l s %
4296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4298 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4301 % The format of the ReadPixelCachePixels() method is:
4303 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4304 % NexusInfo *nexus_info,ExceptionInfo *exception)
4306 % A description of each parameter follows:
4308 % o cache_info: the pixel cache.
4310 % o nexus_info: the cache nexus to read the pixels.
4312 % o exception: return any errors or warnings in this structure.
4315 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4316 NexusInfo *nexus_info,ExceptionInfo *exception)
4335 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4337 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4338 nexus_info->region.x;
4339 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4341 extent=length*nexus_info->region.height;
4342 rows=nexus_info->region.height;
4344 q=nexus_info->pixels;
4345 switch (cache_info->type)
4354 Read pixels from memory.
4356 if ((cache_info->columns == nexus_info->region.width) &&
4357 (extent == (MagickSizeType) ((size_t) extent)))
4362 p=cache_info->pixels+offset*cache_info->number_channels;
4363 for (y=0; y < (ssize_t) rows; y++)
4365 (void) memcpy(q,p,(size_t) length);
4366 p+=cache_info->number_channels*cache_info->columns;
4367 q+=cache_info->number_channels*nexus_info->region.width;
4374 Read pixels from disk.
4376 LockSemaphoreInfo(cache_info->file_semaphore);
4377 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4379 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4380 cache_info->cache_filename);
4381 UnlockSemaphoreInfo(cache_info->file_semaphore);
4382 return(MagickFalse);
4384 if ((cache_info->columns == nexus_info->region.width) &&
4385 (extent <= MagickMaxBufferExtent))
4390 for (y=0; y < (ssize_t) rows; y++)
4392 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4393 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4394 if (count != (MagickOffsetType) length)
4396 offset+=cache_info->columns;
4397 q+=cache_info->number_channels*nexus_info->region.width;
4399 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4400 (void) ClosePixelCacheOnDisk(cache_info);
4401 UnlockSemaphoreInfo(cache_info->file_semaphore);
4404 case DistributedCache:
4410 Read pixels from distributed cache.
4412 LockSemaphoreInfo(cache_info->file_semaphore);
4413 region=nexus_info->region;
4414 if ((cache_info->columns != nexus_info->region.width) ||
4415 (extent > MagickMaxBufferExtent))
4422 for (y=0; y < (ssize_t) rows; y++)
4424 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4425 length,(unsigned char *) q);
4426 if (count != (MagickOffsetType) length)
4428 q+=cache_info->number_channels*nexus_info->region.width;
4431 UnlockSemaphoreInfo(cache_info->file_semaphore);
4437 if (y < (ssize_t) rows)
4439 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4440 cache_info->cache_filename);
4441 return(MagickFalse);
4443 if ((cache_info->debug != MagickFalse) &&
4444 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4445 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4446 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4447 nexus_info->region.width,(double) nexus_info->region.height,(double)
4448 nexus_info->region.x,(double) nexus_info->region.y);
4453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4457 + R e f e r e n c e P i x e l C a c h e %
4461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4463 % ReferencePixelCache() increments the reference count associated with the
4464 % pixel cache returning a pointer to the cache.
4466 % The format of the ReferencePixelCache method is:
4468 % Cache ReferencePixelCache(Cache cache_info)
4470 % A description of each parameter follows:
4472 % o cache_info: the pixel cache.
4475 MagickPrivate Cache ReferencePixelCache(Cache cache)
4480 assert(cache != (Cache *) NULL);
4481 cache_info=(CacheInfo *) cache;
4482 assert(cache_info->signature == MagickSignature);
4483 LockSemaphoreInfo(cache_info->semaphore);
4484 cache_info->reference_count++;
4485 UnlockSemaphoreInfo(cache_info->semaphore);
4490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4494 + S e t P i x e l C a c h e M e t h o d s %
4498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4500 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4502 % The format of the SetPixelCacheMethods() method is:
4504 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4506 % A description of each parameter follows:
4508 % o cache: the pixel cache.
4510 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4513 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4518 GetOneAuthenticPixelFromHandler
4519 get_one_authentic_pixel_from_handler;
4521 GetOneVirtualPixelFromHandler
4522 get_one_virtual_pixel_from_handler;
4525 Set cache pixel methods.
4527 assert(cache != (Cache) NULL);
4528 assert(cache_methods != (CacheMethods *) NULL);
4529 cache_info=(CacheInfo *) cache;
4530 assert(cache_info->signature == MagickSignature);
4531 if (cache_info->debug != MagickFalse)
4532 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4533 cache_info->filename);
4534 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4535 cache_info->methods.get_virtual_pixel_handler=
4536 cache_methods->get_virtual_pixel_handler;
4537 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4538 cache_info->methods.destroy_pixel_handler=
4539 cache_methods->destroy_pixel_handler;
4540 if (cache_methods->get_virtual_metacontent_from_handler !=
4541 (GetVirtualMetacontentFromHandler) NULL)
4542 cache_info->methods.get_virtual_metacontent_from_handler=
4543 cache_methods->get_virtual_metacontent_from_handler;
4544 if (cache_methods->get_authentic_pixels_handler !=
4545 (GetAuthenticPixelsHandler) NULL)
4546 cache_info->methods.get_authentic_pixels_handler=
4547 cache_methods->get_authentic_pixels_handler;
4548 if (cache_methods->queue_authentic_pixels_handler !=
4549 (QueueAuthenticPixelsHandler) NULL)
4550 cache_info->methods.queue_authentic_pixels_handler=
4551 cache_methods->queue_authentic_pixels_handler;
4552 if (cache_methods->sync_authentic_pixels_handler !=
4553 (SyncAuthenticPixelsHandler) NULL)
4554 cache_info->methods.sync_authentic_pixels_handler=
4555 cache_methods->sync_authentic_pixels_handler;
4556 if (cache_methods->get_authentic_pixels_from_handler !=
4557 (GetAuthenticPixelsFromHandler) NULL)
4558 cache_info->methods.get_authentic_pixels_from_handler=
4559 cache_methods->get_authentic_pixels_from_handler;
4560 if (cache_methods->get_authentic_metacontent_from_handler !=
4561 (GetAuthenticMetacontentFromHandler) NULL)
4562 cache_info->methods.get_authentic_metacontent_from_handler=
4563 cache_methods->get_authentic_metacontent_from_handler;
4564 get_one_virtual_pixel_from_handler=
4565 cache_info->methods.get_one_virtual_pixel_from_handler;
4566 if (get_one_virtual_pixel_from_handler !=
4567 (GetOneVirtualPixelFromHandler) NULL)
4568 cache_info->methods.get_one_virtual_pixel_from_handler=
4569 cache_methods->get_one_virtual_pixel_from_handler;
4570 get_one_authentic_pixel_from_handler=
4571 cache_methods->get_one_authentic_pixel_from_handler;
4572 if (get_one_authentic_pixel_from_handler !=
4573 (GetOneAuthenticPixelFromHandler) NULL)
4574 cache_info->methods.get_one_authentic_pixel_from_handler=
4575 cache_methods->get_one_authentic_pixel_from_handler;
4579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4583 + S e t P i x e l C a c h e N e x u s P i x e l s %
4587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4589 % SetPixelCacheNexusPixels() defines the region of the cache for the
4590 % specified cache nexus.
4592 % The format of the SetPixelCacheNexusPixels() method is:
4594 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4595 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4596 % ExceptionInfo *exception)
4598 % A description of each parameter follows:
4600 % o cache_info: the pixel cache.
4602 % o mode: ReadMode, WriteMode, or IOMode.
4604 % o region: A pointer to the RectangleInfo structure that defines the
4605 % region of this particular cache nexus.
4607 % o nexus_info: the cache nexus to set.
4609 % o exception: return any errors or warnings in this structure.
4613 static inline MagickBooleanType AcquireCacheNexusPixels(
4614 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4615 ExceptionInfo *exception)
4617 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4618 return(MagickFalse);
4619 nexus_info->mapped=MagickFalse;
4620 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4621 (size_t) nexus_info->length));
4622 if (nexus_info->cache == (Quantum *) NULL)
4624 nexus_info->mapped=MagickTrue;
4625 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4626 nexus_info->length);
4628 if (nexus_info->cache == (Quantum *) NULL)
4630 (void) ThrowMagickException(exception,GetMagickModule(),
4631 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4632 cache_info->filename);
4633 return(MagickFalse);
4638 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4641 if (mode == ReadMode)
4643 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4646 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4649 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4650 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4651 ExceptionInfo *exception)
4660 assert(cache_info != (const CacheInfo *) NULL);
4661 assert(cache_info->signature == MagickSignature);
4662 if (cache_info->type == UndefinedCache)
4663 return((Quantum *) NULL);
4664 nexus_info->region=(*region);
4665 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4671 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4672 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4673 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4674 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4675 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4676 ((nexus_info->region.width == cache_info->columns) ||
4677 ((nexus_info->region.width % cache_info->columns) == 0)))))
4683 Pixels are accessed directly from memory.
4685 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4686 nexus_info->region.x;
4687 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4689 nexus_info->metacontent=(void *) NULL;
4690 if (cache_info->metacontent_extent != 0)
4691 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4692 offset*cache_info->metacontent_extent;
4693 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4694 return(nexus_info->pixels);
4698 Pixels are stored in a cache region until they are synced to the cache.
4700 number_pixels=(MagickSizeType) nexus_info->region.width*
4701 nexus_info->region.height;
4702 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4703 if (cache_info->metacontent_extent != 0)
4704 length+=number_pixels*cache_info->metacontent_extent;
4705 if (nexus_info->cache == (Quantum *) NULL)
4707 nexus_info->length=length;
4708 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4709 if (status == MagickFalse)
4711 nexus_info->length=0;
4712 return((Quantum *) NULL);
4716 if (nexus_info->length != length)
4718 RelinquishCacheNexusPixels(nexus_info);
4719 nexus_info->length=length;
4720 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4721 if (status == MagickFalse)
4723 nexus_info->length=0;
4724 return((Quantum *) NULL);
4727 nexus_info->pixels=nexus_info->cache;
4728 nexus_info->metacontent=(void *) NULL;
4729 if (cache_info->metacontent_extent != 0)
4730 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4731 cache_info->number_channels);
4732 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4733 return(nexus_info->pixels);
4737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4741 % 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 %
4745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4747 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4748 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4749 % access that is outside the boundaries of the image cache.
4751 % The format of the SetPixelCacheVirtualMethod() method is:
4753 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4754 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4756 % A description of each parameter follows:
4758 % o image: the image.
4760 % o virtual_pixel_method: choose the type of virtual pixel.
4762 % o exception: return any errors or warnings in this structure.
4766 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4767 ExceptionInfo *exception)
4781 assert(image != (Image *) NULL);
4782 assert(image->signature == MagickSignature);
4783 if (image->debug != MagickFalse)
4784 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4785 assert(image->cache != (Cache) NULL);
4786 cache_info=(CacheInfo *) image->cache;
4787 assert(cache_info->signature == MagickSignature);
4788 image->alpha_trait=BlendPixelTrait;
4790 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4791 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4792 #pragma omp parallel for schedule(static,4) shared(status) \
4793 magick_threads(image,image,1,1)
4795 for (y=0; y < (ssize_t) image->rows; y++)
4803 if (status == MagickFalse)
4805 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4806 if (q == (Quantum *) NULL)
4811 for (x=0; x < (ssize_t) image->columns; x++)
4813 SetPixelAlpha(image,alpha,q);
4814 q+=GetPixelChannels(image);
4816 status=SyncCacheViewAuthenticPixels(image_view,exception);
4818 image_view=DestroyCacheView(image_view);
4822 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4823 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4831 assert(image != (Image *) NULL);
4832 assert(image->signature == MagickSignature);
4833 if (image->debug != MagickFalse)
4834 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4835 assert(image->cache != (Cache) NULL);
4836 cache_info=(CacheInfo *) image->cache;
4837 assert(cache_info->signature == MagickSignature);
4838 method=cache_info->virtual_pixel_method;
4839 cache_info->virtual_pixel_method=virtual_pixel_method;
4840 if ((image->columns != 0) && (image->rows != 0))
4841 switch (virtual_pixel_method)
4843 case BackgroundVirtualPixelMethod:
4845 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4846 (image->alpha_trait != BlendPixelTrait))
4847 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4848 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4849 (IsGrayColorspace(image->colorspace) != MagickFalse))
4850 (void) TransformImageColorspace(image,RGBColorspace,exception);
4853 case TransparentVirtualPixelMethod:
4855 if (image->alpha_trait != BlendPixelTrait)
4856 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870 + 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 %
4874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4876 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4877 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4878 % is synced, otherwise MagickFalse.
4880 % The format of the SyncAuthenticPixelCacheNexus() method is:
4882 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4883 % NexusInfo *nexus_info,ExceptionInfo *exception)
4885 % A description of each parameter follows:
4887 % o image: the image.
4889 % o nexus_info: the cache nexus to sync.
4891 % o exception: return any errors or warnings in this structure.
4894 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4895 NexusInfo *nexus_info,ExceptionInfo *exception)
4904 Transfer pixels to the cache.
4906 assert(image != (Image *) NULL);
4907 assert(image->signature == MagickSignature);
4908 if (image->cache == (Cache) NULL)
4909 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4910 cache_info=(CacheInfo *) image->cache;
4911 assert(cache_info->signature == MagickSignature);
4912 if (cache_info->type == UndefinedCache)
4913 return(MagickFalse);
4914 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4916 assert(cache_info->signature == MagickSignature);
4917 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4918 if ((cache_info->metacontent_extent != 0) &&
4919 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4920 return(MagickFalse);
4925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4929 + S y n c A u t h e n t i c P i x e l C a c h e %
4933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4935 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4936 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4937 % otherwise MagickFalse.
4939 % The format of the SyncAuthenticPixelsCache() method is:
4941 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4942 % ExceptionInfo *exception)
4944 % A description of each parameter follows:
4946 % o image: the image.
4948 % o exception: return any errors or warnings in this structure.
4951 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4952 ExceptionInfo *exception)
4958 id = GetOpenMPThreadId();
4963 assert(image != (Image *) NULL);
4964 assert(image->signature == MagickSignature);
4965 assert(image->cache != (Cache) NULL);
4966 cache_info=(CacheInfo *) image->cache;
4967 assert(cache_info->signature == MagickSignature);
4968 assert(id < (int) cache_info->number_threads);
4969 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4979 % S y n c A u t h e n t i c P i x e l s %
4983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4985 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4986 % The method returns MagickTrue if the pixel region is flushed, otherwise
4989 % The format of the SyncAuthenticPixels() method is:
4991 % MagickBooleanType SyncAuthenticPixels(Image *image,
4992 % ExceptionInfo *exception)
4994 % A description of each parameter follows:
4996 % o image: the image.
4998 % o exception: return any errors or warnings in this structure.
5001 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5002 ExceptionInfo *exception)
5008 id = GetOpenMPThreadId();
5013 assert(image != (Image *) NULL);
5014 assert(image->signature == MagickSignature);
5015 assert(image->cache != (Cache) NULL);
5016 cache_info=(CacheInfo *) image->cache;
5017 assert(cache_info->signature == MagickSignature);
5018 if (cache_info->methods.sync_authentic_pixels_handler !=
5019 (SyncAuthenticPixelsHandler) NULL)
5021 status=cache_info->methods.sync_authentic_pixels_handler(image,
5025 assert(id < (int) cache_info->number_threads);
5026 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5036 + S y n c I m a g e P i x e l C a c h e %
5040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5042 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5043 % The method returns MagickTrue if the pixel region is flushed, otherwise
5046 % The format of the SyncImagePixelCache() method is:
5048 % MagickBooleanType SyncImagePixelCache(Image *image,
5049 % ExceptionInfo *exception)
5051 % A description of each parameter follows:
5053 % o image: the image.
5055 % o exception: return any errors or warnings in this structure.
5058 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5059 ExceptionInfo *exception)
5064 assert(image != (Image *) NULL);
5065 assert(exception != (ExceptionInfo *) NULL);
5066 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5067 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5075 + W r i t e P i x e l C a c h e M e t a c o n t e n t %
5079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5081 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5082 % of the pixel cache.
5084 % The format of the WritePixelCacheMetacontent() method is:
5086 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5087 % NexusInfo *nexus_info,ExceptionInfo *exception)
5089 % A description of each parameter follows:
5091 % o cache_info: the pixel cache.
5093 % o nexus_info: the cache nexus to write the meta-content.
5095 % o exception: return any errors or warnings in this structure.
5098 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5099 NexusInfo *nexus_info,ExceptionInfo *exception)
5109 register const unsigned char
5118 if (cache_info->metacontent_extent == 0)
5119 return(MagickFalse);
5120 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5122 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5123 nexus_info->region.x;
5124 length=(MagickSizeType) nexus_info->region.width*
5125 cache_info->metacontent_extent;
5126 extent=(MagickSizeType) length*nexus_info->region.height;
5127 rows=nexus_info->region.height;
5129 p=(unsigned char *) nexus_info->metacontent;
5130 switch (cache_info->type)
5135 register unsigned char
5139 Write associated pixels to memory.
5141 if ((cache_info->columns == nexus_info->region.width) &&
5142 (extent == (MagickSizeType) ((size_t) extent)))
5147 q=(unsigned char *) cache_info->metacontent+offset*
5148 cache_info->metacontent_extent;
5149 for (y=0; y < (ssize_t) rows; y++)
5151 (void) memcpy(q,p,(size_t) length);
5152 p+=nexus_info->region.width*cache_info->metacontent_extent;
5153 q+=cache_info->columns*cache_info->metacontent_extent;
5160 Write associated pixels to disk.
5162 LockSemaphoreInfo(cache_info->file_semaphore);
5163 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5165 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5166 cache_info->cache_filename);
5167 UnlockSemaphoreInfo(cache_info->file_semaphore);
5168 return(MagickFalse);
5170 if ((cache_info->columns == nexus_info->region.width) &&
5171 (extent <= MagickMaxBufferExtent))
5176 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5177 for (y=0; y < (ssize_t) rows; y++)
5179 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5180 cache_info->number_channels*sizeof(Quantum)+offset*
5181 cache_info->metacontent_extent,length,(const unsigned char *) p);
5182 if (count != (MagickOffsetType) length)
5184 p+=cache_info->metacontent_extent*nexus_info->region.width;
5185 offset+=cache_info->columns;
5187 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5188 (void) ClosePixelCacheOnDisk(cache_info);
5189 UnlockSemaphoreInfo(cache_info->file_semaphore);
5192 case DistributedCache:
5198 Write metacontent to distributed cache.
5200 LockSemaphoreInfo(cache_info->file_semaphore);
5201 region=nexus_info->region;
5202 if ((cache_info->columns != nexus_info->region.width) ||
5203 (extent > MagickMaxBufferExtent))
5210 for (y=0; y < (ssize_t) rows; y++)
5212 count=WriteDistributePixelCacheMetacontent(cache_info->server_info,
5213 ®ion,length,(const unsigned char *) p);
5214 if (count != (MagickOffsetType) length)
5216 p+=cache_info->metacontent_extent*nexus_info->region.width;
5219 UnlockSemaphoreInfo(cache_info->file_semaphore);
5225 if (y < (ssize_t) rows)
5227 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5228 cache_info->cache_filename);
5229 return(MagickFalse);
5231 if ((cache_info->debug != MagickFalse) &&
5232 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5233 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5234 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5235 nexus_info->region.width,(double) nexus_info->region.height,(double)
5236 nexus_info->region.x,(double) nexus_info->region.y);
5241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5245 + W r i t e C a c h e P i x e l s %
5249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5251 % WritePixelCachePixels() writes image pixels to the specified region of the
5254 % The format of the WritePixelCachePixels() method is:
5256 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5257 % NexusInfo *nexus_info,ExceptionInfo *exception)
5259 % A description of each parameter follows:
5261 % o cache_info: the pixel cache.
5263 % o nexus_info: the cache nexus to write the pixels.
5265 % o exception: return any errors or warnings in this structure.
5268 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5269 NexusInfo *nexus_info,ExceptionInfo *exception)
5279 register const Quantum
5288 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5290 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5291 nexus_info->region.x;
5292 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5294 extent=length*nexus_info->region.height;
5295 rows=nexus_info->region.height;
5297 p=nexus_info->pixels;
5298 switch (cache_info->type)
5307 Write pixels to memory.
5309 if ((cache_info->columns == nexus_info->region.width) &&
5310 (extent == (MagickSizeType) ((size_t) extent)))
5315 q=cache_info->pixels+offset*cache_info->number_channels;
5316 for (y=0; y < (ssize_t) rows; y++)
5318 (void) memcpy(q,p,(size_t) length);
5319 p+=cache_info->number_channels*nexus_info->region.width;
5320 q+=cache_info->columns*cache_info->number_channels;
5327 Write pixels to disk.
5329 LockSemaphoreInfo(cache_info->file_semaphore);
5330 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5332 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5333 cache_info->cache_filename);
5334 UnlockSemaphoreInfo(cache_info->file_semaphore);
5335 return(MagickFalse);
5337 if ((cache_info->columns == nexus_info->region.width) &&
5338 (extent <= MagickMaxBufferExtent))
5343 for (y=0; y < (ssize_t) rows; y++)
5345 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5346 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5348 if (count != (MagickOffsetType) length)
5350 p+=cache_info->number_channels*nexus_info->region.width;
5351 offset+=cache_info->columns;
5353 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5354 (void) ClosePixelCacheOnDisk(cache_info);
5355 UnlockSemaphoreInfo(cache_info->file_semaphore);
5358 case DistributedCache:
5364 Write pixels to distributed cache.
5366 LockSemaphoreInfo(cache_info->file_semaphore);
5367 region=nexus_info->region;
5368 if ((cache_info->columns != nexus_info->region.width) ||
5369 (extent > MagickMaxBufferExtent))
5376 for (y=0; y < (ssize_t) rows; y++)
5378 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5379 length,(const unsigned char *) p);
5380 if (count != (MagickOffsetType) length)
5382 p+=cache_info->number_channels*nexus_info->region.width;
5385 UnlockSemaphoreInfo(cache_info->file_semaphore);
5391 if (y < (ssize_t) rows)
5393 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5394 cache_info->cache_filename);
5395 return(MagickFalse);
5397 if ((cache_info->debug != MagickFalse) &&
5398 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5399 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5400 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5401 nexus_info->region.width,(double) nexus_info->region.height,(double)
5402 nexus_info->region.x,(double) nexus_info->region.y);