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 != 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((DistributeCacheInfo *)
862 cache_info->server_info);
868 cache_info->type=UndefinedCache;
869 cache_info->mapped=MagickFalse;
870 cache_info->metacontent=(void *) NULL;
873 MagickPrivate Cache DestroyPixelCache(Cache cache)
878 assert(cache != (Cache) NULL);
879 cache_info=(CacheInfo *) cache;
880 assert(cache_info->signature == MagickSignature);
881 if (cache_info->debug != MagickFalse)
882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
883 cache_info->filename);
884 LockSemaphoreInfo(cache_info->semaphore);
885 cache_info->reference_count--;
886 if (cache_info->reference_count != 0)
888 UnlockSemaphoreInfo(cache_info->semaphore);
889 return((Cache) NULL);
891 UnlockSemaphoreInfo(cache_info->semaphore);
892 if (cache_info->debug != MagickFalse)
895 message[MaxTextExtent];
897 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
898 cache_info->filename);
899 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
901 RelinquishPixelCachePixels(cache_info);
902 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
903 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
904 cache_info->server_info);
905 if (cache_info->nexus_info != (NexusInfo **) NULL)
906 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
907 cache_info->number_threads);
908 if (cache_info->random_info != (RandomInfo *) NULL)
909 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
910 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
911 DestroySemaphoreInfo(&cache_info->file_semaphore);
912 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
913 DestroySemaphoreInfo(&cache_info->semaphore);
914 cache_info->signature=(~MagickSignature);
915 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
925 + D e s t r o y P i x e l C a c h e N e x u s %
929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
933 % The format of the DestroyPixelCacheNexus() method is:
935 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
936 % const size_t number_threads)
938 % A description of each parameter follows:
940 % o nexus_info: the nexus to destroy.
942 % o number_threads: the number of nexus threads.
946 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
948 if (nexus_info->mapped == MagickFalse)
949 (void) RelinquishAlignedMemory(nexus_info->cache);
951 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
952 nexus_info->cache=(Quantum *) NULL;
953 nexus_info->pixels=(Quantum *) NULL;
954 nexus_info->metacontent=(void *) NULL;
955 nexus_info->length=0;
956 nexus_info->mapped=MagickFalse;
959 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
960 const size_t number_threads)
965 assert(nexus_info != (NexusInfo **) NULL);
966 for (i=0; i < (ssize_t) number_threads; i++)
968 if (nexus_info[i]->cache != (Quantum *) NULL)
969 RelinquishCacheNexusPixels(nexus_info[i]);
970 nexus_info[i]->signature=(~MagickSignature);
972 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
973 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 % G e t A u t h e n t i c M e t a c o n t e n t %
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
989 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
990 % returned if the associated pixels are not available.
992 % The format of the GetAuthenticMetacontent() method is:
994 % void *GetAuthenticMetacontent(const Image *image)
996 % A description of each parameter follows:
998 % o image: the image.
1001 MagickExport void *GetAuthenticMetacontent(const Image *image)
1007 id = GetOpenMPThreadId();
1012 assert(image != (const Image *) NULL);
1013 assert(image->signature == MagickSignature);
1014 assert(image->cache != (Cache) NULL);
1015 cache_info=(CacheInfo *) image->cache;
1016 assert(cache_info->signature == MagickSignature);
1017 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1018 (GetAuthenticMetacontentFromHandler) NULL)
1020 metacontent=cache_info->methods.
1021 get_authentic_metacontent_from_handler(image);
1022 return(metacontent);
1024 assert(id < (int) cache_info->number_threads);
1025 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1026 cache_info->nexus_info[id]);
1027 return(metacontent);
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 + 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 %
1039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1042 % with the last call to QueueAuthenticPixelsCache() or
1043 % GetAuthenticPixelsCache().
1045 % The format of the GetAuthenticMetacontentFromCache() method is:
1047 % void *GetAuthenticMetacontentFromCache(const Image *image)
1049 % A description of each parameter follows:
1051 % o image: the image.
1054 static void *GetAuthenticMetacontentFromCache(const Image *image)
1060 id = GetOpenMPThreadId();
1065 assert(image != (const Image *) NULL);
1066 assert(image->signature == MagickSignature);
1067 assert(image->cache != (Cache) NULL);
1068 cache_info=(CacheInfo *) image->cache;
1069 assert(cache_info->signature == MagickSignature);
1070 assert(id < (int) cache_info->number_threads);
1071 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1072 cache_info->nexus_info[id]);
1073 return(metacontent);
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 + 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 %
1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1088 % disk pixel cache as defined by the geometry parameters. A pointer to the
1089 % pixels is returned if the pixels are transferred, otherwise a NULL is
1092 % The format of the GetAuthenticPixelCacheNexus() method is:
1094 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1095 % const ssize_t y,const size_t columns,const size_t rows,
1096 % NexusInfo *nexus_info,ExceptionInfo *exception)
1098 % A description of each parameter follows:
1100 % o image: the image.
1102 % o x,y,columns,rows: These values define the perimeter of a region of
1105 % o nexus_info: the cache nexus to return.
1107 % o exception: return any errors or warnings in this structure.
1111 static inline MagickBooleanType IsPixelAuthentic(
1112 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1120 if (cache_info->type == PingCache)
1122 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1123 nexus_info->region.x;
1124 status=nexus_info->pixels == (cache_info->pixels+offset*
1125 cache_info->number_channels) ? MagickTrue : MagickFalse;
1129 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1130 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1131 ExceptionInfo *exception)
1140 Transfer pixels from the cache.
1142 assert(image != (Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1145 nexus_info,exception);
1146 if (pixels == (Quantum *) NULL)
1147 return((Quantum *) NULL);
1148 cache_info=(CacheInfo *) image->cache;
1149 assert(cache_info->signature == MagickSignature);
1150 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1152 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1153 return((Quantum *) NULL);
1154 if (cache_info->metacontent_extent != 0)
1155 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1156 return((Quantum *) NULL);
1161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 + 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 %
1169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1171 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1172 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1174 % The format of the GetAuthenticPixelsFromCache() method is:
1176 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1178 % A description of each parameter follows:
1180 % o image: the image.
1183 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1189 id = GetOpenMPThreadId();
1191 assert(image != (const Image *) NULL);
1192 assert(image->signature == MagickSignature);
1193 assert(image->cache != (Cache) NULL);
1194 cache_info=(CacheInfo *) image->cache;
1195 assert(cache_info->signature == MagickSignature);
1196 assert(id < (int) cache_info->number_threads);
1197 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % G e t A u t h e n t i c P i x e l Q u e u e %
1209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 % GetAuthenticPixelQueue() returns the authentic pixels associated
1212 % corresponding with the last call to QueueAuthenticPixels() or
1213 % GetAuthenticPixels().
1215 % The format of the GetAuthenticPixelQueue() method is:
1217 % Quantum *GetAuthenticPixelQueue(const Image image)
1219 % A description of each parameter follows:
1221 % o image: the image.
1224 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1230 id = GetOpenMPThreadId();
1232 assert(image != (const Image *) NULL);
1233 assert(image->signature == MagickSignature);
1234 assert(image->cache != (Cache) NULL);
1235 cache_info=(CacheInfo *) image->cache;
1236 assert(cache_info->signature == MagickSignature);
1237 if (cache_info->methods.get_authentic_pixels_from_handler !=
1238 (GetAuthenticPixelsFromHandler) NULL)
1239 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1240 assert(id < (int) cache_info->number_threads);
1241 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249 % G e t A u t h e n t i c P i x e l s %
1252 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1254 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1255 % region is successfully accessed, a pointer to a Quantum array
1256 % representing the region is returned, otherwise NULL is returned.
1258 % The returned pointer may point to a temporary working copy of the pixels
1259 % or it may point to the original pixels in memory. Performance is maximized
1260 % if the selected region is part of one row, or one or more full rows, since
1261 % then there is opportunity to access the pixels in-place (without a copy)
1262 % if the image is in memory, or in a memory-mapped file. The returned pointer
1263 % must *never* be deallocated by the user.
1265 % Pixels accessed via the returned pointer represent a simple array of type
1266 % Quantum. If the image has corresponding metacontent,call
1267 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1268 % meta-content corresponding to the region. Once the Quantum array has
1269 % been updated, the changes must be saved back to the underlying image using
1270 % SyncAuthenticPixels() or they may be lost.
1272 % The format of the GetAuthenticPixels() method is:
1274 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1275 % const ssize_t y,const size_t columns,const size_t rows,
1276 % ExceptionInfo *exception)
1278 % A description of each parameter follows:
1280 % o image: the image.
1282 % o x,y,columns,rows: These values define the perimeter of a region of
1285 % o exception: return any errors or warnings in this structure.
1288 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1289 const ssize_t y,const size_t columns,const size_t rows,
1290 ExceptionInfo *exception)
1296 id = GetOpenMPThreadId();
1301 assert(image != (Image *) NULL);
1302 assert(image->signature == MagickSignature);
1303 assert(image->cache != (Cache) NULL);
1304 cache_info=(CacheInfo *) image->cache;
1305 assert(cache_info->signature == MagickSignature);
1306 if (cache_info->methods.get_authentic_pixels_handler !=
1307 (GetAuthenticPixelsHandler) NULL)
1309 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1313 assert(id < (int) cache_info->number_threads);
1314 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1315 cache_info->nexus_info[id],exception);
1320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324 + G e t A u t h e n t i c P i x e l s C a c h e %
1328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1331 % as defined by the geometry parameters. A pointer to the pixels is returned
1332 % if the pixels are transferred, otherwise a NULL is returned.
1334 % The format of the GetAuthenticPixelsCache() method is:
1336 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1337 % const ssize_t y,const size_t columns,const size_t rows,
1338 % ExceptionInfo *exception)
1340 % A description of each parameter follows:
1342 % o image: the image.
1344 % o x,y,columns,rows: These values define the perimeter of a region of
1347 % o exception: return any errors or warnings in this structure.
1350 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1351 const ssize_t y,const size_t columns,const size_t rows,
1352 ExceptionInfo *exception)
1358 id = GetOpenMPThreadId();
1363 assert(image != (const Image *) NULL);
1364 assert(image->signature == MagickSignature);
1365 assert(image->cache != (Cache) NULL);
1366 cache_info=(CacheInfo *) image->cache;
1367 if (cache_info == (Cache) NULL)
1368 return((Quantum *) NULL);
1369 assert(cache_info->signature == MagickSignature);
1370 assert(id < (int) cache_info->number_threads);
1371 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1372 cache_info->nexus_info[id],exception);
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 + G e t I m a g e E x t e n t %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % GetImageExtent() returns the extent of the pixels associated corresponding
1388 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1390 % The format of the GetImageExtent() method is:
1392 % MagickSizeType GetImageExtent(const Image *image)
1394 % A description of each parameter follows:
1396 % o image: the image.
1399 MagickExport MagickSizeType GetImageExtent(const Image *image)
1405 id = GetOpenMPThreadId();
1407 assert(image != (Image *) NULL);
1408 assert(image->signature == MagickSignature);
1409 if (image->debug != MagickFalse)
1410 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1411 assert(image->cache != (Cache) NULL);
1412 cache_info=(CacheInfo *) image->cache;
1413 assert(cache_info->signature == MagickSignature);
1414 assert(id < (int) cache_info->number_threads);
1415 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 + G e t I m a g e P i x e l C a c h e %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 % GetImagePixelCache() ensures that there is only a single reference to the
1430 % pixel cache to be modified, updating the provided cache pointer to point to
1431 % a clone of the original pixel cache if necessary.
1433 % The format of the GetImagePixelCache method is:
1435 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1436 % ExceptionInfo *exception)
1438 % A description of each parameter follows:
1440 % o image: the image.
1442 % o clone: any value other than MagickFalse clones the cache pixels.
1444 % o exception: return any errors or warnings in this structure.
1448 static inline MagickBooleanType ValidatePixelCacheMorphology(
1449 const Image *restrict image)
1452 *restrict cache_info;
1454 const PixelChannelMap
1459 Does the image match the pixel cache morphology?
1461 cache_info=(CacheInfo *) image->cache;
1462 p=image->channel_map;
1463 q=cache_info->channel_map;
1464 if ((image->storage_class != cache_info->storage_class) ||
1465 (image->colorspace != cache_info->colorspace) ||
1466 (image->alpha_trait != cache_info->alpha_trait) ||
1467 (image->read_mask != cache_info->read_mask) ||
1468 (image->write_mask != cache_info->write_mask) ||
1469 (image->columns != cache_info->columns) ||
1470 (image->rows != cache_info->rows) ||
1471 (image->number_channels != cache_info->number_channels) ||
1472 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1473 (image->metacontent_extent != cache_info->metacontent_extent) ||
1474 (cache_info->nexus_info == (NexusInfo **) NULL))
1475 return(MagickFalse);
1479 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1480 ExceptionInfo *exception)
1489 static MagickSizeType
1495 cache_timestamp = 0;
1498 LockSemaphoreInfo(image->semaphore);
1499 if (cpu_throttle == 0)
1500 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1501 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1502 MagickDelay(cpu_throttle);
1503 if (time_limit == 0)
1506 Set the expire time in seconds.
1508 time_limit=GetMagickResourceLimit(TimeResource);
1509 cache_timestamp=time((time_t *) NULL);
1511 if ((time_limit != MagickResourceInfinity) &&
1512 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1513 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1514 assert(image->cache != (Cache) NULL);
1515 cache_info=(CacheInfo *) image->cache;
1516 destroy=MagickFalse;
1517 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1519 LockSemaphoreInfo(cache_info->semaphore);
1520 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1531 clone_image=(*image);
1532 clone_image.semaphore=AllocateSemaphoreInfo();
1533 clone_image.reference_count=1;
1534 clone_image.cache=ClonePixelCache(cache_info);
1535 clone_info=(CacheInfo *) clone_image.cache;
1536 status=OpenPixelCache(&clone_image,IOMode,exception);
1537 if (status != MagickFalse)
1539 if (clone != MagickFalse)
1540 status=ClonePixelCacheRepository(clone_info,cache_info,
1542 if (status != MagickFalse)
1544 if (cache_info->reference_count == 1)
1545 cache_info->nexus_info=(NexusInfo **) NULL;
1547 image->cache=clone_image.cache;
1550 DestroySemaphoreInfo(&clone_image.semaphore);
1552 UnlockSemaphoreInfo(cache_info->semaphore);
1554 if (destroy != MagickFalse)
1555 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1556 if (status != MagickFalse)
1559 Ensure the image matches the pixel cache morphology.
1561 image->taint=MagickTrue;
1562 image->type=UndefinedType;
1563 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1565 status=OpenPixelCache(image,IOMode,exception);
1566 cache_info=(CacheInfo *) image->cache;
1567 if (cache_info->type == DiskCache)
1568 (void) ClosePixelCacheOnDisk(cache_info);
1571 UnlockSemaphoreInfo(image->semaphore);
1572 if (status == MagickFalse)
1573 return((Cache) NULL);
1574 return(image->cache);
1578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582 + G e t I m a g e P i x e l C a c h e T y p e %
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1589 % DiskCache, MemoryCache, MapCache, or PingCache.
1591 % The format of the GetImagePixelCacheType() method is:
1593 % CacheType GetImagePixelCacheType(const Image *image)
1595 % A description of each parameter follows:
1597 % o image: the image.
1600 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1605 assert(image != (Image *) NULL);
1606 assert(image->signature == MagickSignature);
1607 assert(image->cache != (Cache) NULL);
1608 cache_info=(CacheInfo *) image->cache;
1609 assert(cache_info->signature == MagickSignature);
1610 return(cache_info->type);
1614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1618 % G e t O n e A u t h e n t i c P i x e l %
1622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1625 % location. The image background color is returned if an error occurs.
1627 % The format of the GetOneAuthenticPixel() method is:
1629 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1630 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1632 % A description of each parameter follows:
1634 % o image: the image.
1636 % o x,y: These values define the location of the pixel to return.
1638 % o pixel: return a pixel at the specified (x,y) location.
1640 % o exception: return any errors or warnings in this structure.
1643 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1644 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1655 assert(image != (Image *) NULL);
1656 assert(image->signature == MagickSignature);
1657 assert(image->cache != (Cache) NULL);
1658 cache_info=(CacheInfo *) image->cache;
1659 assert(cache_info->signature == MagickSignature);
1660 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1661 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1662 (GetOneAuthenticPixelFromHandler) NULL)
1663 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1665 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1666 if (q == (Quantum *) NULL)
1668 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1669 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1670 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1671 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1672 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1673 return(MagickFalse);
1675 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1677 PixelChannel channel=GetPixelChannelChannel(image,i);
1678 pixel[channel]=q[i];
1684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688 + 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 %
1692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1694 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1695 % location. The image background color is returned if an error occurs.
1697 % The format of the GetOneAuthenticPixelFromCache() method is:
1699 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1700 % const ssize_t x,const ssize_t y,Quantum *pixel,
1701 % ExceptionInfo *exception)
1703 % A description of each parameter follows:
1705 % o image: the image.
1707 % o x,y: These values define the location of the pixel to return.
1709 % o pixel: return a pixel at the specified (x,y) location.
1711 % o exception: return any errors or warnings in this structure.
1714 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1715 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1721 id = GetOpenMPThreadId();
1729 assert(image != (const Image *) NULL);
1730 assert(image->signature == MagickSignature);
1731 assert(image->cache != (Cache) NULL);
1732 cache_info=(CacheInfo *) image->cache;
1733 assert(cache_info->signature == MagickSignature);
1734 assert(id < (int) cache_info->number_threads);
1735 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1736 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1738 if (q == (Quantum *) NULL)
1740 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1741 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1742 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1743 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1744 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1745 return(MagickFalse);
1747 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1749 PixelChannel channel=GetPixelChannelChannel(image,i);
1750 pixel[channel]=q[i];
1756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760 % G e t O n e V i r t u a l P i x e l %
1764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1766 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1767 % (x,y) location. The image background color is returned if an error occurs.
1768 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1770 % The format of the GetOneVirtualPixel() method is:
1772 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1773 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1775 % A description of each parameter follows:
1777 % o image: the image.
1779 % o x,y: These values define the location of the pixel to return.
1781 % o pixel: return a pixel at the specified (x,y) location.
1783 % o exception: return any errors or warnings in this structure.
1786 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1787 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1793 id = GetOpenMPThreadId();
1801 assert(image != (const Image *) NULL);
1802 assert(image->signature == MagickSignature);
1803 assert(image->cache != (Cache) NULL);
1804 cache_info=(CacheInfo *) image->cache;
1805 assert(cache_info->signature == MagickSignature);
1806 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1807 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1808 (GetOneVirtualPixelFromHandler) NULL)
1809 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1810 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1811 assert(id < (int) cache_info->number_threads);
1812 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1813 1UL,1UL,cache_info->nexus_info[id],exception);
1814 if (p == (const Quantum *) NULL)
1816 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1817 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1818 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1819 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1820 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1821 return(MagickFalse);
1823 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1825 PixelChannel channel=GetPixelChannelChannel(image,i);
1826 pixel[channel]=p[i];
1832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1836 + 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 %
1840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1842 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1843 % specified (x,y) location. The image background color is returned if an
1846 % The format of the GetOneVirtualPixelFromCache() method is:
1848 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1849 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1850 % Quantum *pixel,ExceptionInfo *exception)
1852 % A description of each parameter follows:
1854 % o image: the image.
1856 % o virtual_pixel_method: the virtual pixel method.
1858 % o x,y: These values define the location of the pixel to return.
1860 % o pixel: return a pixel at the specified (x,y) location.
1862 % o exception: return any errors or warnings in this structure.
1865 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1866 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1867 Quantum *pixel,ExceptionInfo *exception)
1873 id = GetOpenMPThreadId();
1881 assert(image != (const Image *) NULL);
1882 assert(image->signature == MagickSignature);
1883 assert(image->cache != (Cache) NULL);
1884 cache_info=(CacheInfo *) image->cache;
1885 assert(cache_info->signature == MagickSignature);
1886 assert(id < (int) cache_info->number_threads);
1887 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1888 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1889 cache_info->nexus_info[id],exception);
1890 if (p == (const Quantum *) NULL)
1892 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1893 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1894 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1895 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1896 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1897 return(MagickFalse);
1899 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1901 PixelChannel channel=GetPixelChannelChannel(image,i);
1902 pixel[channel]=p[i];
1908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1912 % G e t O n e V i r t u a l P i x e l I n f o %
1916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1918 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1919 % location. The image background color is returned if an error occurs. If
1920 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1922 % The format of the GetOneVirtualPixelInfo() method is:
1924 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1925 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1926 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1928 % A description of each parameter follows:
1930 % o image: the image.
1932 % o virtual_pixel_method: the virtual pixel method.
1934 % o x,y: these values define the location of the pixel to return.
1936 % o pixel: return a pixel at the specified (x,y) location.
1938 % o exception: return any errors or warnings in this structure.
1941 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1942 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1943 PixelInfo *pixel,ExceptionInfo *exception)
1949 id = GetOpenMPThreadId();
1951 register const Quantum
1954 assert(image != (const Image *) NULL);
1955 assert(image->signature == MagickSignature);
1956 assert(image->cache != (Cache) NULL);
1957 cache_info=(CacheInfo *) image->cache;
1958 assert(cache_info->signature == MagickSignature);
1959 assert(id < (int) cache_info->number_threads);
1960 GetPixelInfo(image,pixel);
1961 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1962 cache_info->nexus_info[id],exception);
1963 if (p == (const Quantum *) NULL)
1964 return(MagickFalse);
1965 GetPixelInfoPixel(image,p,pixel);
1970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1974 + G e t P i x e l C a c h e C o l o r s p a c e %
1978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1982 % The format of the GetPixelCacheColorspace() method is:
1984 % Colorspace GetPixelCacheColorspace(Cache cache)
1986 % A description of each parameter follows:
1988 % o cache: the pixel cache.
1991 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1996 assert(cache != (Cache) NULL);
1997 cache_info=(CacheInfo *) cache;
1998 assert(cache_info->signature == MagickSignature);
1999 if (cache_info->debug != MagickFalse)
2000 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2001 cache_info->filename);
2002 return(cache_info->colorspace);
2006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2010 + G e t P i x e l C a c h e M e t h o d s %
2014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016 % GetPixelCacheMethods() initializes the CacheMethods structure.
2018 % The format of the GetPixelCacheMethods() method is:
2020 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2022 % A description of each parameter follows:
2024 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2027 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2029 assert(cache_methods != (CacheMethods *) NULL);
2030 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2031 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2032 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2033 cache_methods->get_virtual_metacontent_from_handler=
2034 GetVirtualMetacontentFromCache;
2035 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2036 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2037 cache_methods->get_authentic_metacontent_from_handler=
2038 GetAuthenticMetacontentFromCache;
2039 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2040 cache_methods->get_one_authentic_pixel_from_handler=
2041 GetOneAuthenticPixelFromCache;
2042 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2043 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2044 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2052 + G e t P i x e l C a c h e N e x u s E x t e n t %
2056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2058 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2059 % corresponding with the last call to SetPixelCacheNexusPixels() or
2060 % GetPixelCacheNexusPixels().
2062 % The format of the GetPixelCacheNexusExtent() method is:
2064 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2065 % NexusInfo *nexus_info)
2067 % A description of each parameter follows:
2069 % o nexus_info: the nexus info.
2072 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2073 NexusInfo *nexus_info)
2081 assert(cache != NULL);
2082 cache_info=(CacheInfo *) cache;
2083 assert(cache_info->signature == MagickSignature);
2084 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2086 return((MagickSizeType) cache_info->columns*cache_info->rows);
2091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2095 + 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 %
2099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2101 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2104 % The format of the GetPixelCacheNexusMetacontent() method is:
2106 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2107 % NexusInfo *nexus_info)
2109 % A description of each parameter follows:
2111 % o cache: the pixel cache.
2113 % o nexus_info: the cache nexus to return the meta-content.
2116 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2117 NexusInfo *nexus_info)
2122 assert(cache != NULL);
2123 cache_info=(CacheInfo *) cache;
2124 assert(cache_info->signature == MagickSignature);
2125 if (cache_info->storage_class == UndefinedClass)
2126 return((void *) NULL);
2127 return(nexus_info->metacontent);
2131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2135 + G e t P i x e l C a c h e N e x u s P i x e l s %
2139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2141 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2144 % The format of the GetPixelCacheNexusPixels() method is:
2146 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2147 % NexusInfo *nexus_info)
2149 % A description of each parameter follows:
2151 % o cache: the pixel cache.
2153 % o nexus_info: the cache nexus to return the pixels.
2156 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2157 NexusInfo *nexus_info)
2162 assert(cache != NULL);
2163 cache_info=(CacheInfo *) cache;
2164 assert(cache_info->signature == MagickSignature);
2165 if (cache_info->storage_class == UndefinedClass)
2166 return((Quantum *) NULL);
2167 return(nexus_info->pixels);
2171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2175 + G e t P i x e l C a c h e P i x e l s %
2179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2181 % GetPixelCachePixels() returns the pixels associated with the specified image.
2183 % The format of the GetPixelCachePixels() method is:
2185 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2186 % ExceptionInfo *exception)
2188 % A description of each parameter follows:
2190 % o image: the image.
2192 % o length: the pixel cache length.
2194 % o exception: return any errors or warnings in this structure.
2197 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2198 ExceptionInfo *exception)
2203 assert(image != (const Image *) NULL);
2204 assert(image->signature == MagickSignature);
2205 assert(image->cache != (Cache) NULL);
2206 assert(length != (MagickSizeType *) NULL);
2207 assert(exception != (ExceptionInfo *) NULL);
2208 assert(exception->signature == MagickSignature);
2209 cache_info=(CacheInfo *) image->cache;
2210 assert(cache_info->signature == MagickSignature);
2212 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2213 return((void *) NULL);
2214 *length=cache_info->length;
2215 return((void *) cache_info->pixels);
2219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223 + 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 %
2227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2229 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2231 % The format of the GetPixelCacheStorageClass() method is:
2233 % ClassType GetPixelCacheStorageClass(Cache cache)
2235 % A description of each parameter follows:
2237 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2239 % o cache: the pixel cache.
2242 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2247 assert(cache != (Cache) NULL);
2248 cache_info=(CacheInfo *) cache;
2249 assert(cache_info->signature == MagickSignature);
2250 if (cache_info->debug != MagickFalse)
2251 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2252 cache_info->filename);
2253 return(cache_info->storage_class);
2257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2261 + G e t P i x e l C a c h e T i l e S i z e %
2265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2267 % GetPixelCacheTileSize() returns the pixel cache tile size.
2269 % The format of the GetPixelCacheTileSize() method is:
2271 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2274 % A description of each parameter follows:
2276 % o image: the image.
2278 % o width: the optimize cache tile width in pixels.
2280 % o height: the optimize cache tile height in pixels.
2283 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2289 assert(image != (Image *) NULL);
2290 assert(image->signature == MagickSignature);
2291 if (image->debug != MagickFalse)
2292 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2293 cache_info=(CacheInfo *) image->cache;
2294 assert(cache_info->signature == MagickSignature);
2295 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2296 if (GetImagePixelCacheType(image) == DiskCache)
2297 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2306 + 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 %
2310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2313 % pixel cache. A virtual pixel is any pixel access that is outside the
2314 % boundaries of the image cache.
2316 % The format of the GetPixelCacheVirtualMethod() method is:
2318 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2320 % A description of each parameter follows:
2322 % o image: the image.
2325 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2330 assert(image != (Image *) NULL);
2331 assert(image->signature == MagickSignature);
2332 assert(image->cache != (Cache) NULL);
2333 cache_info=(CacheInfo *) image->cache;
2334 assert(cache_info->signature == MagickSignature);
2335 return(cache_info->virtual_pixel_method);
2339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343 + 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 %
2347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2349 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2350 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2352 % The format of the GetVirtualMetacontentFromCache() method is:
2354 % void *GetVirtualMetacontentFromCache(const Image *image)
2356 % A description of each parameter follows:
2358 % o image: the image.
2361 static const void *GetVirtualMetacontentFromCache(const Image *image)
2367 id = GetOpenMPThreadId();
2372 assert(image != (const Image *) NULL);
2373 assert(image->signature == MagickSignature);
2374 assert(image->cache != (Cache) NULL);
2375 cache_info=(CacheInfo *) image->cache;
2376 assert(cache_info->signature == MagickSignature);
2377 assert(id < (int) cache_info->number_threads);
2378 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2379 cache_info->nexus_info[id]);
2380 return(metacontent);
2384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388 + 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 %
2392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2394 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2397 % The format of the GetVirtualMetacontentFromNexus() method is:
2399 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2400 % NexusInfo *nexus_info)
2402 % A description of each parameter follows:
2404 % o cache: the pixel cache.
2406 % o nexus_info: the cache nexus to return the meta-content.
2409 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2410 NexusInfo *nexus_info)
2415 assert(cache != (Cache) NULL);
2416 cache_info=(CacheInfo *) cache;
2417 assert(cache_info->signature == MagickSignature);
2418 if (cache_info->storage_class == UndefinedClass)
2419 return((void *) NULL);
2420 return(nexus_info->metacontent);
2424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2428 % G e t V i r t u a l M e t a c o n t e n t %
2432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2434 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2435 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2436 % returned if the meta-content are not available.
2438 % The format of the GetVirtualMetacontent() method is:
2440 % const void *GetVirtualMetacontent(const Image *image)
2442 % A description of each parameter follows:
2444 % o image: the image.
2447 MagickExport const void *GetVirtualMetacontent(const Image *image)
2453 id = GetOpenMPThreadId();
2458 assert(image != (const Image *) NULL);
2459 assert(image->signature == MagickSignature);
2460 assert(image->cache != (Cache) NULL);
2461 cache_info=(CacheInfo *) image->cache;
2462 assert(cache_info->signature == MagickSignature);
2463 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2464 if (metacontent != (void *) NULL)
2465 return(metacontent);
2466 assert(id < (int) cache_info->number_threads);
2467 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2468 cache_info->nexus_info[id]);
2469 return(metacontent);
2473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2477 + 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 %
2481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2483 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2484 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2485 % is returned if the pixels are transferred, otherwise a NULL is returned.
2487 % The format of the GetVirtualPixelsFromNexus() method is:
2489 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2490 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2491 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2492 % ExceptionInfo *exception)
2494 % A description of each parameter follows:
2496 % o image: the image.
2498 % o virtual_pixel_method: the virtual pixel method.
2500 % o x,y,columns,rows: These values define the perimeter of a region of
2503 % o nexus_info: the cache nexus to acquire.
2505 % o exception: return any errors or warnings in this structure.
2512 0, 48, 12, 60, 3, 51, 15, 63,
2513 32, 16, 44, 28, 35, 19, 47, 31,
2514 8, 56, 4, 52, 11, 59, 7, 55,
2515 40, 24, 36, 20, 43, 27, 39, 23,
2516 2, 50, 14, 62, 1, 49, 13, 61,
2517 34, 18, 46, 30, 33, 17, 45, 29,
2518 10, 58, 6, 54, 9, 57, 5, 53,
2519 42, 26, 38, 22, 41, 25, 37, 21
2522 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2527 index=x+DitherMatrix[x & 0x07]-32L;
2530 if (index >= (ssize_t) columns)
2531 return((ssize_t) columns-1L);
2535 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2540 index=y+DitherMatrix[y & 0x07]-32L;
2543 if (index >= (ssize_t) rows)
2544 return((ssize_t) rows-1L);
2548 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2552 if (x >= (ssize_t) columns)
2553 return((ssize_t) (columns-1));
2557 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2561 if (y >= (ssize_t) rows)
2562 return((ssize_t) (rows-1));
2566 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2568 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2571 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2573 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2576 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2577 const size_t extent)
2583 Compute the remainder of dividing offset by extent. It returns not only
2584 the quotient (tile the offset falls in) but also the positive remainer
2585 within that tile such that 0 <= remainder < extent. This method is
2586 essentially a ldiv() using a floored modulo division rather than the
2587 normal default truncated modulo division.
2589 modulo.quotient=offset/(ssize_t) extent;
2592 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2596 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2597 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2598 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2599 ExceptionInfo *exception)
2616 virtual_pixel[CompositePixelChannel];
2621 register const Quantum
2634 register unsigned char
2641 *virtual_metacontent;
2646 assert(image != (const Image *) NULL);
2647 assert(image->signature == MagickSignature);
2648 assert(image->cache != (Cache) NULL);
2649 cache_info=(CacheInfo *) image->cache;
2650 assert(cache_info->signature == MagickSignature);
2651 if (cache_info->type == UndefinedCache)
2652 return((const Quantum *) NULL);
2655 region.width=columns;
2657 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2659 if (pixels == (Quantum *) NULL)
2660 return((const Quantum *) NULL);
2662 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2663 nexus_info->region.x;
2664 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2665 nexus_info->region.width-1L;
2666 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2667 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2668 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2669 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2675 Pixel request is inside cache extents.
2677 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2679 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2680 if (status == MagickFalse)
2681 return((const Quantum *) NULL);
2682 if (cache_info->metacontent_extent != 0)
2684 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2685 if (status == MagickFalse)
2686 return((const Quantum *) NULL);
2691 Pixel request is outside cache extents.
2693 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2694 virtual_nexus=AcquirePixelCacheNexus(1);
2695 if (virtual_nexus == (NexusInfo **) NULL)
2697 if (virtual_nexus != (NexusInfo **) NULL)
2698 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2699 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2700 "UnableToGetCacheNexus","`%s'",image->filename);
2701 return((const Quantum *) NULL);
2703 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2704 sizeof(*virtual_pixel));
2705 virtual_metacontent=(void *) NULL;
2706 switch (virtual_pixel_method)
2708 case BackgroundVirtualPixelMethod:
2709 case BlackVirtualPixelMethod:
2710 case GrayVirtualPixelMethod:
2711 case TransparentVirtualPixelMethod:
2712 case MaskVirtualPixelMethod:
2713 case WhiteVirtualPixelMethod:
2714 case EdgeVirtualPixelMethod:
2715 case CheckerTileVirtualPixelMethod:
2716 case HorizontalTileVirtualPixelMethod:
2717 case VerticalTileVirtualPixelMethod:
2719 if (cache_info->metacontent_extent != 0)
2722 Acquire a metacontent buffer.
2724 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2725 cache_info->metacontent_extent);
2726 if (virtual_metacontent == (void *) NULL)
2728 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2729 (void) ThrowMagickException(exception,GetMagickModule(),
2730 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2731 return((const Quantum *) NULL);
2733 (void) ResetMagickMemory(virtual_metacontent,0,
2734 cache_info->metacontent_extent);
2736 switch (virtual_pixel_method)
2738 case BlackVirtualPixelMethod:
2740 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2741 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2742 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2745 case GrayVirtualPixelMethod:
2747 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2748 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2750 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2753 case TransparentVirtualPixelMethod:
2755 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2756 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2757 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2760 case MaskVirtualPixelMethod:
2761 case WhiteVirtualPixelMethod:
2763 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2764 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2765 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2770 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2772 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2774 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2776 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2778 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2788 for (v=0; v < (ssize_t) rows; v++)
2794 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2795 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2796 y_offset=EdgeY(y_offset,cache_info->rows);
2797 for (u=0; u < (ssize_t) columns; u+=length)
2803 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2804 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2805 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2813 Transfer a single pixel.
2815 length=(MagickSizeType) 1;
2816 switch (virtual_pixel_method)
2818 case EdgeVirtualPixelMethod:
2821 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2822 EdgeX(x_offset,cache_info->columns),
2823 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2825 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2828 case RandomVirtualPixelMethod:
2830 if (cache_info->random_info == (RandomInfo *) NULL)
2831 cache_info->random_info=AcquireRandomInfo();
2832 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2833 RandomX(cache_info->random_info,cache_info->columns),
2834 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2835 *virtual_nexus,exception);
2836 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2839 case DitherVirtualPixelMethod:
2841 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2842 DitherX(x_offset,cache_info->columns),
2843 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2845 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2848 case TileVirtualPixelMethod:
2850 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2851 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2852 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2853 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2855 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2858 case MirrorVirtualPixelMethod:
2860 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2861 if ((x_modulo.quotient & 0x01) == 1L)
2862 x_modulo.remainder=(ssize_t) cache_info->columns-
2863 x_modulo.remainder-1L;
2864 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2865 if ((y_modulo.quotient & 0x01) == 1L)
2866 y_modulo.remainder=(ssize_t) cache_info->rows-
2867 y_modulo.remainder-1L;
2868 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2869 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2871 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2874 case HorizontalTileEdgeVirtualPixelMethod:
2876 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2877 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2878 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2879 *virtual_nexus,exception);
2880 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2883 case VerticalTileEdgeVirtualPixelMethod:
2885 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2886 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2887 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2888 *virtual_nexus,exception);
2889 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2892 case BackgroundVirtualPixelMethod:
2893 case BlackVirtualPixelMethod:
2894 case GrayVirtualPixelMethod:
2895 case TransparentVirtualPixelMethod:
2896 case MaskVirtualPixelMethod:
2897 case WhiteVirtualPixelMethod:
2900 r=virtual_metacontent;
2903 case CheckerTileVirtualPixelMethod:
2905 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2906 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2907 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2910 r=virtual_metacontent;
2913 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2914 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2916 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2919 case HorizontalTileVirtualPixelMethod:
2921 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2924 r=virtual_metacontent;
2927 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2928 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2929 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2930 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2932 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2935 case VerticalTileVirtualPixelMethod:
2937 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2940 r=virtual_metacontent;
2943 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2944 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2945 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2946 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2948 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2952 if (p == (const Quantum *) NULL)
2954 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2956 q+=cache_info->number_channels;
2957 if ((s != (void *) NULL) && (r != (const void *) NULL))
2959 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2960 s+=cache_info->metacontent_extent;
2965 Transfer a run of pixels.
2967 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2968 (size_t) length,1UL,*virtual_nexus,exception);
2969 if (p == (const Quantum *) NULL)
2971 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2972 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2973 q+=length*cache_info->number_channels;
2974 if ((r != (void *) NULL) && (s != (const void *) NULL))
2976 (void) memcpy(s,r,(size_t) length);
2977 s+=length*cache_info->metacontent_extent;
2984 if (virtual_metacontent != (void *) NULL)
2985 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2986 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2995 + G e t V i r t u a l P i x e l C a c h e %
2999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3002 % cache as defined by the geometry parameters. A pointer to the pixels
3003 % is returned if the pixels are transferred, otherwise a NULL is returned.
3005 % The format of the GetVirtualPixelCache() method is:
3007 % const Quantum *GetVirtualPixelCache(const Image *image,
3008 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3009 % const ssize_t y,const size_t columns,const size_t rows,
3010 % ExceptionInfo *exception)
3012 % A description of each parameter follows:
3014 % o image: the image.
3016 % o virtual_pixel_method: the virtual pixel method.
3018 % o x,y,columns,rows: These values define the perimeter of a region of
3021 % o exception: return any errors or warnings in this structure.
3024 static const Quantum *GetVirtualPixelCache(const Image *image,
3025 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3026 const size_t columns,const size_t rows,ExceptionInfo *exception)
3032 id = GetOpenMPThreadId();
3037 assert(image != (const Image *) NULL);
3038 assert(image->signature == MagickSignature);
3039 assert(image->cache != (Cache) NULL);
3040 cache_info=(CacheInfo *) image->cache;
3041 assert(cache_info->signature == MagickSignature);
3042 assert(id < (int) cache_info->number_threads);
3043 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3044 cache_info->nexus_info[id],exception);
3049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3053 % G e t V i r t u a l P i x e l Q u e u e %
3057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3059 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3060 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3062 % The format of the GetVirtualPixelQueue() method is:
3064 % const Quantum *GetVirtualPixelQueue(const Image image)
3066 % A description of each parameter follows:
3068 % o image: the image.
3071 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3077 id = GetOpenMPThreadId();
3079 assert(image != (const Image *) NULL);
3080 assert(image->signature == MagickSignature);
3081 assert(image->cache != (Cache) NULL);
3082 cache_info=(CacheInfo *) image->cache;
3083 assert(cache_info->signature == MagickSignature);
3084 if (cache_info->methods.get_virtual_pixels_handler !=
3085 (GetVirtualPixelsHandler) NULL)
3086 return(cache_info->methods.get_virtual_pixels_handler(image));
3087 assert(id < (int) cache_info->number_threads);
3088 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3096 % G e t V i r t u a l P i x e l s %
3100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3102 % GetVirtualPixels() returns an immutable pixel region. If the
3103 % region is successfully accessed, a pointer to it is returned, otherwise
3104 % NULL is returned. The returned pointer may point to a temporary working
3105 % copy of the pixels or it may point to the original pixels in memory.
3106 % Performance is maximized if the selected region is part of one row, or one
3107 % or more full rows, since there is opportunity to access the pixels in-place
3108 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3109 % returned pointer must *never* be deallocated by the user.
3111 % Pixels accessed via the returned pointer represent a simple array of type
3112 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3113 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3114 % access the meta-content (of type void) corresponding to the the
3117 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3119 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3120 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3121 % GetCacheViewAuthenticPixels() instead.
3123 % The format of the GetVirtualPixels() method is:
3125 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3126 % const ssize_t y,const size_t columns,const size_t rows,
3127 % ExceptionInfo *exception)
3129 % A description of each parameter follows:
3131 % o image: the image.
3133 % o x,y,columns,rows: These values define the perimeter of a region of
3136 % o exception: return any errors or warnings in this structure.
3139 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3140 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3141 ExceptionInfo *exception)
3147 id = GetOpenMPThreadId();
3152 assert(image != (const Image *) NULL);
3153 assert(image->signature == MagickSignature);
3154 assert(image->cache != (Cache) NULL);
3155 cache_info=(CacheInfo *) image->cache;
3156 assert(cache_info->signature == MagickSignature);
3157 if (cache_info->methods.get_virtual_pixel_handler !=
3158 (GetVirtualPixelHandler) NULL)
3159 return(cache_info->methods.get_virtual_pixel_handler(image,
3160 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3161 assert(id < (int) cache_info->number_threads);
3162 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3163 columns,rows,cache_info->nexus_info[id],exception);
3168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3172 + 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 %
3176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3178 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3179 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3181 % The format of the GetVirtualPixelsCache() method is:
3183 % Quantum *GetVirtualPixelsCache(const Image *image)
3185 % A description of each parameter follows:
3187 % o image: the image.
3190 static const Quantum *GetVirtualPixelsCache(const Image *image)
3196 id = GetOpenMPThreadId();
3198 assert(image != (const Image *) NULL);
3199 assert(image->signature == MagickSignature);
3200 assert(image->cache != (Cache) NULL);
3201 cache_info=(CacheInfo *) image->cache;
3202 assert(cache_info->signature == MagickSignature);
3203 assert(id < (int) cache_info->number_threads);
3204 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3212 + G e t V i r t u a l P i x e l s N e x u s %
3216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3218 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3221 % The format of the GetVirtualPixelsNexus() method is:
3223 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3224 % NexusInfo *nexus_info)
3226 % A description of each parameter follows:
3228 % o cache: the pixel cache.
3230 % o nexus_info: the cache nexus to return the colormap pixels.
3233 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3234 NexusInfo *nexus_info)
3239 assert(cache != (Cache) NULL);
3240 cache_info=(CacheInfo *) cache;
3241 assert(cache_info->signature == MagickSignature);
3242 if (cache_info->storage_class == UndefinedClass)
3243 return((Quantum *) NULL);
3244 return((const Quantum *) nexus_info->pixels);
3248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3252 + O p e n P i x e l C a c h e %
3256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3258 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3259 % dimensions, allocating space for the image pixels and optionally the
3260 % metacontent, and memory mapping the cache if it is disk based. The cache
3261 % nexus array is initialized as well.
3263 % The format of the OpenPixelCache() method is:
3265 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3266 % ExceptionInfo *exception)
3268 % A description of each parameter follows:
3270 % o image: the image.
3272 % o mode: ReadMode, WriteMode, or IOMode.
3274 % o exception: return any errors or warnings in this structure.
3278 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3280 cache_info->pixels=(Quantum *) NULL;
3281 if (cache_info->length < MagickMaxBufferExtent)
3283 cache_info->mapped=MagickFalse;
3284 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3285 (size_t) cache_info->length));
3287 if (cache_info->pixels == (Quantum *) NULL)
3289 cache_info->mapped=MagickTrue;
3290 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3291 cache_info->length);
3295 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3302 Open pixel cache on disk.
3304 if (cache_info->file != -1)
3305 return(MagickTrue); /* cache already open */
3306 if (*cache_info->cache_filename == '\0')
3307 file=AcquireUniqueFileResource(cache_info->cache_filename);
3313 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3318 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3319 O_BINARY | O_EXCL,S_MODE);
3321 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3327 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3330 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3335 return(MagickFalse);
3336 (void) AcquireMagickResource(FileResource,1);
3337 cache_info->file=file;
3338 cache_info->mode=mode;
3342 static inline MagickOffsetType WritePixelCacheRegion(
3343 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3344 const MagickSizeType length,const unsigned char *restrict buffer)
3346 register MagickOffsetType
3352 #if !defined(MAGICKCORE_HAVE_PWRITE)
3353 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3354 return((MagickOffsetType) -1);
3357 for (i=0; i < (MagickOffsetType) length; i+=count)
3359 #if !defined(MAGICKCORE_HAVE_PWRITE)
3360 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3361 (MagickSizeType) SSIZE_MAX));
3363 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3364 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3376 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3386 cache_info=(CacheInfo *) image->cache;
3387 if (image->debug != MagickFalse)
3390 format[MaxTextExtent],
3391 message[MaxTextExtent];
3393 (void) FormatMagickSize(length,MagickFalse,format);
3394 (void) FormatLocaleString(message,MaxTextExtent,
3395 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3396 cache_info->cache_filename,cache_info->file,format);
3397 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3399 if (length != (MagickSizeType) ((MagickOffsetType) length))
3400 return(MagickFalse);
3401 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3403 return(MagickFalse);
3404 if ((MagickSizeType) offset >= length)
3406 extent=(MagickOffsetType) length-1;
3407 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3408 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3409 if (cache_info->synchronize != MagickFalse)
3414 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3416 return(MagickFalse);
3419 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3422 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3423 ExceptionInfo *exception)
3430 format[MaxTextExtent],
3431 message[MaxTextExtent];
3447 assert(image != (const Image *) NULL);
3448 assert(image->signature == MagickSignature);
3449 assert(image->cache != (Cache) NULL);
3450 if (image->debug != MagickFalse)
3451 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3452 if ((image->columns == 0) || (image->rows == 0))
3453 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3454 cache_info=(CacheInfo *) image->cache;
3455 assert(cache_info->signature == MagickSignature);
3456 source_info=(*cache_info);
3457 source_info.file=(-1);
3458 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3459 image->filename,(double) GetImageIndexInList(image));
3460 cache_info->storage_class=image->storage_class;
3461 cache_info->colorspace=image->colorspace;
3462 cache_info->alpha_trait=image->alpha_trait;
3463 cache_info->read_mask=image->read_mask;
3464 cache_info->write_mask=image->write_mask;
3465 cache_info->rows=image->rows;
3466 cache_info->columns=image->columns;
3467 InitializePixelChannelMap(image);
3468 cache_info->number_channels=GetPixelChannels(image);
3469 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3470 sizeof(*image->channel_map));
3471 cache_info->metacontent_extent=image->metacontent_extent;
3472 cache_info->mode=mode;
3473 if (image->ping != MagickFalse)
3475 cache_info->type=PingCache;
3476 cache_info->pixels=(Quantum *) NULL;
3477 cache_info->metacontent=(void *) NULL;
3478 cache_info->length=0;
3481 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3482 packet_size=cache_info->number_channels*sizeof(Quantum);
3483 if (image->metacontent_extent != 0)
3484 packet_size+=cache_info->metacontent_extent;
3485 length=number_pixels*packet_size;
3486 columns=(size_t) (length/cache_info->rows/packet_size);
3487 if (cache_info->columns != columns)
3488 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3490 cache_info->length=length;
3491 status=AcquireMagickResource(AreaResource,cache_info->length);
3492 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3493 cache_info->metacontent_extent);
3494 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3496 status=AcquireMagickResource(MemoryResource,cache_info->length);
3497 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3498 (cache_info->type == MemoryCache))
3500 AllocatePixelCachePixels(cache_info);
3501 if (cache_info->pixels == (Quantum *) NULL)
3502 cache_info->pixels=source_info.pixels;
3506 Create memory pixel cache.
3509 cache_info->type=MemoryCache;
3510 cache_info->metacontent=(void *) NULL;
3511 if (cache_info->metacontent_extent != 0)
3512 cache_info->metacontent=(void *) (cache_info->pixels+
3513 number_pixels*cache_info->number_channels);
3514 if ((source_info.storage_class != UndefinedClass) &&
3517 status=ClonePixelCacheRepository(cache_info,&source_info,
3519 RelinquishPixelCachePixels(&source_info);
3521 if (image->debug != MagickFalse)
3523 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3524 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3526 (void) FormatLocaleString(message,MaxTextExtent,
3527 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3528 cache_info->filename,cache_info->mapped != MagickFalse ?
3529 "Anonymous" : "Heap",type,(double) cache_info->columns,
3530 (double) cache_info->rows,(double)
3531 cache_info->number_channels,format);
3532 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3538 RelinquishMagickResource(MemoryResource,cache_info->length);
3541 Create pixel cache on disk.
3543 status=AcquireMagickResource(DiskResource,cache_info->length);
3544 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3549 if (cache_info->type == DistributedCache)
3550 RelinquishMagickResource(DiskResource,cache_info->length);
3551 server_info=AcquireDistributeCacheInfo(exception);
3552 if (server_info != (DistributeCacheInfo *) NULL)
3554 status=OpenDistributePixelCache(server_info,image);
3555 if (status == MagickFalse)
3557 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3558 GetDistributeCacheHostname(server_info));
3559 server_info=DestroyDistributeCacheInfo(server_info);
3564 Create a distributed pixel cache.
3566 cache_info->type=DistributedCache;
3567 cache_info->server_info=server_info;
3568 (void) FormatLocaleString(cache_info->cache_filename,
3569 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3570 (DistributeCacheInfo *) cache_info->server_info),
3571 GetDistributeCachePort((DistributeCacheInfo *)
3572 cache_info->server_info));
3573 if ((source_info.storage_class != UndefinedClass) &&
3576 status=ClonePixelCacheRepository(cache_info,&source_info,
3578 RelinquishPixelCachePixels(&source_info);
3580 if (image->debug != MagickFalse)
3582 (void) FormatMagickSize(cache_info->length,MagickFalse,
3584 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3586 (void) FormatLocaleString(message,MaxTextExtent,
3587 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3588 cache_info->filename,cache_info->cache_filename,
3589 GetDistributeCacheFile((DistributeCacheInfo *)
3590 cache_info->server_info),type,(double) cache_info->columns,
3591 (double) cache_info->rows,(double)
3592 cache_info->number_channels,format);
3593 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3599 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3600 "CacheResourcesExhausted","`%s'",image->filename);
3601 return(MagickFalse);
3603 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3605 (void) ClosePixelCacheOnDisk(cache_info);
3606 *cache_info->cache_filename='\0';
3608 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3610 RelinquishMagickResource(DiskResource,cache_info->length);
3611 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3613 return(MagickFalse);
3615 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3616 cache_info->length);
3617 if (status == MagickFalse)
3619 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3621 return(MagickFalse);
3623 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3624 cache_info->metacontent_extent);
3625 if (length != (MagickSizeType) ((size_t) length))
3626 cache_info->type=DiskCache;
3629 status=AcquireMagickResource(MapResource,cache_info->length);
3630 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3631 (cache_info->type != MemoryCache))
3632 cache_info->type=DiskCache;
3635 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3636 cache_info->offset,(size_t) cache_info->length);
3637 if (cache_info->pixels == (Quantum *) NULL)
3639 cache_info->type=DiskCache;
3640 cache_info->pixels=source_info.pixels;
3645 Create file-backed memory-mapped pixel cache.
3648 (void) ClosePixelCacheOnDisk(cache_info);
3649 cache_info->type=MapCache;
3650 cache_info->mapped=MagickTrue;
3651 cache_info->metacontent=(void *) NULL;
3652 if (cache_info->metacontent_extent != 0)
3653 cache_info->metacontent=(void *) (cache_info->pixels+
3654 number_pixels*cache_info->number_channels);
3655 if ((source_info.storage_class != UndefinedClass) &&
3658 status=ClonePixelCacheRepository(cache_info,&source_info,
3660 RelinquishPixelCachePixels(&source_info);
3662 if (image->debug != MagickFalse)
3664 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3665 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3667 (void) FormatLocaleString(message,MaxTextExtent,
3668 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3669 cache_info->filename,cache_info->cache_filename,
3670 cache_info->file,type,(double) cache_info->columns,(double)
3671 cache_info->rows,(double) cache_info->number_channels,
3673 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3679 RelinquishMagickResource(MapResource,cache_info->length);
3682 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3684 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3685 RelinquishPixelCachePixels(&source_info);
3687 if (image->debug != MagickFalse)
3689 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3690 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3692 (void) FormatLocaleString(message,MaxTextExtent,
3693 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3694 cache_info->cache_filename,cache_info->file,type,(double)
3695 cache_info->columns,(double) cache_info->rows,(double)
3696 cache_info->number_channels,format);
3697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3707 + P e r s i s t P i x e l C a c h e %
3711 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3713 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3714 % persistent pixel cache is one that resides on disk and is not destroyed
3715 % when the program exits.
3717 % The format of the PersistPixelCache() method is:
3719 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3720 % const MagickBooleanType attach,MagickOffsetType *offset,
3721 % ExceptionInfo *exception)
3723 % A description of each parameter follows:
3725 % o image: the image.
3727 % o filename: the persistent pixel cache filename.
3729 % o attach: A value other than zero initializes the persistent pixel cache.
3731 % o initialize: A value other than zero initializes the persistent pixel
3734 % o offset: the offset in the persistent cache to store pixels.
3736 % o exception: return any errors or warnings in this structure.
3739 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3740 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3741 ExceptionInfo *exception)
3756 assert(image != (Image *) NULL);
3757 assert(image->signature == MagickSignature);
3758 if (image->debug != MagickFalse)
3759 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3760 assert(image->cache != (void *) NULL);
3761 assert(filename != (const char *) NULL);
3762 assert(offset != (MagickOffsetType *) NULL);
3763 page_size=GetMagickPageSize();
3764 cache_info=(CacheInfo *) image->cache;
3765 assert(cache_info->signature == MagickSignature);
3766 if (attach != MagickFalse)
3769 Attach existing persistent pixel cache.
3771 if (image->debug != MagickFalse)
3772 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3773 "attach persistent cache");
3774 (void) CopyMagickString(cache_info->cache_filename,filename,
3776 cache_info->type=DiskCache;
3777 cache_info->offset=(*offset);
3778 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3779 return(MagickFalse);
3780 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3783 if ((cache_info->mode != ReadMode) &&
3784 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3785 (cache_info->reference_count == 1))
3787 LockSemaphoreInfo(cache_info->semaphore);
3788 if ((cache_info->mode != ReadMode) &&
3789 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3790 (cache_info->reference_count == 1))
3796 Usurp existing persistent pixel cache.
3798 status=rename_utf8(cache_info->cache_filename,filename);
3801 (void) CopyMagickString(cache_info->cache_filename,filename,
3803 *offset+=cache_info->length+page_size-(cache_info->length %
3805 UnlockSemaphoreInfo(cache_info->semaphore);
3806 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3807 if (image->debug != MagickFalse)
3808 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3809 "Usurp resident persistent cache");
3813 UnlockSemaphoreInfo(cache_info->semaphore);
3816 Clone persistent pixel cache.
3818 clone_image=(*image);
3819 clone_info=(CacheInfo *) clone_image.cache;
3820 image->cache=ClonePixelCache(cache_info);
3821 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3822 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3823 cache_info->type=DiskCache;
3824 cache_info->offset=(*offset);
3825 cache_info=(CacheInfo *) image->cache;
3826 status=OpenPixelCache(image,IOMode,exception);
3827 if (status != MagickFalse)
3828 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3829 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3830 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3839 + 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 %
3843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3845 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3846 % defined by the region rectangle and returns a pointer to the region. This
3847 % region is subsequently transferred from the pixel cache with
3848 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3849 % pixels are transferred, otherwise a NULL is returned.
3851 % The format of the QueueAuthenticPixelCacheNexus() method is:
3853 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3854 % const ssize_t y,const size_t columns,const size_t rows,
3855 % const MagickBooleanType clone,NexusInfo *nexus_info,
3856 % ExceptionInfo *exception)
3858 % A description of each parameter follows:
3860 % o image: the image.
3862 % o x,y,columns,rows: These values define the perimeter of a region of
3865 % o nexus_info: the cache nexus to set.
3867 % o clone: clone the pixel cache.
3869 % o exception: return any errors or warnings in this structure.
3872 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3873 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3874 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3892 Validate pixel cache geometry.
3894 assert(image != (const Image *) NULL);
3895 assert(image->signature == MagickSignature);
3896 assert(image->cache != (Cache) NULL);
3897 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3898 if (cache_info == (Cache) NULL)
3899 return((Quantum *) NULL);
3900 assert(cache_info->signature == MagickSignature);
3901 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3902 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3903 (y >= (ssize_t) cache_info->rows))
3905 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3906 "PixelsAreNotAuthentic","`%s'",image->filename);
3907 return((Quantum *) NULL);
3909 offset=(MagickOffsetType) y*cache_info->columns+x;
3911 return((Quantum *) NULL);
3912 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3913 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3914 if ((MagickSizeType) offset >= number_pixels)
3915 return((Quantum *) NULL);
3921 region.width=columns;
3923 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3933 + 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 %
3937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3939 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3940 % defined by the region rectangle and returns a pointer to the region. This
3941 % region is subsequently transferred from the pixel cache with
3942 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3943 % pixels are transferred, otherwise a NULL is returned.
3945 % The format of the QueueAuthenticPixelsCache() method is:
3947 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3948 % const ssize_t y,const size_t columns,const size_t rows,
3949 % ExceptionInfo *exception)
3951 % A description of each parameter follows:
3953 % o image: the image.
3955 % o x,y,columns,rows: These values define the perimeter of a region of
3958 % o exception: return any errors or warnings in this structure.
3961 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3962 const ssize_t y,const size_t columns,const size_t rows,
3963 ExceptionInfo *exception)
3969 id = GetOpenMPThreadId();
3974 assert(image != (const Image *) NULL);
3975 assert(image->signature == MagickSignature);
3976 assert(image->cache != (Cache) NULL);
3977 cache_info=(CacheInfo *) image->cache;
3978 assert(cache_info->signature == MagickSignature);
3979 assert(id < (int) cache_info->number_threads);
3980 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3981 cache_info->nexus_info[id],exception);
3986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3990 % Q u e u e A u t h e n t i c P i x e l s %
3994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3996 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3997 % successfully initialized a pointer to a Quantum array representing the
3998 % region is returned, otherwise NULL is returned. The returned pointer may
3999 % point to a temporary working buffer for the pixels or it may point to the
4000 % final location of the pixels in memory.
4002 % Write-only access means that any existing pixel values corresponding to
4003 % the region are ignored. This is useful if the initial image is being
4004 % created from scratch, or if the existing pixel values are to be
4005 % completely replaced without need to refer to their pre-existing values.
4006 % The application is free to read and write the pixel buffer returned by
4007 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4008 % initialize the pixel array values. Initializing pixel array values is the
4009 % application's responsibility.
4011 % Performance is maximized if the selected region is part of one row, or
4012 % one or more full rows, since then there is opportunity to access the
4013 % pixels in-place (without a copy) if the image is in memory, or in a
4014 % memory-mapped file. The returned pointer must *never* be deallocated
4017 % Pixels accessed via the returned pointer represent a simple array of type
4018 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4019 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4020 % obtain the meta-content (of type void) corresponding to the region.
4021 % Once the Quantum (and/or Quantum) array has been updated, the
4022 % changes must be saved back to the underlying image using
4023 % SyncAuthenticPixels() or they may be lost.
4025 % The format of the QueueAuthenticPixels() method is:
4027 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4028 % const ssize_t y,const size_t columns,const size_t rows,
4029 % ExceptionInfo *exception)
4031 % A description of each parameter follows:
4033 % o image: the image.
4035 % o x,y,columns,rows: These values define the perimeter of a region of
4038 % o exception: return any errors or warnings in this structure.
4041 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4042 const ssize_t y,const size_t columns,const size_t rows,
4043 ExceptionInfo *exception)
4049 id = GetOpenMPThreadId();
4054 assert(image != (Image *) NULL);
4055 assert(image->signature == MagickSignature);
4056 assert(image->cache != (Cache) NULL);
4057 cache_info=(CacheInfo *) image->cache;
4058 assert(cache_info->signature == MagickSignature);
4059 if (cache_info->methods.queue_authentic_pixels_handler !=
4060 (QueueAuthenticPixelsHandler) NULL)
4062 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4063 columns,rows,exception);
4066 assert(id < (int) cache_info->number_threads);
4067 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4068 cache_info->nexus_info[id],exception);
4073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4077 + 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 %
4081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4083 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4086 % The format of the ReadPixelCacheMetacontent() method is:
4088 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4089 % NexusInfo *nexus_info,ExceptionInfo *exception)
4091 % A description of each parameter follows:
4093 % o cache_info: the pixel cache.
4095 % o nexus_info: the cache nexus to read the metacontent.
4097 % o exception: return any errors or warnings in this structure.
4101 static inline MagickOffsetType ReadPixelCacheRegion(
4102 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4103 const MagickSizeType length,unsigned char *restrict buffer)
4105 register MagickOffsetType
4111 #if !defined(MAGICKCORE_HAVE_PREAD)
4112 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4113 return((MagickOffsetType) -1);
4116 for (i=0; i < (MagickOffsetType) length; i+=count)
4118 #if !defined(MAGICKCORE_HAVE_PREAD)
4119 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4120 (MagickSizeType) SSIZE_MAX));
4122 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4123 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4135 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4136 NexusInfo *nexus_info,ExceptionInfo *exception)
4149 register unsigned char
4155 if (cache_info->metacontent_extent == 0)
4156 return(MagickFalse);
4157 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4159 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4160 nexus_info->region.x;
4161 length=(MagickSizeType) nexus_info->region.width*
4162 cache_info->metacontent_extent;
4163 extent=length*nexus_info->region.height;
4164 rows=nexus_info->region.height;
4166 q=(unsigned char *) nexus_info->metacontent;
4167 switch (cache_info->type)
4172 register unsigned char
4176 Read meta-content from memory.
4178 if ((cache_info->columns == nexus_info->region.width) &&
4179 (extent == (MagickSizeType) ((size_t) extent)))
4184 p=(unsigned char *) cache_info->metacontent+offset*
4185 cache_info->metacontent_extent;
4186 for (y=0; y < (ssize_t) rows; y++)
4188 (void) memcpy(q,p,(size_t) length);
4189 p+=cache_info->metacontent_extent*cache_info->columns;
4190 q+=cache_info->metacontent_extent*nexus_info->region.width;
4197 Read meta content from disk.
4199 LockSemaphoreInfo(cache_info->file_semaphore);
4200 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4202 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4203 cache_info->cache_filename);
4204 UnlockSemaphoreInfo(cache_info->file_semaphore);
4205 return(MagickFalse);
4207 if ((cache_info->columns == nexus_info->region.width) &&
4208 (extent <= MagickMaxBufferExtent))
4213 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4214 for (y=0; y < (ssize_t) rows; y++)
4216 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4217 cache_info->number_channels*sizeof(Quantum)+offset*
4218 cache_info->metacontent_extent,length,(unsigned char *) q);
4219 if (count != (MagickOffsetType) length)
4221 offset+=cache_info->columns;
4222 q+=cache_info->metacontent_extent*nexus_info->region.width;
4224 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4225 (void) ClosePixelCacheOnDisk(cache_info);
4226 UnlockSemaphoreInfo(cache_info->file_semaphore);
4229 case DistributedCache:
4235 Read metacontent from distributed cache.
4237 LockSemaphoreInfo(cache_info->file_semaphore);
4238 region=nexus_info->region;
4239 if ((cache_info->columns != nexus_info->region.width) ||
4240 (extent > MagickMaxBufferExtent))
4247 for (y=0; y < (ssize_t) rows; y++)
4249 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4250 cache_info->server_info,®ion,length,(unsigned char *) q);
4251 if (count != (MagickOffsetType) length)
4253 q+=cache_info->metacontent_extent*nexus_info->region.width;
4256 UnlockSemaphoreInfo(cache_info->file_semaphore);
4262 if (y < (ssize_t) rows)
4264 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4265 cache_info->cache_filename);
4266 return(MagickFalse);
4268 if ((cache_info->debug != MagickFalse) &&
4269 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4270 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4271 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4272 nexus_info->region.width,(double) nexus_info->region.height,(double)
4273 nexus_info->region.x,(double) nexus_info->region.y);
4278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4282 + R e a d P i x e l C a c h e P i x e l s %
4286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4288 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4291 % The format of the ReadPixelCachePixels() method is:
4293 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4294 % NexusInfo *nexus_info,ExceptionInfo *exception)
4296 % A description of each parameter follows:
4298 % o cache_info: the pixel cache.
4300 % o nexus_info: the cache nexus to read the pixels.
4302 % o exception: return any errors or warnings in this structure.
4305 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4306 NexusInfo *nexus_info,ExceptionInfo *exception)
4325 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4327 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4328 nexus_info->region.x;
4329 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4331 extent=length*nexus_info->region.height;
4332 rows=nexus_info->region.height;
4334 q=nexus_info->pixels;
4335 switch (cache_info->type)
4344 Read pixels from memory.
4346 if ((cache_info->columns == nexus_info->region.width) &&
4347 (extent == (MagickSizeType) ((size_t) extent)))
4352 p=cache_info->pixels+offset*cache_info->number_channels;
4353 for (y=0; y < (ssize_t) rows; y++)
4355 (void) memcpy(q,p,(size_t) length);
4356 p+=cache_info->number_channels*cache_info->columns;
4357 q+=cache_info->number_channels*nexus_info->region.width;
4364 Read pixels from disk.
4366 LockSemaphoreInfo(cache_info->file_semaphore);
4367 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4369 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4370 cache_info->cache_filename);
4371 UnlockSemaphoreInfo(cache_info->file_semaphore);
4372 return(MagickFalse);
4374 if ((cache_info->columns == nexus_info->region.width) &&
4375 (extent <= MagickMaxBufferExtent))
4380 for (y=0; y < (ssize_t) rows; y++)
4382 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4383 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4384 if (count != (MagickOffsetType) length)
4386 offset+=cache_info->columns;
4387 q+=cache_info->number_channels*nexus_info->region.width;
4389 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4390 (void) ClosePixelCacheOnDisk(cache_info);
4391 UnlockSemaphoreInfo(cache_info->file_semaphore);
4394 case DistributedCache:
4400 Read pixels from distributed cache.
4402 LockSemaphoreInfo(cache_info->file_semaphore);
4403 region=nexus_info->region;
4404 if ((cache_info->columns != nexus_info->region.width) ||
4405 (extent > MagickMaxBufferExtent))
4412 for (y=0; y < (ssize_t) rows; y++)
4414 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4415 cache_info->server_info,®ion,length,(unsigned char *) q);
4416 if (count != (MagickOffsetType) length)
4418 q+=cache_info->number_channels*nexus_info->region.width;
4421 UnlockSemaphoreInfo(cache_info->file_semaphore);
4427 if (y < (ssize_t) rows)
4429 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4430 cache_info->cache_filename);
4431 return(MagickFalse);
4433 if ((cache_info->debug != MagickFalse) &&
4434 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4435 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4436 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4437 nexus_info->region.width,(double) nexus_info->region.height,(double)
4438 nexus_info->region.x,(double) nexus_info->region.y);
4443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447 + R e f e r e n c e P i x e l C a c h e %
4451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4453 % ReferencePixelCache() increments the reference count associated with the
4454 % pixel cache returning a pointer to the cache.
4456 % The format of the ReferencePixelCache method is:
4458 % Cache ReferencePixelCache(Cache cache_info)
4460 % A description of each parameter follows:
4462 % o cache_info: the pixel cache.
4465 MagickPrivate Cache ReferencePixelCache(Cache cache)
4470 assert(cache != (Cache *) NULL);
4471 cache_info=(CacheInfo *) cache;
4472 assert(cache_info->signature == MagickSignature);
4473 LockSemaphoreInfo(cache_info->semaphore);
4474 cache_info->reference_count++;
4475 UnlockSemaphoreInfo(cache_info->semaphore);
4480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4484 + S e t P i x e l C a c h e M e t h o d s %
4488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4490 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4492 % The format of the SetPixelCacheMethods() method is:
4494 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4496 % A description of each parameter follows:
4498 % o cache: the pixel cache.
4500 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4503 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4508 GetOneAuthenticPixelFromHandler
4509 get_one_authentic_pixel_from_handler;
4511 GetOneVirtualPixelFromHandler
4512 get_one_virtual_pixel_from_handler;
4515 Set cache pixel methods.
4517 assert(cache != (Cache) NULL);
4518 assert(cache_methods != (CacheMethods *) NULL);
4519 cache_info=(CacheInfo *) cache;
4520 assert(cache_info->signature == MagickSignature);
4521 if (cache_info->debug != MagickFalse)
4522 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4523 cache_info->filename);
4524 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4525 cache_info->methods.get_virtual_pixel_handler=
4526 cache_methods->get_virtual_pixel_handler;
4527 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4528 cache_info->methods.destroy_pixel_handler=
4529 cache_methods->destroy_pixel_handler;
4530 if (cache_methods->get_virtual_metacontent_from_handler !=
4531 (GetVirtualMetacontentFromHandler) NULL)
4532 cache_info->methods.get_virtual_metacontent_from_handler=
4533 cache_methods->get_virtual_metacontent_from_handler;
4534 if (cache_methods->get_authentic_pixels_handler !=
4535 (GetAuthenticPixelsHandler) NULL)
4536 cache_info->methods.get_authentic_pixels_handler=
4537 cache_methods->get_authentic_pixels_handler;
4538 if (cache_methods->queue_authentic_pixels_handler !=
4539 (QueueAuthenticPixelsHandler) NULL)
4540 cache_info->methods.queue_authentic_pixels_handler=
4541 cache_methods->queue_authentic_pixels_handler;
4542 if (cache_methods->sync_authentic_pixels_handler !=
4543 (SyncAuthenticPixelsHandler) NULL)
4544 cache_info->methods.sync_authentic_pixels_handler=
4545 cache_methods->sync_authentic_pixels_handler;
4546 if (cache_methods->get_authentic_pixels_from_handler !=
4547 (GetAuthenticPixelsFromHandler) NULL)
4548 cache_info->methods.get_authentic_pixels_from_handler=
4549 cache_methods->get_authentic_pixels_from_handler;
4550 if (cache_methods->get_authentic_metacontent_from_handler !=
4551 (GetAuthenticMetacontentFromHandler) NULL)
4552 cache_info->methods.get_authentic_metacontent_from_handler=
4553 cache_methods->get_authentic_metacontent_from_handler;
4554 get_one_virtual_pixel_from_handler=
4555 cache_info->methods.get_one_virtual_pixel_from_handler;
4556 if (get_one_virtual_pixel_from_handler !=
4557 (GetOneVirtualPixelFromHandler) NULL)
4558 cache_info->methods.get_one_virtual_pixel_from_handler=
4559 cache_methods->get_one_virtual_pixel_from_handler;
4560 get_one_authentic_pixel_from_handler=
4561 cache_methods->get_one_authentic_pixel_from_handler;
4562 if (get_one_authentic_pixel_from_handler !=
4563 (GetOneAuthenticPixelFromHandler) NULL)
4564 cache_info->methods.get_one_authentic_pixel_from_handler=
4565 cache_methods->get_one_authentic_pixel_from_handler;
4569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4573 + S e t P i x e l C a c h e N e x u s P i x e l s %
4577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4579 % SetPixelCacheNexusPixels() defines the region of the cache for the
4580 % specified cache nexus.
4582 % The format of the SetPixelCacheNexusPixels() method is:
4584 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4585 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4586 % ExceptionInfo *exception)
4588 % A description of each parameter follows:
4590 % o cache_info: the pixel cache.
4592 % o mode: ReadMode, WriteMode, or IOMode.
4594 % o region: A pointer to the RectangleInfo structure that defines the
4595 % region of this particular cache nexus.
4597 % o nexus_info: the cache nexus to set.
4599 % o exception: return any errors or warnings in this structure.
4603 static inline MagickBooleanType AcquireCacheNexusPixels(
4604 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4605 ExceptionInfo *exception)
4607 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4608 return(MagickFalse);
4609 nexus_info->mapped=MagickFalse;
4610 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4611 (size_t) nexus_info->length));
4612 if (nexus_info->cache == (Quantum *) NULL)
4614 nexus_info->mapped=MagickTrue;
4615 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4616 nexus_info->length);
4618 if (nexus_info->cache == (Quantum *) NULL)
4620 (void) ThrowMagickException(exception,GetMagickModule(),
4621 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4622 cache_info->filename);
4623 return(MagickFalse);
4628 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4631 if (mode == ReadMode)
4633 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4636 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4639 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4640 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4641 ExceptionInfo *exception)
4650 assert(cache_info != (const CacheInfo *) NULL);
4651 assert(cache_info->signature == MagickSignature);
4652 if (cache_info->type == UndefinedCache)
4653 return((Quantum *) NULL);
4654 nexus_info->region=(*region);
4655 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4661 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4662 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4663 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4664 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4665 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4666 ((nexus_info->region.width == cache_info->columns) ||
4667 ((nexus_info->region.width % cache_info->columns) == 0)))))
4673 Pixels are accessed directly from memory.
4675 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4676 nexus_info->region.x;
4677 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4679 nexus_info->metacontent=(void *) NULL;
4680 if (cache_info->metacontent_extent != 0)
4681 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4682 offset*cache_info->metacontent_extent;
4683 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4684 return(nexus_info->pixels);
4688 Pixels are stored in a cache region until they are synced to the cache.
4690 number_pixels=(MagickSizeType) nexus_info->region.width*
4691 nexus_info->region.height;
4692 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4693 if (cache_info->metacontent_extent != 0)
4694 length+=number_pixels*cache_info->metacontent_extent;
4695 if (nexus_info->cache == (Quantum *) NULL)
4697 nexus_info->length=length;
4698 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4699 if (status == MagickFalse)
4701 nexus_info->length=0;
4702 return((Quantum *) NULL);
4706 if (nexus_info->length != length)
4708 RelinquishCacheNexusPixels(nexus_info);
4709 nexus_info->length=length;
4710 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4711 if (status == MagickFalse)
4713 nexus_info->length=0;
4714 return((Quantum *) NULL);
4717 nexus_info->pixels=nexus_info->cache;
4718 nexus_info->metacontent=(void *) NULL;
4719 if (cache_info->metacontent_extent != 0)
4720 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4721 cache_info->number_channels);
4722 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4723 return(nexus_info->pixels);
4727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4731 % 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 %
4735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4737 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4738 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4739 % access that is outside the boundaries of the image cache.
4741 % The format of the SetPixelCacheVirtualMethod() method is:
4743 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4744 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4746 % A description of each parameter follows:
4748 % o image: the image.
4750 % o virtual_pixel_method: choose the type of virtual pixel.
4752 % o exception: return any errors or warnings in this structure.
4756 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4757 ExceptionInfo *exception)
4771 assert(image != (Image *) NULL);
4772 assert(image->signature == MagickSignature);
4773 if (image->debug != MagickFalse)
4774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4775 assert(image->cache != (Cache) NULL);
4776 cache_info=(CacheInfo *) image->cache;
4777 assert(cache_info->signature == MagickSignature);
4778 image->alpha_trait=BlendPixelTrait;
4780 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4781 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4782 #pragma omp parallel for schedule(static,4) shared(status) \
4783 magick_threads(image,image,1,1)
4785 for (y=0; y < (ssize_t) image->rows; y++)
4793 if (status == MagickFalse)
4795 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4796 if (q == (Quantum *) NULL)
4801 for (x=0; x < (ssize_t) image->columns; x++)
4803 SetPixelAlpha(image,alpha,q);
4804 q+=GetPixelChannels(image);
4806 status=SyncCacheViewAuthenticPixels(image_view,exception);
4808 image_view=DestroyCacheView(image_view);
4812 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4813 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4821 assert(image != (Image *) NULL);
4822 assert(image->signature == MagickSignature);
4823 if (image->debug != MagickFalse)
4824 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4825 assert(image->cache != (Cache) NULL);
4826 cache_info=(CacheInfo *) image->cache;
4827 assert(cache_info->signature == MagickSignature);
4828 method=cache_info->virtual_pixel_method;
4829 cache_info->virtual_pixel_method=virtual_pixel_method;
4830 if ((image->columns != 0) && (image->rows != 0))
4831 switch (virtual_pixel_method)
4833 case BackgroundVirtualPixelMethod:
4835 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4836 (image->alpha_trait != BlendPixelTrait))
4837 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4838 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4839 (IsGrayColorspace(image->colorspace) != MagickFalse))
4840 (void) TransformImageColorspace(image,sRGBColorspace,exception);
4843 case TransparentVirtualPixelMethod:
4845 if (image->alpha_trait != BlendPixelTrait)
4846 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4860 + 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 %
4864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4867 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4868 % is synced, otherwise MagickFalse.
4870 % The format of the SyncAuthenticPixelCacheNexus() method is:
4872 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4873 % NexusInfo *nexus_info,ExceptionInfo *exception)
4875 % A description of each parameter follows:
4877 % o image: the image.
4879 % o nexus_info: the cache nexus to sync.
4881 % o exception: return any errors or warnings in this structure.
4884 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4885 NexusInfo *nexus_info,ExceptionInfo *exception)
4894 Transfer pixels to the cache.
4896 assert(image != (Image *) NULL);
4897 assert(image->signature == MagickSignature);
4898 if (image->cache == (Cache) NULL)
4899 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4900 cache_info=(CacheInfo *) image->cache;
4901 assert(cache_info->signature == MagickSignature);
4902 if (cache_info->type == UndefinedCache)
4903 return(MagickFalse);
4904 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4906 assert(cache_info->signature == MagickSignature);
4907 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4908 if ((cache_info->metacontent_extent != 0) &&
4909 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4910 return(MagickFalse);
4915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4919 + S y n c A u t h e n t i c P i x e l C a c h e %
4923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4925 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4926 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4927 % otherwise MagickFalse.
4929 % The format of the SyncAuthenticPixelsCache() method is:
4931 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4932 % ExceptionInfo *exception)
4934 % A description of each parameter follows:
4936 % o image: the image.
4938 % o exception: return any errors or warnings in this structure.
4941 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4942 ExceptionInfo *exception)
4948 id = GetOpenMPThreadId();
4953 assert(image != (Image *) NULL);
4954 assert(image->signature == MagickSignature);
4955 assert(image->cache != (Cache) NULL);
4956 cache_info=(CacheInfo *) image->cache;
4957 assert(cache_info->signature == MagickSignature);
4958 assert(id < (int) cache_info->number_threads);
4959 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4969 % S y n c A u t h e n t i c P i x e l s %
4973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4975 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4976 % The method returns MagickTrue if the pixel region is flushed, otherwise
4979 % The format of the SyncAuthenticPixels() method is:
4981 % MagickBooleanType SyncAuthenticPixels(Image *image,
4982 % ExceptionInfo *exception)
4984 % A description of each parameter follows:
4986 % o image: the image.
4988 % o exception: return any errors or warnings in this structure.
4991 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4992 ExceptionInfo *exception)
4998 id = GetOpenMPThreadId();
5003 assert(image != (Image *) NULL);
5004 assert(image->signature == MagickSignature);
5005 assert(image->cache != (Cache) NULL);
5006 cache_info=(CacheInfo *) image->cache;
5007 assert(cache_info->signature == MagickSignature);
5008 if (cache_info->methods.sync_authentic_pixels_handler !=
5009 (SyncAuthenticPixelsHandler) NULL)
5011 status=cache_info->methods.sync_authentic_pixels_handler(image,
5015 assert(id < (int) cache_info->number_threads);
5016 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5026 + S y n c I m a g e P i x e l C a c h e %
5030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5032 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5033 % The method returns MagickTrue if the pixel region is flushed, otherwise
5036 % The format of the SyncImagePixelCache() method is:
5038 % MagickBooleanType SyncImagePixelCache(Image *image,
5039 % ExceptionInfo *exception)
5041 % A description of each parameter follows:
5043 % o image: the image.
5045 % o exception: return any errors or warnings in this structure.
5048 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5049 ExceptionInfo *exception)
5054 assert(image != (Image *) NULL);
5055 assert(exception != (ExceptionInfo *) NULL);
5056 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5057 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5065 + 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 %
5069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5071 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5072 % of the pixel cache.
5074 % The format of the WritePixelCacheMetacontent() method is:
5076 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5077 % NexusInfo *nexus_info,ExceptionInfo *exception)
5079 % A description of each parameter follows:
5081 % o cache_info: the pixel cache.
5083 % o nexus_info: the cache nexus to write the meta-content.
5085 % o exception: return any errors or warnings in this structure.
5088 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5089 NexusInfo *nexus_info,ExceptionInfo *exception)
5099 register const unsigned char
5108 if (cache_info->metacontent_extent == 0)
5109 return(MagickFalse);
5110 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5112 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5113 nexus_info->region.x;
5114 length=(MagickSizeType) nexus_info->region.width*
5115 cache_info->metacontent_extent;
5116 extent=(MagickSizeType) length*nexus_info->region.height;
5117 rows=nexus_info->region.height;
5119 p=(unsigned char *) nexus_info->metacontent;
5120 switch (cache_info->type)
5125 register unsigned char
5129 Write associated pixels to memory.
5131 if ((cache_info->columns == nexus_info->region.width) &&
5132 (extent == (MagickSizeType) ((size_t) extent)))
5137 q=(unsigned char *) cache_info->metacontent+offset*
5138 cache_info->metacontent_extent;
5139 for (y=0; y < (ssize_t) rows; y++)
5141 (void) memcpy(q,p,(size_t) length);
5142 p+=nexus_info->region.width*cache_info->metacontent_extent;
5143 q+=cache_info->columns*cache_info->metacontent_extent;
5150 Write associated pixels to disk.
5152 LockSemaphoreInfo(cache_info->file_semaphore);
5153 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5155 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5156 cache_info->cache_filename);
5157 UnlockSemaphoreInfo(cache_info->file_semaphore);
5158 return(MagickFalse);
5160 if ((cache_info->columns == nexus_info->region.width) &&
5161 (extent <= MagickMaxBufferExtent))
5166 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5167 for (y=0; y < (ssize_t) rows; y++)
5169 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5170 cache_info->number_channels*sizeof(Quantum)+offset*
5171 cache_info->metacontent_extent,length,(const unsigned char *) p);
5172 if (count != (MagickOffsetType) length)
5174 p+=cache_info->metacontent_extent*nexus_info->region.width;
5175 offset+=cache_info->columns;
5177 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5178 (void) ClosePixelCacheOnDisk(cache_info);
5179 UnlockSemaphoreInfo(cache_info->file_semaphore);
5182 case DistributedCache:
5188 Write metacontent to distributed cache.
5190 LockSemaphoreInfo(cache_info->file_semaphore);
5191 region=nexus_info->region;
5192 if ((cache_info->columns != nexus_info->region.width) ||
5193 (extent > MagickMaxBufferExtent))
5200 for (y=0; y < (ssize_t) rows; y++)
5202 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5203 cache_info->server_info,®ion,length,(const unsigned char *) p);
5204 if (count != (MagickOffsetType) length)
5206 p+=cache_info->metacontent_extent*nexus_info->region.width;
5209 UnlockSemaphoreInfo(cache_info->file_semaphore);
5215 if (y < (ssize_t) rows)
5217 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5218 cache_info->cache_filename);
5219 return(MagickFalse);
5221 if ((cache_info->debug != MagickFalse) &&
5222 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5223 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5224 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5225 nexus_info->region.width,(double) nexus_info->region.height,(double)
5226 nexus_info->region.x,(double) nexus_info->region.y);
5231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5235 + W r i t e C a c h e P i x e l s %
5239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5241 % WritePixelCachePixels() writes image pixels to the specified region of the
5244 % The format of the WritePixelCachePixels() method is:
5246 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5247 % NexusInfo *nexus_info,ExceptionInfo *exception)
5249 % A description of each parameter follows:
5251 % o cache_info: the pixel cache.
5253 % o nexus_info: the cache nexus to write the pixels.
5255 % o exception: return any errors or warnings in this structure.
5258 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5259 NexusInfo *nexus_info,ExceptionInfo *exception)
5269 register const Quantum
5278 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5280 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5281 nexus_info->region.x;
5282 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5284 extent=length*nexus_info->region.height;
5285 rows=nexus_info->region.height;
5287 p=nexus_info->pixels;
5288 switch (cache_info->type)
5297 Write pixels to memory.
5299 if ((cache_info->columns == nexus_info->region.width) &&
5300 (extent == (MagickSizeType) ((size_t) extent)))
5305 q=cache_info->pixels+offset*cache_info->number_channels;
5306 for (y=0; y < (ssize_t) rows; y++)
5308 (void) memcpy(q,p,(size_t) length);
5309 p+=cache_info->number_channels*nexus_info->region.width;
5310 q+=cache_info->columns*cache_info->number_channels;
5317 Write pixels to disk.
5319 LockSemaphoreInfo(cache_info->file_semaphore);
5320 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5322 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5323 cache_info->cache_filename);
5324 UnlockSemaphoreInfo(cache_info->file_semaphore);
5325 return(MagickFalse);
5327 if ((cache_info->columns == nexus_info->region.width) &&
5328 (extent <= MagickMaxBufferExtent))
5333 for (y=0; y < (ssize_t) rows; y++)
5335 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5336 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5338 if (count != (MagickOffsetType) length)
5340 p+=cache_info->number_channels*nexus_info->region.width;
5341 offset+=cache_info->columns;
5343 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5344 (void) ClosePixelCacheOnDisk(cache_info);
5345 UnlockSemaphoreInfo(cache_info->file_semaphore);
5348 case DistributedCache:
5354 Write pixels to distributed cache.
5356 LockSemaphoreInfo(cache_info->file_semaphore);
5357 region=nexus_info->region;
5358 if ((cache_info->columns != nexus_info->region.width) ||
5359 (extent > MagickMaxBufferExtent))
5366 for (y=0; y < (ssize_t) rows; y++)
5368 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5369 cache_info->server_info,®ion,length,(const unsigned char *) p);
5370 if (count != (MagickOffsetType) length)
5372 p+=cache_info->number_channels*nexus_info->region.width;
5375 UnlockSemaphoreInfo(cache_info->file_semaphore);
5381 if (y < (ssize_t) rows)
5383 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5384 cache_info->cache_filename);
5385 return(MagickFalse);
5387 if ((cache_info->debug != MagickFalse) &&
5388 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5389 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5390 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5391 nexus_info->region.width,(double) nexus_info->region.height,(double)
5392 nexus_info->region.x,(double) nexus_info->region.y);