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,exception);
1554 if (status != MagickFalse)
1556 if (cache_info->reference_count == 1)
1557 cache_info->nexus_info=(NexusInfo **) NULL;
1559 image->cache=clone_image.cache;
1562 DestroySemaphoreInfo(&clone_image.semaphore);
1564 UnlockSemaphoreInfo(cache_info->semaphore);
1566 if (destroy != MagickFalse)
1567 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1568 if (status != MagickFalse)
1571 Ensure the image matches the pixel cache morphology.
1573 image->taint=MagickTrue;
1574 image->type=UndefinedType;
1575 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1577 status=OpenPixelCache(image,IOMode,exception);
1578 cache_info=(CacheInfo *) image->cache;
1579 if (cache_info->type == DiskCache)
1580 (void) ClosePixelCacheOnDisk(cache_info);
1583 UnlockSemaphoreInfo(image->semaphore);
1584 if (status == MagickFalse)
1585 return((Cache) NULL);
1586 return(image->cache);
1590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594 + G e t I m a g e P i x e l C a c h e T y p e %
1598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1601 % DiskCache, MemoryCache, MapCache, or PingCache.
1603 % The format of the GetImagePixelCacheType() method is:
1605 % CacheType GetImagePixelCacheType(const Image *image)
1607 % A description of each parameter follows:
1609 % o image: the image.
1612 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1617 assert(image != (Image *) NULL);
1618 assert(image->signature == MagickSignature);
1619 assert(image->cache != (Cache) NULL);
1620 cache_info=(CacheInfo *) image->cache;
1621 assert(cache_info->signature == MagickSignature);
1622 return(cache_info->type);
1626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630 % G e t O n e A u t h e n t i c P i x e l %
1634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1637 % location. The image background color is returned if an error occurs.
1639 % The format of the GetOneAuthenticPixel() method is:
1641 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1642 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1644 % A description of each parameter follows:
1646 % o image: the image.
1648 % o x,y: These values define the location of the pixel to return.
1650 % o pixel: return a pixel at the specified (x,y) location.
1652 % o exception: return any errors or warnings in this structure.
1655 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1656 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1667 assert(image != (Image *) NULL);
1668 assert(image->signature == MagickSignature);
1669 assert(image->cache != (Cache) NULL);
1670 cache_info=(CacheInfo *) image->cache;
1671 assert(cache_info->signature == MagickSignature);
1672 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1673 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1674 (GetOneAuthenticPixelFromHandler) NULL)
1675 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1677 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1678 if (q == (Quantum *) NULL)
1680 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1681 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1682 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1683 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1684 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1685 return(MagickFalse);
1687 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1692 channel=GetPixelChannelChannel(image,i);
1693 pixel[channel]=q[i];
1699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703 + 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 %
1707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1709 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1710 % location. The image background color is returned if an error occurs.
1712 % The format of the GetOneAuthenticPixelFromCache() method is:
1714 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1715 % const ssize_t x,const ssize_t y,Quantum *pixel,
1716 % ExceptionInfo *exception)
1718 % A description of each parameter follows:
1720 % o image: the image.
1722 % o x,y: These values define the location of the pixel to return.
1724 % o pixel: return a pixel at the specified (x,y) location.
1726 % o exception: return any errors or warnings in this structure.
1729 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1730 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1736 id = GetOpenMPThreadId();
1744 assert(image != (const Image *) NULL);
1745 assert(image->signature == MagickSignature);
1746 assert(image->cache != (Cache) NULL);
1747 cache_info=(CacheInfo *) image->cache;
1748 assert(cache_info->signature == MagickSignature);
1749 assert(id < (int) cache_info->number_threads);
1750 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1751 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1753 if (q == (Quantum *) NULL)
1755 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1756 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1757 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1758 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1759 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1760 return(MagickFalse);
1762 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1767 channel=GetPixelChannelChannel(image,i);
1768 pixel[channel]=q[i];
1774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1778 % G e t O n e V i r t u a l P i x e l %
1782 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1785 % (x,y) location. The image background color is returned if an error occurs.
1786 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1788 % The format of the GetOneVirtualPixel() method is:
1790 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1791 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1793 % A description of each parameter follows:
1795 % o image: the image.
1797 % o x,y: These values define the location of the pixel to return.
1799 % o pixel: return a pixel at the specified (x,y) location.
1801 % o exception: return any errors or warnings in this structure.
1804 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1805 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1811 id = GetOpenMPThreadId();
1819 assert(image != (const Image *) NULL);
1820 assert(image->signature == MagickSignature);
1821 assert(image->cache != (Cache) NULL);
1822 cache_info=(CacheInfo *) image->cache;
1823 assert(cache_info->signature == MagickSignature);
1824 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1825 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1826 (GetOneVirtualPixelFromHandler) NULL)
1827 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1828 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1829 assert(id < (int) cache_info->number_threads);
1830 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1831 1UL,1UL,cache_info->nexus_info[id],exception);
1832 if (p == (const Quantum *) NULL)
1834 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1835 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1836 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1837 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1838 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1839 return(MagickFalse);
1841 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1846 channel=GetPixelChannelChannel(image,i);
1847 pixel[channel]=p[i];
1853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1857 + 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 %
1861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1864 % specified (x,y) location. The image background color is returned if an
1867 % The format of the GetOneVirtualPixelFromCache() method is:
1869 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1870 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1871 % Quantum *pixel,ExceptionInfo *exception)
1873 % A description of each parameter follows:
1875 % o image: the image.
1877 % o virtual_pixel_method: the virtual pixel method.
1879 % o x,y: These values define the location of the pixel to return.
1881 % o pixel: return a pixel at the specified (x,y) location.
1883 % o exception: return any errors or warnings in this structure.
1886 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1887 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1888 Quantum *pixel,ExceptionInfo *exception)
1894 id = GetOpenMPThreadId();
1902 assert(image != (const Image *) NULL);
1903 assert(image->signature == MagickSignature);
1904 assert(image->cache != (Cache) NULL);
1905 cache_info=(CacheInfo *) image->cache;
1906 assert(cache_info->signature == MagickSignature);
1907 assert(id < (int) cache_info->number_threads);
1908 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1909 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1910 cache_info->nexus_info[id],exception);
1911 if (p == (const Quantum *) NULL)
1913 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1914 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1915 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1916 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1917 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1918 return(MagickFalse);
1920 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1925 channel=GetPixelChannelChannel(image,i);
1926 pixel[channel]=p[i];
1932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1936 % G e t O n e V i r t u a l P i x e l I n f o %
1940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1943 % location. The image background color is returned if an error occurs. If
1944 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1946 % The format of the GetOneVirtualPixelInfo() method is:
1948 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1949 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1950 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1952 % A description of each parameter follows:
1954 % o image: the image.
1956 % o virtual_pixel_method: the virtual pixel method.
1958 % o x,y: these values define the location of the pixel to return.
1960 % o pixel: return a pixel at the specified (x,y) location.
1962 % o exception: return any errors or warnings in this structure.
1965 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1966 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1967 PixelInfo *pixel,ExceptionInfo *exception)
1973 id = GetOpenMPThreadId();
1975 register const Quantum
1978 assert(image != (const Image *) NULL);
1979 assert(image->signature == MagickSignature);
1980 assert(image->cache != (Cache) NULL);
1981 cache_info=(CacheInfo *) image->cache;
1982 assert(cache_info->signature == MagickSignature);
1983 assert(id < (int) cache_info->number_threads);
1984 GetPixelInfo(image,pixel);
1985 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1986 cache_info->nexus_info[id],exception);
1987 if (p == (const Quantum *) NULL)
1988 return(MagickFalse);
1989 GetPixelInfoPixel(image,p,pixel);
1994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1998 + G e t P i x e l C a c h e C o l o r s p a c e %
2002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2004 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2006 % The format of the GetPixelCacheColorspace() method is:
2008 % Colorspace GetPixelCacheColorspace(Cache cache)
2010 % A description of each parameter follows:
2012 % o cache: the pixel cache.
2015 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2020 assert(cache != (Cache) NULL);
2021 cache_info=(CacheInfo *) cache;
2022 assert(cache_info->signature == MagickSignature);
2023 if (cache_info->debug != MagickFalse)
2024 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2025 cache_info->filename);
2026 return(cache_info->colorspace);
2030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2034 + G e t P i x e l C a c h e M e t h o d s %
2038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2040 % GetPixelCacheMethods() initializes the CacheMethods structure.
2042 % The format of the GetPixelCacheMethods() method is:
2044 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2046 % A description of each parameter follows:
2048 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2051 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2053 assert(cache_methods != (CacheMethods *) NULL);
2054 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2055 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2056 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2057 cache_methods->get_virtual_metacontent_from_handler=
2058 GetVirtualMetacontentFromCache;
2059 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2060 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2061 cache_methods->get_authentic_metacontent_from_handler=
2062 GetAuthenticMetacontentFromCache;
2063 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2064 cache_methods->get_one_authentic_pixel_from_handler=
2065 GetOneAuthenticPixelFromCache;
2066 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2067 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2068 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2076 + G e t P i x e l C a c h e N e x u s E x t e n t %
2080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2082 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2083 % corresponding with the last call to SetPixelCacheNexusPixels() or
2084 % GetPixelCacheNexusPixels().
2086 % The format of the GetPixelCacheNexusExtent() method is:
2088 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2089 % NexusInfo *nexus_info)
2091 % A description of each parameter follows:
2093 % o nexus_info: the nexus info.
2096 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2097 NexusInfo *nexus_info)
2105 assert(cache != NULL);
2106 cache_info=(CacheInfo *) cache;
2107 assert(cache_info->signature == MagickSignature);
2108 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2110 return((MagickSizeType) cache_info->columns*cache_info->rows);
2115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2119 + 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 %
2123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2128 % The format of the GetPixelCacheNexusMetacontent() method is:
2130 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2131 % NexusInfo *nexus_info)
2133 % A description of each parameter follows:
2135 % o cache: the pixel cache.
2137 % o nexus_info: the cache nexus to return the meta-content.
2140 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2141 NexusInfo *nexus_info)
2146 assert(cache != NULL);
2147 cache_info=(CacheInfo *) cache;
2148 assert(cache_info->signature == MagickSignature);
2149 if (cache_info->storage_class == UndefinedClass)
2150 return((void *) NULL);
2151 return(nexus_info->metacontent);
2155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2159 + G e t P i x e l C a c h e N e x u s P i x e l s %
2163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2165 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2168 % The format of the GetPixelCacheNexusPixels() method is:
2170 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2171 % NexusInfo *nexus_info)
2173 % A description of each parameter follows:
2175 % o cache: the pixel cache.
2177 % o nexus_info: the cache nexus to return the pixels.
2180 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2181 NexusInfo *nexus_info)
2186 assert(cache != NULL);
2187 cache_info=(CacheInfo *) cache;
2188 assert(cache_info->signature == MagickSignature);
2189 if (cache_info->storage_class == UndefinedClass)
2190 return((Quantum *) NULL);
2191 return(nexus_info->pixels);
2195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2199 + G e t P i x e l C a c h e P i x e l s %
2203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205 % GetPixelCachePixels() returns the pixels associated with the specified image.
2207 % The format of the GetPixelCachePixels() method is:
2209 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2210 % ExceptionInfo *exception)
2212 % A description of each parameter follows:
2214 % o image: the image.
2216 % o length: the pixel cache length.
2218 % o exception: return any errors or warnings in this structure.
2221 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2222 ExceptionInfo *exception)
2227 assert(image != (const Image *) NULL);
2228 assert(image->signature == MagickSignature);
2229 assert(image->cache != (Cache) NULL);
2230 assert(length != (MagickSizeType *) NULL);
2231 assert(exception != (ExceptionInfo *) NULL);
2232 assert(exception->signature == MagickSignature);
2233 cache_info=(CacheInfo *) image->cache;
2234 assert(cache_info->signature == MagickSignature);
2236 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2237 return((void *) NULL);
2238 *length=cache_info->length;
2239 return((void *) cache_info->pixels);
2243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247 + 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 %
2251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2253 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2255 % The format of the GetPixelCacheStorageClass() method is:
2257 % ClassType GetPixelCacheStorageClass(Cache cache)
2259 % A description of each parameter follows:
2261 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2263 % o cache: the pixel cache.
2266 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2271 assert(cache != (Cache) NULL);
2272 cache_info=(CacheInfo *) cache;
2273 assert(cache_info->signature == MagickSignature);
2274 if (cache_info->debug != MagickFalse)
2275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2276 cache_info->filename);
2277 return(cache_info->storage_class);
2281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285 + G e t P i x e l C a c h e T i l e S i z e %
2289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2291 % GetPixelCacheTileSize() returns the pixel cache tile size.
2293 % The format of the GetPixelCacheTileSize() method is:
2295 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2298 % A description of each parameter follows:
2300 % o image: the image.
2302 % o width: the optimize cache tile width in pixels.
2304 % o height: the optimize cache tile height in pixels.
2307 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2313 assert(image != (Image *) NULL);
2314 assert(image->signature == MagickSignature);
2315 if (image->debug != MagickFalse)
2316 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2317 cache_info=(CacheInfo *) image->cache;
2318 assert(cache_info->signature == MagickSignature);
2319 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2320 if (GetImagePixelCacheType(image) == DiskCache)
2321 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2330 + 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 %
2334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2336 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2337 % pixel cache. A virtual pixel is any pixel access that is outside the
2338 % boundaries of the image cache.
2340 % The format of the GetPixelCacheVirtualMethod() method is:
2342 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2344 % A description of each parameter follows:
2346 % o image: the image.
2349 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2354 assert(image != (Image *) NULL);
2355 assert(image->signature == MagickSignature);
2356 assert(image->cache != (Cache) NULL);
2357 cache_info=(CacheInfo *) image->cache;
2358 assert(cache_info->signature == MagickSignature);
2359 return(cache_info->virtual_pixel_method);
2363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367 + 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 %
2371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2373 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2374 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2376 % The format of the GetVirtualMetacontentFromCache() method is:
2378 % void *GetVirtualMetacontentFromCache(const Image *image)
2380 % A description of each parameter follows:
2382 % o image: the image.
2385 static const void *GetVirtualMetacontentFromCache(const Image *image)
2391 id = GetOpenMPThreadId();
2396 assert(image != (const Image *) NULL);
2397 assert(image->signature == MagickSignature);
2398 assert(image->cache != (Cache) NULL);
2399 cache_info=(CacheInfo *) image->cache;
2400 assert(cache_info->signature == MagickSignature);
2401 assert(id < (int) cache_info->number_threads);
2402 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2403 cache_info->nexus_info[id]);
2404 return(metacontent);
2408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412 + 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 %
2416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2418 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2421 % The format of the GetVirtualMetacontentFromNexus() method is:
2423 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2424 % NexusInfo *nexus_info)
2426 % A description of each parameter follows:
2428 % o cache: the pixel cache.
2430 % o nexus_info: the cache nexus to return the meta-content.
2433 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2434 NexusInfo *nexus_info)
2439 assert(cache != (Cache) NULL);
2440 cache_info=(CacheInfo *) cache;
2441 assert(cache_info->signature == MagickSignature);
2442 if (cache_info->storage_class == UndefinedClass)
2443 return((void *) NULL);
2444 return(nexus_info->metacontent);
2448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2452 % G e t V i r t u a l M e t a c o n t e n t %
2456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2458 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2459 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2460 % returned if the meta-content are not available.
2462 % The format of the GetVirtualMetacontent() method is:
2464 % const void *GetVirtualMetacontent(const Image *image)
2466 % A description of each parameter follows:
2468 % o image: the image.
2471 MagickExport const void *GetVirtualMetacontent(const Image *image)
2477 id = GetOpenMPThreadId();
2482 assert(image != (const Image *) NULL);
2483 assert(image->signature == MagickSignature);
2484 assert(image->cache != (Cache) NULL);
2485 cache_info=(CacheInfo *) image->cache;
2486 assert(cache_info->signature == MagickSignature);
2487 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2488 if (metacontent != (void *) NULL)
2489 return(metacontent);
2490 assert(id < (int) cache_info->number_threads);
2491 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2492 cache_info->nexus_info[id]);
2493 return(metacontent);
2497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501 + 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 %
2505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2507 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2508 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2509 % is returned if the pixels are transferred, otherwise a NULL is returned.
2511 % The format of the GetVirtualPixelsFromNexus() method is:
2513 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2514 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2515 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2516 % ExceptionInfo *exception)
2518 % A description of each parameter follows:
2520 % o image: the image.
2522 % o virtual_pixel_method: the virtual pixel method.
2524 % o x,y,columns,rows: These values define the perimeter of a region of
2527 % o nexus_info: the cache nexus to acquire.
2529 % o exception: return any errors or warnings in this structure.
2536 0, 48, 12, 60, 3, 51, 15, 63,
2537 32, 16, 44, 28, 35, 19, 47, 31,
2538 8, 56, 4, 52, 11, 59, 7, 55,
2539 40, 24, 36, 20, 43, 27, 39, 23,
2540 2, 50, 14, 62, 1, 49, 13, 61,
2541 34, 18, 46, 30, 33, 17, 45, 29,
2542 10, 58, 6, 54, 9, 57, 5, 53,
2543 42, 26, 38, 22, 41, 25, 37, 21
2546 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2551 index=x+DitherMatrix[x & 0x07]-32L;
2554 if (index >= (ssize_t) columns)
2555 return((ssize_t) columns-1L);
2559 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2564 index=y+DitherMatrix[y & 0x07]-32L;
2567 if (index >= (ssize_t) rows)
2568 return((ssize_t) rows-1L);
2572 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2576 if (x >= (ssize_t) columns)
2577 return((ssize_t) (columns-1));
2581 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2585 if (y >= (ssize_t) rows)
2586 return((ssize_t) (rows-1));
2590 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2592 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2595 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2597 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2600 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2601 const size_t extent)
2607 Compute the remainder of dividing offset by extent. It returns not only
2608 the quotient (tile the offset falls in) but also the positive remainer
2609 within that tile such that 0 <= remainder < extent. This method is
2610 essentially a ldiv() using a floored modulo division rather than the
2611 normal default truncated modulo division.
2613 modulo.quotient=offset/(ssize_t) extent;
2616 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2620 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2621 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2622 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2623 ExceptionInfo *exception)
2640 virtual_pixel[CompositePixelChannel];
2645 register const Quantum
2658 register unsigned char
2665 *virtual_metacontent;
2670 assert(image != (const Image *) NULL);
2671 assert(image->signature == MagickSignature);
2672 assert(image->cache != (Cache) NULL);
2673 cache_info=(CacheInfo *) image->cache;
2674 assert(cache_info->signature == MagickSignature);
2675 if (cache_info->type == UndefinedCache)
2676 return((const Quantum *) NULL);
2679 region.width=columns;
2681 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2683 if (pixels == (Quantum *) NULL)
2684 return((const Quantum *) NULL);
2686 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2687 nexus_info->region.x;
2688 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2689 nexus_info->region.width-1L;
2690 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2691 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2692 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2693 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2699 Pixel request is inside cache extents.
2701 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2703 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2704 if (status == MagickFalse)
2705 return((const Quantum *) NULL);
2706 if (cache_info->metacontent_extent != 0)
2708 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2709 if (status == MagickFalse)
2710 return((const Quantum *) NULL);
2715 Pixel request is outside cache extents.
2717 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2718 virtual_nexus=AcquirePixelCacheNexus(1);
2719 if (virtual_nexus == (NexusInfo **) NULL)
2721 if (virtual_nexus != (NexusInfo **) NULL)
2722 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2723 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2724 "UnableToGetCacheNexus","`%s'",image->filename);
2725 return((const Quantum *) NULL);
2727 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2728 sizeof(*virtual_pixel));
2729 virtual_metacontent=(void *) NULL;
2730 switch (virtual_pixel_method)
2732 case BackgroundVirtualPixelMethod:
2733 case BlackVirtualPixelMethod:
2734 case GrayVirtualPixelMethod:
2735 case TransparentVirtualPixelMethod:
2736 case MaskVirtualPixelMethod:
2737 case WhiteVirtualPixelMethod:
2738 case EdgeVirtualPixelMethod:
2739 case CheckerTileVirtualPixelMethod:
2740 case HorizontalTileVirtualPixelMethod:
2741 case VerticalTileVirtualPixelMethod:
2743 if (cache_info->metacontent_extent != 0)
2746 Acquire a metacontent buffer.
2748 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2749 cache_info->metacontent_extent);
2750 if (virtual_metacontent == (void *) NULL)
2752 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2753 (void) ThrowMagickException(exception,GetMagickModule(),
2754 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2755 return((const Quantum *) NULL);
2757 (void) ResetMagickMemory(virtual_metacontent,0,
2758 cache_info->metacontent_extent);
2760 switch (virtual_pixel_method)
2762 case BlackVirtualPixelMethod:
2764 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2765 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2766 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2769 case GrayVirtualPixelMethod:
2771 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2772 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2774 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2777 case TransparentVirtualPixelMethod:
2779 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2780 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2781 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2784 case MaskVirtualPixelMethod:
2785 case WhiteVirtualPixelMethod:
2787 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2788 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2789 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2794 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2796 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2798 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2800 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2802 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2812 for (v=0; v < (ssize_t) rows; v++)
2814 for (u=0; u < (ssize_t) columns; u+=length)
2816 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
2817 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
2818 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
2826 Transfer a single pixel.
2828 length=(MagickSizeType) 1;
2829 switch (virtual_pixel_method)
2833 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2834 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
2835 1UL,1UL,*virtual_nexus,exception);
2836 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2839 case RandomVirtualPixelMethod:
2841 if (cache_info->random_info == (RandomInfo *) NULL)
2842 cache_info->random_info=AcquireRandomInfo();
2843 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2844 RandomX(cache_info->random_info,cache_info->columns),
2845 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2846 *virtual_nexus,exception);
2847 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2850 case DitherVirtualPixelMethod:
2852 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2853 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
2854 1UL,1UL,*virtual_nexus,exception);
2855 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2858 case TileVirtualPixelMethod:
2860 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2861 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2862 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2863 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2865 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2868 case MirrorVirtualPixelMethod:
2870 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2871 if ((x_modulo.quotient & 0x01) == 1L)
2872 x_modulo.remainder=(ssize_t) cache_info->columns-
2873 x_modulo.remainder-1L;
2874 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2875 if ((y_modulo.quotient & 0x01) == 1L)
2876 y_modulo.remainder=(ssize_t) cache_info->rows-
2877 y_modulo.remainder-1L;
2878 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2879 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2881 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2884 case HorizontalTileEdgeVirtualPixelMethod:
2886 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2887 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2888 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
2889 *virtual_nexus,exception);
2890 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2893 case VerticalTileEdgeVirtualPixelMethod:
2895 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2896 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2897 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
2898 *virtual_nexus,exception);
2899 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2902 case BackgroundVirtualPixelMethod:
2903 case BlackVirtualPixelMethod:
2904 case GrayVirtualPixelMethod:
2905 case TransparentVirtualPixelMethod:
2906 case MaskVirtualPixelMethod:
2907 case WhiteVirtualPixelMethod:
2910 r=virtual_metacontent;
2913 case EdgeVirtualPixelMethod:
2914 case CheckerTileVirtualPixelMethod:
2916 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2917 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2918 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2921 r=virtual_metacontent;
2924 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2925 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2927 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2930 case HorizontalTileVirtualPixelMethod:
2932 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
2935 r=virtual_metacontent;
2938 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2939 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2940 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2941 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2943 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2946 case VerticalTileVirtualPixelMethod:
2948 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
2951 r=virtual_metacontent;
2954 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2955 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2956 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2957 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2959 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2963 if (p == (const Quantum *) NULL)
2965 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2967 q+=cache_info->number_channels;
2968 if ((s != (void *) NULL) && (r != (const void *) NULL))
2970 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2971 s+=cache_info->metacontent_extent;
2976 Transfer a run of pixels.
2978 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
2979 length,1UL,*virtual_nexus,exception);
2980 if (p == (const Quantum *) NULL)
2982 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2983 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2984 q+=length*cache_info->number_channels;
2985 if ((r != (void *) NULL) && (s != (const void *) NULL))
2987 (void) memcpy(s,r,(size_t) length);
2988 s+=length*cache_info->metacontent_extent;
2995 if (virtual_metacontent != (void *) NULL)
2996 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2997 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006 + G e t V i r t u a l P i x e l C a c h e %
3010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3012 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3013 % cache as defined by the geometry parameters. A pointer to the pixels
3014 % is returned if the pixels are transferred, otherwise a NULL is returned.
3016 % The format of the GetVirtualPixelCache() method is:
3018 % const Quantum *GetVirtualPixelCache(const Image *image,
3019 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3020 % const ssize_t y,const size_t columns,const size_t rows,
3021 % ExceptionInfo *exception)
3023 % A description of each parameter follows:
3025 % o image: the image.
3027 % o virtual_pixel_method: the virtual pixel method.
3029 % o x,y,columns,rows: These values define the perimeter of a region of
3032 % o exception: return any errors or warnings in this structure.
3035 static const Quantum *GetVirtualPixelCache(const Image *image,
3036 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3037 const size_t columns,const size_t rows,ExceptionInfo *exception)
3043 id = GetOpenMPThreadId();
3048 assert(image != (const Image *) NULL);
3049 assert(image->signature == MagickSignature);
3050 assert(image->cache != (Cache) NULL);
3051 cache_info=(CacheInfo *) image->cache;
3052 assert(cache_info->signature == MagickSignature);
3053 assert(id < (int) cache_info->number_threads);
3054 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3055 cache_info->nexus_info[id],exception);
3060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3064 % G e t V i r t u a l P i x e l Q u e u e %
3068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3070 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3071 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3073 % The format of the GetVirtualPixelQueue() method is:
3075 % const Quantum *GetVirtualPixelQueue(const Image image)
3077 % A description of each parameter follows:
3079 % o image: the image.
3082 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3088 id = GetOpenMPThreadId();
3090 assert(image != (const Image *) NULL);
3091 assert(image->signature == MagickSignature);
3092 assert(image->cache != (Cache) NULL);
3093 cache_info=(CacheInfo *) image->cache;
3094 assert(cache_info->signature == MagickSignature);
3095 if (cache_info->methods.get_virtual_pixels_handler !=
3096 (GetVirtualPixelsHandler) NULL)
3097 return(cache_info->methods.get_virtual_pixels_handler(image));
3098 assert(id < (int) cache_info->number_threads);
3099 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3107 % G e t V i r t u a l P i x e l s %
3111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3113 % GetVirtualPixels() returns an immutable pixel region. If the
3114 % region is successfully accessed, a pointer to it is returned, otherwise
3115 % NULL is returned. The returned pointer may point to a temporary working
3116 % copy of the pixels or it may point to the original pixels in memory.
3117 % Performance is maximized if the selected region is part of one row, or one
3118 % or more full rows, since there is opportunity to access the pixels in-place
3119 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3120 % returned pointer must *never* be deallocated by the user.
3122 % Pixels accessed via the returned pointer represent a simple array of type
3123 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3124 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3125 % access the meta-content (of type void) corresponding to the the
3128 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3130 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3131 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3132 % GetCacheViewAuthenticPixels() instead.
3134 % The format of the GetVirtualPixels() method is:
3136 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3137 % const ssize_t y,const size_t columns,const size_t rows,
3138 % ExceptionInfo *exception)
3140 % A description of each parameter follows:
3142 % o image: the image.
3144 % o x,y,columns,rows: These values define the perimeter of a region of
3147 % o exception: return any errors or warnings in this structure.
3150 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3151 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3152 ExceptionInfo *exception)
3158 id = GetOpenMPThreadId();
3163 assert(image != (const Image *) NULL);
3164 assert(image->signature == MagickSignature);
3165 assert(image->cache != (Cache) NULL);
3166 cache_info=(CacheInfo *) image->cache;
3167 assert(cache_info->signature == MagickSignature);
3168 if (cache_info->methods.get_virtual_pixel_handler !=
3169 (GetVirtualPixelHandler) NULL)
3170 return(cache_info->methods.get_virtual_pixel_handler(image,
3171 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3172 assert(id < (int) cache_info->number_threads);
3173 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3174 columns,rows,cache_info->nexus_info[id],exception);
3179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3183 + 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 %
3187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3189 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3190 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3192 % The format of the GetVirtualPixelsCache() method is:
3194 % Quantum *GetVirtualPixelsCache(const Image *image)
3196 % A description of each parameter follows:
3198 % o image: the image.
3201 static const Quantum *GetVirtualPixelsCache(const Image *image)
3207 id = GetOpenMPThreadId();
3209 assert(image != (const Image *) NULL);
3210 assert(image->signature == MagickSignature);
3211 assert(image->cache != (Cache) NULL);
3212 cache_info=(CacheInfo *) image->cache;
3213 assert(cache_info->signature == MagickSignature);
3214 assert(id < (int) cache_info->number_threads);
3215 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3223 + G e t V i r t u a l P i x e l s N e x u s %
3227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3229 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3232 % The format of the GetVirtualPixelsNexus() method is:
3234 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3235 % NexusInfo *nexus_info)
3237 % A description of each parameter follows:
3239 % o cache: the pixel cache.
3241 % o nexus_info: the cache nexus to return the colormap pixels.
3244 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3245 NexusInfo *nexus_info)
3250 assert(cache != (Cache) NULL);
3251 cache_info=(CacheInfo *) cache;
3252 assert(cache_info->signature == MagickSignature);
3253 if (cache_info->storage_class == UndefinedClass)
3254 return((Quantum *) NULL);
3255 return((const Quantum *) nexus_info->pixels);
3259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3263 + O p e n P i x e l C a c h e %
3267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3269 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3270 % dimensions, allocating space for the image pixels and optionally the
3271 % metacontent, and memory mapping the cache if it is disk based. The cache
3272 % nexus array is initialized as well.
3274 % The format of the OpenPixelCache() method is:
3276 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3277 % ExceptionInfo *exception)
3279 % A description of each parameter follows:
3281 % o image: the image.
3283 % o mode: ReadMode, WriteMode, or IOMode.
3285 % o exception: return any errors or warnings in this structure.
3289 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3291 cache_info->mapped=MagickFalse;
3292 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3293 (size_t) cache_info->length));
3294 if (cache_info->pixels == (Quantum *) NULL)
3296 cache_info->mapped=MagickTrue;
3297 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3298 cache_info->length);
3302 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3309 Open pixel cache on disk.
3311 if (cache_info->file != -1)
3312 return(MagickTrue); /* cache already open */
3313 if (*cache_info->cache_filename == '\0')
3314 file=AcquireUniqueFileResource(cache_info->cache_filename);
3320 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3325 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3326 O_BINARY | O_EXCL,S_MODE);
3328 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3334 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3337 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3342 return(MagickFalse);
3343 (void) AcquireMagickResource(FileResource,1);
3344 cache_info->file=file;
3345 cache_info->mode=mode;
3349 static inline MagickOffsetType WritePixelCacheRegion(
3350 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3351 const MagickSizeType length,const unsigned char *restrict buffer)
3353 register MagickOffsetType
3359 #if !defined(MAGICKCORE_HAVE_PWRITE)
3360 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3361 return((MagickOffsetType) -1);
3364 for (i=0; i < (MagickOffsetType) length; i+=count)
3366 #if !defined(MAGICKCORE_HAVE_PWRITE)
3367 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3368 (MagickSizeType) SSIZE_MAX));
3370 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3371 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3383 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3393 cache_info=(CacheInfo *) image->cache;
3394 if (image->debug != MagickFalse)
3397 format[MaxTextExtent],
3398 message[MaxTextExtent];
3400 (void) FormatMagickSize(length,MagickFalse,format);
3401 (void) FormatLocaleString(message,MaxTextExtent,
3402 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3403 cache_info->cache_filename,cache_info->file,format);
3404 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3406 if (length != (MagickSizeType) ((MagickOffsetType) length))
3407 return(MagickFalse);
3408 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3410 return(MagickFalse);
3411 if ((MagickSizeType) offset >= length)
3413 extent=(MagickOffsetType) length-1;
3414 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3415 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3416 if (cache_info->synchronize != MagickFalse)
3421 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3423 return(MagickFalse);
3426 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3429 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3430 ExceptionInfo *exception)
3437 format[MaxTextExtent],
3438 message[MaxTextExtent];
3454 assert(image != (const Image *) NULL);
3455 assert(image->signature == MagickSignature);
3456 assert(image->cache != (Cache) NULL);
3457 if (image->debug != MagickFalse)
3458 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3459 if ((image->columns == 0) || (image->rows == 0))
3460 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3461 cache_info=(CacheInfo *) image->cache;
3462 assert(cache_info->signature == MagickSignature);
3463 source_info=(*cache_info);
3464 source_info.file=(-1);
3465 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3466 image->filename,(double) GetImageIndexInList(image));
3467 cache_info->storage_class=image->storage_class;
3468 cache_info->colorspace=image->colorspace;
3469 cache_info->alpha_trait=image->alpha_trait;
3470 cache_info->mask=image->mask;
3471 cache_info->rows=image->rows;
3472 cache_info->columns=image->columns;
3473 InitializePixelChannelMap(image);
3474 cache_info->number_channels=GetPixelChannels(image);
3475 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3476 sizeof(*image->channel_map));
3477 cache_info->metacontent_extent=image->metacontent_extent;
3478 cache_info->mode=mode;
3479 if (image->ping != MagickFalse)
3481 cache_info->type=PingCache;
3482 cache_info->pixels=(Quantum *) NULL;
3483 cache_info->metacontent=(void *) NULL;
3484 cache_info->length=0;
3487 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3488 packet_size=cache_info->number_channels*sizeof(Quantum);
3489 if (image->metacontent_extent != 0)
3490 packet_size+=cache_info->metacontent_extent;
3491 length=number_pixels*packet_size;
3492 columns=(size_t) (length/cache_info->rows/packet_size);
3493 if (cache_info->columns != columns)
3494 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3496 cache_info->length=length;
3497 status=AcquireMagickResource(AreaResource,cache_info->length);
3498 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3499 cache_info->metacontent_extent);
3500 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3502 status=AcquireMagickResource(MemoryResource,cache_info->length);
3503 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3504 (cache_info->type == MemoryCache))
3506 AllocatePixelCachePixels(cache_info);
3507 if (cache_info->pixels == (Quantum *) NULL)
3508 cache_info->pixels=source_info.pixels;
3512 Create memory pixel cache.
3515 cache_info->type=MemoryCache;
3516 cache_info->metacontent=(void *) NULL;
3517 if (cache_info->metacontent_extent != 0)
3518 cache_info->metacontent=(void *) (cache_info->pixels+
3519 number_pixels*cache_info->number_channels);
3520 if ((source_info.storage_class != UndefinedClass) &&
3523 status=ClonePixelCacheRepository(cache_info,&source_info,
3525 RelinquishPixelCachePixels(&source_info);
3527 if (image->debug != MagickFalse)
3529 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3530 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3532 (void) FormatLocaleString(message,MaxTextExtent,
3533 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3534 cache_info->filename,cache_info->mapped != MagickFalse ?
3535 "Anonymous" : "Heap",type,(double) cache_info->columns,
3536 (double) cache_info->rows,(double)
3537 cache_info->number_channels,format);
3538 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3544 RelinquishMagickResource(MemoryResource,cache_info->length);
3547 Create pixel cache on disk.
3549 status=AcquireMagickResource(DiskResource,cache_info->length);
3550 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3555 if (cache_info->type == DistributedCache)
3556 RelinquishMagickResource(DiskResource,cache_info->length);
3557 server_info=AcquireDistributeCacheInfo(exception);
3558 if (server_info != (DistributeCacheInfo *) NULL)
3560 status=OpenDistributePixelCache(server_info,image);
3561 if (status == MagickFalse)
3563 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3564 GetDistributeCacheHostname(server_info));
3565 server_info=DestroyDistributeCacheInfo(server_info);
3570 Create a distributed pixel cache.
3572 cache_info->type=DistributedCache;
3573 cache_info->server_info=server_info;
3574 (void) FormatLocaleString(cache_info->cache_filename,
3575 MaxTextExtent,"%s:%d",
3576 GetDistributeCacheHostname(cache_info->server_info),
3577 GetDistributeCachePort(cache_info->server_info));
3578 if ((source_info.storage_class != UndefinedClass) &&
3581 status=ClonePixelCacheRepository(cache_info,&source_info,
3583 RelinquishPixelCachePixels(&source_info);
3585 if (image->debug != MagickFalse)
3587 (void) FormatMagickSize(cache_info->length,MagickFalse,
3589 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3591 (void) FormatLocaleString(message,MaxTextExtent,
3592 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3593 cache_info->filename,cache_info->cache_filename,
3594 GetDistributeCacheFile(cache_info->server_info),type,
3595 (double) cache_info->columns,(double) cache_info->rows,
3596 (double) cache_info->number_channels,format);
3597 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3603 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3604 "CacheResourcesExhausted","`%s'",image->filename);
3605 return(MagickFalse);
3607 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3609 (void) ClosePixelCacheOnDisk(cache_info);
3610 *cache_info->cache_filename='\0';
3612 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3614 RelinquishMagickResource(DiskResource,cache_info->length);
3615 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3617 return(MagickFalse);
3619 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3620 cache_info->length);
3621 if (status == MagickFalse)
3623 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3625 return(MagickFalse);
3627 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3628 cache_info->metacontent_extent);
3629 if (length != (MagickSizeType) ((size_t) length))
3630 cache_info->type=DiskCache;
3633 status=AcquireMagickResource(MapResource,cache_info->length);
3634 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3635 (cache_info->type != MemoryCache))
3636 cache_info->type=DiskCache;
3639 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3640 cache_info->offset,(size_t) cache_info->length);
3641 if (cache_info->pixels == (Quantum *) NULL)
3643 cache_info->type=DiskCache;
3644 cache_info->pixels=source_info.pixels;
3649 Create file-backed memory-mapped pixel cache.
3652 (void) ClosePixelCacheOnDisk(cache_info);
3653 cache_info->type=MapCache;
3654 cache_info->mapped=MagickTrue;
3655 cache_info->metacontent=(void *) NULL;
3656 if (cache_info->metacontent_extent != 0)
3657 cache_info->metacontent=(void *) (cache_info->pixels+
3658 number_pixels*cache_info->number_channels);
3659 if ((source_info.storage_class != UndefinedClass) &&
3662 status=ClonePixelCacheRepository(cache_info,&source_info,
3664 RelinquishPixelCachePixels(&source_info);
3666 if (image->debug != MagickFalse)
3668 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3669 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3671 (void) FormatLocaleString(message,MaxTextExtent,
3672 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3673 cache_info->filename,cache_info->cache_filename,
3674 cache_info->file,type,(double) cache_info->columns,(double)
3675 cache_info->rows,(double) cache_info->number_channels,
3677 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3683 RelinquishMagickResource(MapResource,cache_info->length);
3686 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3688 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3689 RelinquishPixelCachePixels(&source_info);
3691 if (image->debug != MagickFalse)
3693 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3694 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3696 (void) FormatLocaleString(message,MaxTextExtent,
3697 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3698 cache_info->cache_filename,cache_info->file,type,(double)
3699 cache_info->columns,(double) cache_info->rows,(double)
3700 cache_info->number_channels,format);
3701 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3711 + P e r s i s t P i x e l C a c h e %
3715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3717 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3718 % persistent pixel cache is one that resides on disk and is not destroyed
3719 % when the program exits.
3721 % The format of the PersistPixelCache() method is:
3723 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3724 % const MagickBooleanType attach,MagickOffsetType *offset,
3725 % ExceptionInfo *exception)
3727 % A description of each parameter follows:
3729 % o image: the image.
3731 % o filename: the persistent pixel cache filename.
3733 % o attach: A value other than zero initializes the persistent pixel cache.
3735 % o initialize: A value other than zero initializes the persistent pixel
3738 % o offset: the offset in the persistent cache to store pixels.
3740 % o exception: return any errors or warnings in this structure.
3743 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3744 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3745 ExceptionInfo *exception)
3760 assert(image != (Image *) NULL);
3761 assert(image->signature == MagickSignature);
3762 if (image->debug != MagickFalse)
3763 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3764 assert(image->cache != (void *) NULL);
3765 assert(filename != (const char *) NULL);
3766 assert(offset != (MagickOffsetType *) NULL);
3767 page_size=GetMagickPageSize();
3768 cache_info=(CacheInfo *) image->cache;
3769 assert(cache_info->signature == MagickSignature);
3770 if (attach != MagickFalse)
3773 Attach existing persistent pixel cache.
3775 if (image->debug != MagickFalse)
3776 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3777 "attach persistent cache");
3778 (void) CopyMagickString(cache_info->cache_filename,filename,
3780 cache_info->type=DiskCache;
3781 cache_info->offset=(*offset);
3782 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3783 return(MagickFalse);
3784 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3787 if ((cache_info->mode != ReadMode) &&
3788 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3789 (cache_info->reference_count == 1))
3791 LockSemaphoreInfo(cache_info->semaphore);
3792 if ((cache_info->mode != ReadMode) &&
3793 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3794 (cache_info->reference_count == 1))
3800 Usurp existing persistent pixel cache.
3802 status=rename_utf8(cache_info->cache_filename,filename);
3805 (void) CopyMagickString(cache_info->cache_filename,filename,
3807 *offset+=cache_info->length+page_size-(cache_info->length %
3809 UnlockSemaphoreInfo(cache_info->semaphore);
3810 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3811 if (image->debug != MagickFalse)
3812 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3813 "Usurp resident persistent cache");
3817 UnlockSemaphoreInfo(cache_info->semaphore);
3820 Clone persistent pixel cache.
3822 clone_image=(*image);
3823 clone_info=(CacheInfo *) clone_image.cache;
3824 image->cache=ClonePixelCache(cache_info);
3825 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3826 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3827 cache_info->type=DiskCache;
3828 cache_info->offset=(*offset);
3829 cache_info=(CacheInfo *) image->cache;
3830 status=OpenPixelCache(image,IOMode,exception);
3831 if (status != MagickFalse)
3832 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3833 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3834 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3843 + 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 %
3847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3849 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3850 % defined by the region rectangle and returns a pointer to the region. This
3851 % region is subsequently transferred from the pixel cache with
3852 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3853 % pixels are transferred, otherwise a NULL is returned.
3855 % The format of the QueueAuthenticPixelCacheNexus() method is:
3857 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3858 % const ssize_t y,const size_t columns,const size_t rows,
3859 % const MagickBooleanType clone,NexusInfo *nexus_info,
3860 % ExceptionInfo *exception)
3862 % A description of each parameter follows:
3864 % o image: the image.
3866 % o x,y,columns,rows: These values define the perimeter of a region of
3869 % o nexus_info: the cache nexus to set.
3871 % o clone: clone the pixel cache.
3873 % o exception: return any errors or warnings in this structure.
3876 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3877 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3878 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3896 Validate pixel cache geometry.
3898 assert(image != (const Image *) NULL);
3899 assert(image->signature == MagickSignature);
3900 assert(image->cache != (Cache) NULL);
3901 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3902 if (cache_info == (Cache) NULL)
3903 return((Quantum *) NULL);
3904 assert(cache_info->signature == MagickSignature);
3905 if ((cache_info->columns == 0) && (cache_info->rows == 0))
3907 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3908 "NoPixelsDefinedInCache","`%s'",image->filename);
3909 return((Quantum *) NULL);
3911 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3912 (y >= (ssize_t) cache_info->rows))
3914 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3915 "PixelsAreNotAuthentic","`%s'",image->filename);
3916 return((Quantum *) NULL);
3918 offset=(MagickOffsetType) y*cache_info->columns+x;
3920 return((Quantum *) NULL);
3921 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3922 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3923 if ((MagickSizeType) offset >= number_pixels)
3924 return((Quantum *) NULL);
3930 region.width=columns;
3932 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3942 + 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 %
3946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3948 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3949 % defined by the region rectangle and returns a pointer to the region. This
3950 % region is subsequently transferred from the pixel cache with
3951 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3952 % pixels are transferred, otherwise a NULL is returned.
3954 % The format of the QueueAuthenticPixelsCache() method is:
3956 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3957 % const ssize_t y,const size_t columns,const size_t rows,
3958 % ExceptionInfo *exception)
3960 % A description of each parameter follows:
3962 % o image: the image.
3964 % o x,y,columns,rows: These values define the perimeter of a region of
3967 % o exception: return any errors or warnings in this structure.
3970 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3971 const ssize_t y,const size_t columns,const size_t rows,
3972 ExceptionInfo *exception)
3978 id = GetOpenMPThreadId();
3983 assert(image != (const Image *) NULL);
3984 assert(image->signature == MagickSignature);
3985 assert(image->cache != (Cache) NULL);
3986 cache_info=(CacheInfo *) image->cache;
3987 assert(cache_info->signature == MagickSignature);
3988 assert(id < (int) cache_info->number_threads);
3989 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3990 cache_info->nexus_info[id],exception);
3995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3999 % Q u e u e A u t h e n t i c P i x e l s %
4003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4005 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4006 % successfully initialized a pointer to a Quantum array representing the
4007 % region is returned, otherwise NULL is returned. The returned pointer may
4008 % point to a temporary working buffer for the pixels or it may point to the
4009 % final location of the pixels in memory.
4011 % Write-only access means that any existing pixel values corresponding to
4012 % the region are ignored. This is useful if the initial image is being
4013 % created from scratch, or if the existing pixel values are to be
4014 % completely replaced without need to refer to their pre-existing values.
4015 % The application is free to read and write the pixel buffer returned by
4016 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4017 % initialize the pixel array values. Initializing pixel array values is the
4018 % application's responsibility.
4020 % Performance is maximized if the selected region is part of one row, or
4021 % one or more full rows, since then there is opportunity to access the
4022 % pixels in-place (without a copy) if the image is in memory, or in a
4023 % memory-mapped file. The returned pointer must *never* be deallocated
4026 % Pixels accessed via the returned pointer represent a simple array of type
4027 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4028 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4029 % obtain the meta-content (of type void) corresponding to the region.
4030 % Once the Quantum (and/or Quantum) array has been updated, the
4031 % changes must be saved back to the underlying image using
4032 % SyncAuthenticPixels() or they may be lost.
4034 % The format of the QueueAuthenticPixels() method is:
4036 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4037 % const ssize_t y,const size_t columns,const size_t rows,
4038 % ExceptionInfo *exception)
4040 % A description of each parameter follows:
4042 % o image: the image.
4044 % o x,y,columns,rows: These values define the perimeter of a region of
4047 % o exception: return any errors or warnings in this structure.
4050 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4051 const ssize_t y,const size_t columns,const size_t rows,
4052 ExceptionInfo *exception)
4058 id = GetOpenMPThreadId();
4063 assert(image != (Image *) NULL);
4064 assert(image->signature == MagickSignature);
4065 assert(image->cache != (Cache) NULL);
4066 cache_info=(CacheInfo *) image->cache;
4067 assert(cache_info->signature == MagickSignature);
4068 if (cache_info->methods.queue_authentic_pixels_handler !=
4069 (QueueAuthenticPixelsHandler) NULL)
4071 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4075 assert(id < (int) cache_info->number_threads);
4076 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4077 cache_info->nexus_info[id],exception);
4082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4086 + 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 %
4090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4092 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4095 % The format of the ReadPixelCacheMetacontent() method is:
4097 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4098 % NexusInfo *nexus_info,ExceptionInfo *exception)
4100 % A description of each parameter follows:
4102 % o cache_info: the pixel cache.
4104 % o nexus_info: the cache nexus to read the metacontent.
4106 % o exception: return any errors or warnings in this structure.
4110 static inline MagickOffsetType ReadPixelCacheRegion(
4111 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4112 const MagickSizeType length,unsigned char *restrict buffer)
4114 register MagickOffsetType
4120 #if !defined(MAGICKCORE_HAVE_PREAD)
4121 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4122 return((MagickOffsetType) -1);
4125 for (i=0; i < (MagickOffsetType) length; i+=count)
4127 #if !defined(MAGICKCORE_HAVE_PREAD)
4128 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4129 (MagickSizeType) SSIZE_MAX));
4131 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4132 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4144 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4145 NexusInfo *nexus_info,ExceptionInfo *exception)
4158 register unsigned char
4164 if (cache_info->metacontent_extent == 0)
4165 return(MagickFalse);
4166 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4168 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4169 nexus_info->region.x;
4170 length=(MagickSizeType) nexus_info->region.width*
4171 cache_info->metacontent_extent;
4172 extent=length*nexus_info->region.height;
4173 rows=nexus_info->region.height;
4175 q=(unsigned char *) nexus_info->metacontent;
4176 switch (cache_info->type)
4181 register unsigned char
4185 Read meta-content from memory.
4187 if ((cache_info->columns == nexus_info->region.width) &&
4188 (extent == (MagickSizeType) ((size_t) extent)))
4193 p=(unsigned char *) cache_info->metacontent+offset*
4194 cache_info->metacontent_extent;
4195 for (y=0; y < (ssize_t) rows; y++)
4197 (void) memcpy(q,p,(size_t) length);
4198 p+=cache_info->metacontent_extent*cache_info->columns;
4199 q+=cache_info->metacontent_extent*nexus_info->region.width;
4206 Read meta content from disk.
4208 LockSemaphoreInfo(cache_info->file_semaphore);
4209 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4211 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4212 cache_info->cache_filename);
4213 UnlockSemaphoreInfo(cache_info->file_semaphore);
4214 return(MagickFalse);
4216 if ((cache_info->columns == nexus_info->region.width) &&
4217 (extent <= MagickMaxBufferExtent))
4222 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4223 for (y=0; y < (ssize_t) rows; y++)
4225 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4226 cache_info->number_channels*sizeof(Quantum)+offset*
4227 cache_info->metacontent_extent,length,(unsigned char *) q);
4228 if (count != (MagickOffsetType) length)
4230 offset+=cache_info->columns;
4231 q+=cache_info->metacontent_extent*nexus_info->region.width;
4233 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4234 (void) ClosePixelCacheOnDisk(cache_info);
4235 UnlockSemaphoreInfo(cache_info->file_semaphore);
4238 case DistributedCache:
4244 Read metacontent from distributed cache.
4246 LockSemaphoreInfo(cache_info->file_semaphore);
4247 region=nexus_info->region;
4248 if ((cache_info->columns != nexus_info->region.width) ||
4249 (extent > MagickMaxBufferExtent))
4256 for (y=0; y < (ssize_t) rows; y++)
4258 count=ReadDistributePixelCacheMetacontent(cache_info->server_info,
4259 ®ion,length,(unsigned char *) q);
4260 if (count != (MagickOffsetType) length)
4262 q+=cache_info->metacontent_extent*nexus_info->region.width;
4265 UnlockSemaphoreInfo(cache_info->file_semaphore);
4271 if (y < (ssize_t) rows)
4273 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4274 cache_info->cache_filename);
4275 return(MagickFalse);
4277 if ((cache_info->debug != MagickFalse) &&
4278 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4279 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4280 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4281 nexus_info->region.width,(double) nexus_info->region.height,(double)
4282 nexus_info->region.x,(double) nexus_info->region.y);
4287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4291 + R e a d P i x e l C a c h e P i x e l s %
4295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4297 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4300 % The format of the ReadPixelCachePixels() method is:
4302 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4303 % NexusInfo *nexus_info,ExceptionInfo *exception)
4305 % A description of each parameter follows:
4307 % o cache_info: the pixel cache.
4309 % o nexus_info: the cache nexus to read the pixels.
4311 % o exception: return any errors or warnings in this structure.
4314 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4315 NexusInfo *nexus_info,ExceptionInfo *exception)
4334 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4336 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4337 nexus_info->region.x;
4338 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4340 extent=length*nexus_info->region.height;
4341 rows=nexus_info->region.height;
4343 q=nexus_info->pixels;
4344 switch (cache_info->type)
4353 Read pixels from memory.
4355 if ((cache_info->columns == nexus_info->region.width) &&
4356 (extent == (MagickSizeType) ((size_t) extent)))
4361 p=cache_info->pixels+offset*cache_info->number_channels;
4362 for (y=0; y < (ssize_t) rows; y++)
4364 (void) memcpy(q,p,(size_t) length);
4365 p+=cache_info->number_channels*cache_info->columns;
4366 q+=cache_info->number_channels*nexus_info->region.width;
4373 Read pixels from disk.
4375 LockSemaphoreInfo(cache_info->file_semaphore);
4376 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4378 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4379 cache_info->cache_filename);
4380 UnlockSemaphoreInfo(cache_info->file_semaphore);
4381 return(MagickFalse);
4383 if ((cache_info->columns == nexus_info->region.width) &&
4384 (extent <= MagickMaxBufferExtent))
4389 for (y=0; y < (ssize_t) rows; y++)
4391 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4392 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4393 if (count != (MagickOffsetType) length)
4395 offset+=cache_info->columns;
4396 q+=cache_info->number_channels*nexus_info->region.width;
4398 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4399 (void) ClosePixelCacheOnDisk(cache_info);
4400 UnlockSemaphoreInfo(cache_info->file_semaphore);
4403 case DistributedCache:
4409 Read pixels from distributed cache.
4411 LockSemaphoreInfo(cache_info->file_semaphore);
4412 region=nexus_info->region;
4413 if ((cache_info->columns != nexus_info->region.width) ||
4414 (extent > MagickMaxBufferExtent))
4421 for (y=0; y < (ssize_t) rows; y++)
4423 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4424 length,(unsigned char *) q);
4425 if (count != (MagickOffsetType) length)
4427 q+=cache_info->number_channels*nexus_info->region.width;
4430 UnlockSemaphoreInfo(cache_info->file_semaphore);
4436 if (y < (ssize_t) rows)
4438 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4439 cache_info->cache_filename);
4440 return(MagickFalse);
4442 if ((cache_info->debug != MagickFalse) &&
4443 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4444 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4445 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4446 nexus_info->region.width,(double) nexus_info->region.height,(double)
4447 nexus_info->region.x,(double) nexus_info->region.y);
4452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4456 + R e f e r e n c e P i x e l C a c h e %
4460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4462 % ReferencePixelCache() increments the reference count associated with the
4463 % pixel cache returning a pointer to the cache.
4465 % The format of the ReferencePixelCache method is:
4467 % Cache ReferencePixelCache(Cache cache_info)
4469 % A description of each parameter follows:
4471 % o cache_info: the pixel cache.
4474 MagickPrivate Cache ReferencePixelCache(Cache cache)
4479 assert(cache != (Cache *) NULL);
4480 cache_info=(CacheInfo *) cache;
4481 assert(cache_info->signature == MagickSignature);
4482 LockSemaphoreInfo(cache_info->semaphore);
4483 cache_info->reference_count++;
4484 UnlockSemaphoreInfo(cache_info->semaphore);
4489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493 + S e t P i x e l C a c h e M e t h o d s %
4497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4499 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4501 % The format of the SetPixelCacheMethods() method is:
4503 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4505 % A description of each parameter follows:
4507 % o cache: the pixel cache.
4509 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4512 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4517 GetOneAuthenticPixelFromHandler
4518 get_one_authentic_pixel_from_handler;
4520 GetOneVirtualPixelFromHandler
4521 get_one_virtual_pixel_from_handler;
4524 Set cache pixel methods.
4526 assert(cache != (Cache) NULL);
4527 assert(cache_methods != (CacheMethods *) NULL);
4528 cache_info=(CacheInfo *) cache;
4529 assert(cache_info->signature == MagickSignature);
4530 if (cache_info->debug != MagickFalse)
4531 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4532 cache_info->filename);
4533 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4534 cache_info->methods.get_virtual_pixel_handler=
4535 cache_methods->get_virtual_pixel_handler;
4536 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4537 cache_info->methods.destroy_pixel_handler=
4538 cache_methods->destroy_pixel_handler;
4539 if (cache_methods->get_virtual_metacontent_from_handler !=
4540 (GetVirtualMetacontentFromHandler) NULL)
4541 cache_info->methods.get_virtual_metacontent_from_handler=
4542 cache_methods->get_virtual_metacontent_from_handler;
4543 if (cache_methods->get_authentic_pixels_handler !=
4544 (GetAuthenticPixelsHandler) NULL)
4545 cache_info->methods.get_authentic_pixels_handler=
4546 cache_methods->get_authentic_pixels_handler;
4547 if (cache_methods->queue_authentic_pixels_handler !=
4548 (QueueAuthenticPixelsHandler) NULL)
4549 cache_info->methods.queue_authentic_pixels_handler=
4550 cache_methods->queue_authentic_pixels_handler;
4551 if (cache_methods->sync_authentic_pixels_handler !=
4552 (SyncAuthenticPixelsHandler) NULL)
4553 cache_info->methods.sync_authentic_pixels_handler=
4554 cache_methods->sync_authentic_pixels_handler;
4555 if (cache_methods->get_authentic_pixels_from_handler !=
4556 (GetAuthenticPixelsFromHandler) NULL)
4557 cache_info->methods.get_authentic_pixels_from_handler=
4558 cache_methods->get_authentic_pixels_from_handler;
4559 if (cache_methods->get_authentic_metacontent_from_handler !=
4560 (GetAuthenticMetacontentFromHandler) NULL)
4561 cache_info->methods.get_authentic_metacontent_from_handler=
4562 cache_methods->get_authentic_metacontent_from_handler;
4563 get_one_virtual_pixel_from_handler=
4564 cache_info->methods.get_one_virtual_pixel_from_handler;
4565 if (get_one_virtual_pixel_from_handler !=
4566 (GetOneVirtualPixelFromHandler) NULL)
4567 cache_info->methods.get_one_virtual_pixel_from_handler=
4568 cache_methods->get_one_virtual_pixel_from_handler;
4569 get_one_authentic_pixel_from_handler=
4570 cache_methods->get_one_authentic_pixel_from_handler;
4571 if (get_one_authentic_pixel_from_handler !=
4572 (GetOneAuthenticPixelFromHandler) NULL)
4573 cache_info->methods.get_one_authentic_pixel_from_handler=
4574 cache_methods->get_one_authentic_pixel_from_handler;
4578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4582 + S e t P i x e l C a c h e N e x u s P i x e l s %
4586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4588 % SetPixelCacheNexusPixels() defines the region of the cache for the
4589 % specified cache nexus.
4591 % The format of the SetPixelCacheNexusPixels() method is:
4593 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4594 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4595 % ExceptionInfo *exception)
4597 % A description of each parameter follows:
4599 % o cache_info: the pixel cache.
4601 % o mode: ReadMode, WriteMode, or IOMode.
4603 % o region: A pointer to the RectangleInfo structure that defines the
4604 % region of this particular cache nexus.
4606 % o nexus_info: the cache nexus to set.
4608 % o exception: return any errors or warnings in this structure.
4612 static inline MagickBooleanType AcquireCacheNexusPixels(
4613 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4614 ExceptionInfo *exception)
4616 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4617 return(MagickFalse);
4618 nexus_info->mapped=MagickFalse;
4619 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4620 (size_t) nexus_info->length));
4621 if (nexus_info->cache == (Quantum *) NULL)
4623 nexus_info->mapped=MagickTrue;
4624 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4625 nexus_info->length);
4627 if (nexus_info->cache == (Quantum *) NULL)
4629 (void) ThrowMagickException(exception,GetMagickModule(),
4630 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4631 cache_info->filename);
4632 return(MagickFalse);
4637 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4640 if (mode == ReadMode)
4642 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4645 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4648 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4649 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4650 ExceptionInfo *exception)
4659 assert(cache_info != (const CacheInfo *) NULL);
4660 assert(cache_info->signature == MagickSignature);
4661 if (cache_info->type == UndefinedCache)
4662 return((Quantum *) NULL);
4663 nexus_info->region=(*region);
4664 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4670 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4671 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4672 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4673 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4674 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4675 ((nexus_info->region.width == cache_info->columns) ||
4676 ((nexus_info->region.width % cache_info->columns) == 0)))))
4682 Pixels are accessed directly from memory.
4684 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4685 nexus_info->region.x;
4686 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4688 nexus_info->metacontent=(void *) NULL;
4689 if (cache_info->metacontent_extent != 0)
4690 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4691 offset*cache_info->metacontent_extent;
4692 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4693 return(nexus_info->pixels);
4697 Pixels are stored in a cache region until they are synced to the cache.
4699 number_pixels=(MagickSizeType) nexus_info->region.width*
4700 nexus_info->region.height;
4701 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4702 if (cache_info->metacontent_extent != 0)
4703 length+=number_pixels*cache_info->metacontent_extent;
4704 if (nexus_info->cache == (Quantum *) NULL)
4706 nexus_info->length=length;
4707 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4708 if (status == MagickFalse)
4710 nexus_info->length=0;
4711 return((Quantum *) NULL);
4715 if (nexus_info->length != length)
4717 RelinquishCacheNexusPixels(nexus_info);
4718 nexus_info->length=length;
4719 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4720 if (status == MagickFalse)
4722 nexus_info->length=0;
4723 return((Quantum *) NULL);
4726 nexus_info->pixels=nexus_info->cache;
4727 nexus_info->metacontent=(void *) NULL;
4728 if (cache_info->metacontent_extent != 0)
4729 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4730 cache_info->number_channels);
4731 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4732 return(nexus_info->pixels);
4736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4740 % 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 %
4744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4746 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4747 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4748 % access that is outside the boundaries of the image cache.
4750 % The format of the SetPixelCacheVirtualMethod() method is:
4752 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4753 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4755 % A description of each parameter follows:
4757 % o image: the image.
4759 % o virtual_pixel_method: choose the type of virtual pixel.
4761 % o exception: return any errors or warnings in this structure.
4765 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4766 ExceptionInfo *exception)
4780 assert(image != (Image *) NULL);
4781 assert(image->signature == MagickSignature);
4782 if (image->debug != MagickFalse)
4783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4784 assert(image->cache != (Cache) NULL);
4785 cache_info=(CacheInfo *) image->cache;
4786 assert(cache_info->signature == MagickSignature);
4787 image->alpha_trait=BlendPixelTrait;
4789 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4790 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4791 #pragma omp parallel for schedule(static,4) shared(status) \
4792 magick_threads(image,image,1,1)
4794 for (y=0; y < (ssize_t) image->rows; y++)
4802 if (status == MagickFalse)
4804 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4805 if (q == (Quantum *) NULL)
4810 for (x=0; x < (ssize_t) image->columns; x++)
4812 SetPixelAlpha(image,alpha,q);
4813 q+=GetPixelChannels(image);
4815 status=SyncCacheViewAuthenticPixels(image_view,exception);
4817 image_view=DestroyCacheView(image_view);
4821 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4822 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4830 assert(image != (Image *) NULL);
4831 assert(image->signature == MagickSignature);
4832 if (image->debug != MagickFalse)
4833 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4834 assert(image->cache != (Cache) NULL);
4835 cache_info=(CacheInfo *) image->cache;
4836 assert(cache_info->signature == MagickSignature);
4837 method=cache_info->virtual_pixel_method;
4838 cache_info->virtual_pixel_method=virtual_pixel_method;
4839 if ((image->columns != 0) && (image->rows != 0))
4840 switch (virtual_pixel_method)
4842 case BackgroundVirtualPixelMethod:
4844 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4845 (image->alpha_trait != BlendPixelTrait))
4846 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4847 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4848 (IsGrayColorspace(image->colorspace) != MagickFalse))
4849 (void) TransformImageColorspace(image,RGBColorspace,exception);
4852 case TransparentVirtualPixelMethod:
4854 if (image->alpha_trait != BlendPixelTrait)
4855 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4869 + 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 %
4873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4875 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4876 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4877 % is synced, otherwise MagickFalse.
4879 % The format of the SyncAuthenticPixelCacheNexus() method is:
4881 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4882 % NexusInfo *nexus_info,ExceptionInfo *exception)
4884 % A description of each parameter follows:
4886 % o image: the image.
4888 % o nexus_info: the cache nexus to sync.
4890 % o exception: return any errors or warnings in this structure.
4893 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4894 NexusInfo *nexus_info,ExceptionInfo *exception)
4903 Transfer pixels to the cache.
4905 assert(image != (Image *) NULL);
4906 assert(image->signature == MagickSignature);
4907 if (image->cache == (Cache) NULL)
4908 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4909 cache_info=(CacheInfo *) image->cache;
4910 assert(cache_info->signature == MagickSignature);
4911 if (cache_info->type == UndefinedCache)
4912 return(MagickFalse);
4913 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4915 assert(cache_info->signature == MagickSignature);
4916 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4917 if ((cache_info->metacontent_extent != 0) &&
4918 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4919 return(MagickFalse);
4924 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4928 + S y n c A u t h e n t i c P i x e l C a c h e %
4932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4934 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4935 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4936 % otherwise MagickFalse.
4938 % The format of the SyncAuthenticPixelsCache() method is:
4940 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4941 % ExceptionInfo *exception)
4943 % A description of each parameter follows:
4945 % o image: the image.
4947 % o exception: return any errors or warnings in this structure.
4950 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4951 ExceptionInfo *exception)
4957 id = GetOpenMPThreadId();
4962 assert(image != (Image *) NULL);
4963 assert(image->signature == MagickSignature);
4964 assert(image->cache != (Cache) NULL);
4965 cache_info=(CacheInfo *) image->cache;
4966 assert(cache_info->signature == MagickSignature);
4967 assert(id < (int) cache_info->number_threads);
4968 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4978 % S y n c A u t h e n t i c P i x e l s %
4982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4984 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4985 % The method returns MagickTrue if the pixel region is flushed, otherwise
4988 % The format of the SyncAuthenticPixels() method is:
4990 % MagickBooleanType SyncAuthenticPixels(Image *image,
4991 % ExceptionInfo *exception)
4993 % A description of each parameter follows:
4995 % o image: the image.
4997 % o exception: return any errors or warnings in this structure.
5000 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5001 ExceptionInfo *exception)
5007 id = GetOpenMPThreadId();
5012 assert(image != (Image *) NULL);
5013 assert(image->signature == MagickSignature);
5014 assert(image->cache != (Cache) NULL);
5015 cache_info=(CacheInfo *) image->cache;
5016 assert(cache_info->signature == MagickSignature);
5017 if (cache_info->methods.sync_authentic_pixels_handler !=
5018 (SyncAuthenticPixelsHandler) NULL)
5020 status=cache_info->methods.sync_authentic_pixels_handler(image,
5024 assert(id < (int) cache_info->number_threads);
5025 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5035 + S y n c I m a g e P i x e l C a c h e %
5039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5041 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5042 % The method returns MagickTrue if the pixel region is flushed, otherwise
5045 % The format of the SyncImagePixelCache() method is:
5047 % MagickBooleanType SyncImagePixelCache(Image *image,
5048 % ExceptionInfo *exception)
5050 % A description of each parameter follows:
5052 % o image: the image.
5054 % o exception: return any errors or warnings in this structure.
5057 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5058 ExceptionInfo *exception)
5063 assert(image != (Image *) NULL);
5064 assert(exception != (ExceptionInfo *) NULL);
5065 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5066 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5074 + 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 %
5078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5080 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5081 % of the pixel cache.
5083 % The format of the WritePixelCacheMetacontent() method is:
5085 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5086 % NexusInfo *nexus_info,ExceptionInfo *exception)
5088 % A description of each parameter follows:
5090 % o cache_info: the pixel cache.
5092 % o nexus_info: the cache nexus to write the meta-content.
5094 % o exception: return any errors or warnings in this structure.
5097 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5098 NexusInfo *nexus_info,ExceptionInfo *exception)
5108 register const unsigned char
5117 if (cache_info->metacontent_extent == 0)
5118 return(MagickFalse);
5119 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5121 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5122 nexus_info->region.x;
5123 length=(MagickSizeType) nexus_info->region.width*
5124 cache_info->metacontent_extent;
5125 extent=(MagickSizeType) length*nexus_info->region.height;
5126 rows=nexus_info->region.height;
5128 p=(unsigned char *) nexus_info->metacontent;
5129 switch (cache_info->type)
5134 register unsigned char
5138 Write associated pixels to memory.
5140 if ((cache_info->columns == nexus_info->region.width) &&
5141 (extent == (MagickSizeType) ((size_t) extent)))
5146 q=(unsigned char *) cache_info->metacontent+offset*
5147 cache_info->metacontent_extent;
5148 for (y=0; y < (ssize_t) rows; y++)
5150 (void) memcpy(q,p,(size_t) length);
5151 p+=nexus_info->region.width*cache_info->metacontent_extent;
5152 q+=cache_info->columns*cache_info->metacontent_extent;
5159 Write associated pixels to disk.
5161 LockSemaphoreInfo(cache_info->file_semaphore);
5162 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5164 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5165 cache_info->cache_filename);
5166 UnlockSemaphoreInfo(cache_info->file_semaphore);
5167 return(MagickFalse);
5169 if ((cache_info->columns == nexus_info->region.width) &&
5170 (extent <= MagickMaxBufferExtent))
5175 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5176 for (y=0; y < (ssize_t) rows; y++)
5178 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5179 cache_info->number_channels*sizeof(Quantum)+offset*
5180 cache_info->metacontent_extent,length,(const unsigned char *) p);
5181 if (count != (MagickOffsetType) length)
5183 p+=cache_info->metacontent_extent*nexus_info->region.width;
5184 offset+=cache_info->columns;
5186 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5187 (void) ClosePixelCacheOnDisk(cache_info);
5188 UnlockSemaphoreInfo(cache_info->file_semaphore);
5191 case DistributedCache:
5197 Write metacontent to distributed cache.
5199 LockSemaphoreInfo(cache_info->file_semaphore);
5200 region=nexus_info->region;
5201 if ((cache_info->columns != nexus_info->region.width) ||
5202 (extent > MagickMaxBufferExtent))
5209 for (y=0; y < (ssize_t) rows; y++)
5211 count=WriteDistributePixelCacheMetacontent(cache_info->server_info,
5212 ®ion,length,(const unsigned char *) p);
5213 if (count != (MagickOffsetType) length)
5215 p+=cache_info->metacontent_extent*nexus_info->region.width;
5218 UnlockSemaphoreInfo(cache_info->file_semaphore);
5224 if (y < (ssize_t) rows)
5226 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5227 cache_info->cache_filename);
5228 return(MagickFalse);
5230 if ((cache_info->debug != MagickFalse) &&
5231 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5232 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5233 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5234 nexus_info->region.width,(double) nexus_info->region.height,(double)
5235 nexus_info->region.x,(double) nexus_info->region.y);
5240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5244 + W r i t e C a c h e P i x e l s %
5248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5250 % WritePixelCachePixels() writes image pixels to the specified region of the
5253 % The format of the WritePixelCachePixels() method is:
5255 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5256 % NexusInfo *nexus_info,ExceptionInfo *exception)
5258 % A description of each parameter follows:
5260 % o cache_info: the pixel cache.
5262 % o nexus_info: the cache nexus to write the pixels.
5264 % o exception: return any errors or warnings in this structure.
5267 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5268 NexusInfo *nexus_info,ExceptionInfo *exception)
5278 register const Quantum
5287 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5289 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5290 nexus_info->region.x;
5291 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5293 extent=length*nexus_info->region.height;
5294 rows=nexus_info->region.height;
5296 p=nexus_info->pixels;
5297 switch (cache_info->type)
5306 Write pixels to memory.
5308 if ((cache_info->columns == nexus_info->region.width) &&
5309 (extent == (MagickSizeType) ((size_t) extent)))
5314 q=cache_info->pixels+offset*cache_info->number_channels;
5315 for (y=0; y < (ssize_t) rows; y++)
5317 (void) memcpy(q,p,(size_t) length);
5318 p+=cache_info->number_channels*nexus_info->region.width;
5319 q+=cache_info->columns*cache_info->number_channels;
5326 Write pixels to disk.
5328 LockSemaphoreInfo(cache_info->file_semaphore);
5329 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5331 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5332 cache_info->cache_filename);
5333 UnlockSemaphoreInfo(cache_info->file_semaphore);
5334 return(MagickFalse);
5336 if ((cache_info->columns == nexus_info->region.width) &&
5337 (extent <= MagickMaxBufferExtent))
5342 for (y=0; y < (ssize_t) rows; y++)
5344 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5345 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5347 if (count != (MagickOffsetType) length)
5349 p+=cache_info->number_channels*nexus_info->region.width;
5350 offset+=cache_info->columns;
5352 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5353 (void) ClosePixelCacheOnDisk(cache_info);
5354 UnlockSemaphoreInfo(cache_info->file_semaphore);
5357 case DistributedCache:
5363 Write pixels to distributed cache.
5365 LockSemaphoreInfo(cache_info->file_semaphore);
5366 region=nexus_info->region;
5367 if ((cache_info->columns != nexus_info->region.width) ||
5368 (extent > MagickMaxBufferExtent))
5375 for (y=0; y < (ssize_t) rows; y++)
5377 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5378 length,(const unsigned char *) p);
5379 if (count != (MagickOffsetType) length)
5381 p+=cache_info->number_channels*nexus_info->region.width;
5384 UnlockSemaphoreInfo(cache_info->file_semaphore);
5390 if (y < (ssize_t) rows)
5392 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5393 cache_info->cache_filename);
5394 return(MagickFalse);
5396 if ((cache_info->debug != MagickFalse) &&
5397 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5398 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5399 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5400 nexus_info->region.width,(double) nexus_info->region.height,(double)
5401 nexus_info->region.x,(double) nexus_info->region.y);