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(cache_info->server_info);
867 cache_info->type=UndefinedCache;
868 cache_info->mapped=MagickFalse;
869 cache_info->metacontent=(void *) NULL;
872 MagickPrivate Cache DestroyPixelCache(Cache cache)
877 assert(cache != (Cache) NULL);
878 cache_info=(CacheInfo *) cache;
879 assert(cache_info->signature == MagickSignature);
880 if (cache_info->debug != MagickFalse)
881 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
882 cache_info->filename);
883 LockSemaphoreInfo(cache_info->semaphore);
884 cache_info->reference_count--;
885 if (cache_info->reference_count != 0)
887 UnlockSemaphoreInfo(cache_info->semaphore);
888 return((Cache) NULL);
890 UnlockSemaphoreInfo(cache_info->semaphore);
891 if (cache_info->debug != MagickFalse)
894 message[MaxTextExtent];
896 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
897 cache_info->filename);
898 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
900 RelinquishPixelCachePixels(cache_info);
901 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
902 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
903 if (cache_info->nexus_info != (NexusInfo **) NULL)
904 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
905 cache_info->number_threads);
906 if (cache_info->random_info != (RandomInfo *) NULL)
907 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
908 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
909 DestroySemaphoreInfo(&cache_info->file_semaphore);
910 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
911 DestroySemaphoreInfo(&cache_info->semaphore);
912 cache_info->signature=(~MagickSignature);
913 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923 + D e s t r o y P i x e l C a c h e N e x u s %
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
931 % The format of the DestroyPixelCacheNexus() method is:
933 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
934 % const size_t number_threads)
936 % A description of each parameter follows:
938 % o nexus_info: the nexus to destroy.
940 % o number_threads: the number of nexus threads.
944 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
946 if (nexus_info->mapped == MagickFalse)
947 (void) RelinquishAlignedMemory(nexus_info->cache);
949 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
950 nexus_info->cache=(Quantum *) NULL;
951 nexus_info->pixels=(Quantum *) NULL;
952 nexus_info->metacontent=(void *) NULL;
953 nexus_info->length=0;
954 nexus_info->mapped=MagickFalse;
957 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
958 const size_t number_threads)
963 assert(nexus_info != (NexusInfo **) NULL);
964 for (i=0; i < (ssize_t) number_threads; i++)
966 if (nexus_info[i]->cache != (Quantum *) NULL)
967 RelinquishCacheNexusPixels(nexus_info[i]);
968 nexus_info[i]->signature=(~MagickSignature);
970 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
971 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980 % G e t A u t h e n t i c M e t a c o n t e n t %
984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
987 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
988 % returned if the associated pixels are not available.
990 % The format of the GetAuthenticMetacontent() method is:
992 % void *GetAuthenticMetacontent(const Image *image)
994 % A description of each parameter follows:
996 % o image: the image.
999 MagickExport void *GetAuthenticMetacontent(const Image *image)
1005 id = GetOpenMPThreadId();
1010 assert(image != (const Image *) NULL);
1011 assert(image->signature == MagickSignature);
1012 assert(image->cache != (Cache) NULL);
1013 cache_info=(CacheInfo *) image->cache;
1014 assert(cache_info->signature == MagickSignature);
1015 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1016 (GetAuthenticMetacontentFromHandler) NULL)
1018 metacontent=cache_info->methods.
1019 get_authentic_metacontent_from_handler(image);
1020 return(metacontent);
1022 assert(id < (int) cache_info->number_threads);
1023 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1024 cache_info->nexus_info[id]);
1025 return(metacontent);
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 + G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
1037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1039 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1040 % with the last call to QueueAuthenticPixelsCache() or
1041 % GetAuthenticPixelsCache().
1043 % The format of the GetAuthenticMetacontentFromCache() method is:
1045 % void *GetAuthenticMetacontentFromCache(const Image *image)
1047 % A description of each parameter follows:
1049 % o image: the image.
1052 static void *GetAuthenticMetacontentFromCache(const Image *image)
1058 id = GetOpenMPThreadId();
1063 assert(image != (const Image *) NULL);
1064 assert(image->signature == MagickSignature);
1065 assert(image->cache != (Cache) NULL);
1066 cache_info=(CacheInfo *) image->cache;
1067 assert(cache_info->signature == MagickSignature);
1068 assert(id < (int) cache_info->number_threads);
1069 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1070 cache_info->nexus_info[id]);
1071 return(metacontent);
1075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079 + G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1086 % disk pixel cache as defined by the geometry parameters. A pointer to the
1087 % pixels is returned if the pixels are transferred, otherwise a NULL is
1090 % The format of the GetAuthenticPixelCacheNexus() method is:
1092 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1093 % const ssize_t y,const size_t columns,const size_t rows,
1094 % NexusInfo *nexus_info,ExceptionInfo *exception)
1096 % A description of each parameter follows:
1098 % o image: the image.
1100 % o x,y,columns,rows: These values define the perimeter of a region of
1103 % o nexus_info: the cache nexus to return.
1105 % o exception: return any errors or warnings in this structure.
1109 static inline MagickBooleanType IsPixelAuthentic(
1110 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1118 if (cache_info->type == PingCache)
1120 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1121 nexus_info->region.x;
1122 status=nexus_info->pixels == (cache_info->pixels+offset*
1123 cache_info->number_channels) ? MagickTrue : MagickFalse;
1127 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1128 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1129 NexusInfo *nexus_info,ExceptionInfo *exception)
1138 Transfer pixels from the cache.
1140 assert(image != (Image *) NULL);
1141 assert(image->signature == MagickSignature);
1142 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1144 if (q == (Quantum *) NULL)
1145 return((Quantum *) NULL);
1146 cache_info=(CacheInfo *) image->cache;
1147 assert(cache_info->signature == MagickSignature);
1148 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1150 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1151 return((Quantum *) NULL);
1152 if (cache_info->metacontent_extent != 0)
1153 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1154 return((Quantum *) NULL);
1159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1163 + G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1170 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1172 % The format of the GetAuthenticPixelsFromCache() method is:
1174 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1176 % A description of each parameter follows:
1178 % o image: the image.
1181 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1187 id = GetOpenMPThreadId();
1189 assert(image != (const Image *) NULL);
1190 assert(image->signature == MagickSignature);
1191 assert(image->cache != (Cache) NULL);
1192 cache_info=(CacheInfo *) image->cache;
1193 assert(cache_info->signature == MagickSignature);
1194 assert(id < (int) cache_info->number_threads);
1195 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203 % G e t A u t h e n t i c P i x e l Q u e u e %
1207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209 % GetAuthenticPixelQueue() returns the authentic pixels associated
1210 % corresponding with the last call to QueueAuthenticPixels() or
1211 % GetAuthenticPixels().
1213 % The format of the GetAuthenticPixelQueue() method is:
1215 % Quantum *GetAuthenticPixelQueue(const Image image)
1217 % A description of each parameter follows:
1219 % o image: the image.
1222 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1228 id = GetOpenMPThreadId();
1230 assert(image != (const Image *) NULL);
1231 assert(image->signature == MagickSignature);
1232 assert(image->cache != (Cache) NULL);
1233 cache_info=(CacheInfo *) image->cache;
1234 assert(cache_info->signature == MagickSignature);
1235 if (cache_info->methods.get_authentic_pixels_from_handler !=
1236 (GetAuthenticPixelsFromHandler) NULL)
1237 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1238 assert(id < (int) cache_info->number_threads);
1239 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247 % G e t A u t h e n t i c P i x e l s %
1250 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1253 % region is successfully accessed, a pointer to a Quantum array
1254 % representing the region is returned, otherwise NULL is returned.
1256 % The returned pointer may point to a temporary working copy of the pixels
1257 % or it may point to the original pixels in memory. Performance is maximized
1258 % if the selected region is part of one row, or one or more full rows, since
1259 % then there is opportunity to access the pixels in-place (without a copy)
1260 % if the image is in memory, or in a memory-mapped file. The returned pointer
1261 % must *never* be deallocated by the user.
1263 % Pixels accessed via the returned pointer represent a simple array of type
1264 % Quantum. If the image has corresponding metacontent,call
1265 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1266 % meta-content corresponding to the region. Once the Quantum array has
1267 % been updated, the changes must be saved back to the underlying image using
1268 % SyncAuthenticPixels() or they may be lost.
1270 % The format of the GetAuthenticPixels() method is:
1272 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1273 % const ssize_t y,const size_t columns,const size_t rows,
1274 % ExceptionInfo *exception)
1276 % A description of each parameter follows:
1278 % o image: the image.
1280 % o x,y,columns,rows: These values define the perimeter of a region of
1283 % o exception: return any errors or warnings in this structure.
1286 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1287 const ssize_t y,const size_t columns,const size_t rows,
1288 ExceptionInfo *exception)
1294 id = GetOpenMPThreadId();
1299 assert(image != (Image *) NULL);
1300 assert(image->signature == MagickSignature);
1301 assert(image->cache != (Cache) NULL);
1302 cache_info=(CacheInfo *) image->cache;
1303 assert(cache_info->signature == MagickSignature);
1304 if (cache_info->methods.get_authentic_pixels_handler !=
1305 (GetAuthenticPixelsHandler) NULL)
1307 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1311 assert(id < (int) cache_info->number_threads);
1312 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1313 cache_info->nexus_info[id],exception);
1318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 + G e t A u t h e n t i c P i x e l s C a c h e %
1326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1328 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1329 % as defined by the geometry parameters. A pointer to the pixels is returned
1330 % if the pixels are transferred, otherwise a NULL is returned.
1332 % The format of the GetAuthenticPixelsCache() method is:
1334 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1335 % const ssize_t y,const size_t columns,const size_t rows,
1336 % ExceptionInfo *exception)
1338 % A description of each parameter follows:
1340 % o image: the image.
1342 % o x,y,columns,rows: These values define the perimeter of a region of
1345 % o exception: return any errors or warnings in this structure.
1348 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1349 const ssize_t y,const size_t columns,const size_t rows,
1350 ExceptionInfo *exception)
1356 id = GetOpenMPThreadId();
1361 assert(image != (const Image *) NULL);
1362 assert(image->signature == MagickSignature);
1363 assert(image->cache != (Cache) NULL);
1364 cache_info=(CacheInfo *) image->cache;
1365 if (cache_info == (Cache) NULL)
1366 return((Quantum *) NULL);
1367 assert(cache_info->signature == MagickSignature);
1368 assert(id < (int) cache_info->number_threads);
1369 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1370 cache_info->nexus_info[id],exception);
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379 + G e t I m a g e E x t e n t %
1383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385 % GetImageExtent() returns the extent of the pixels associated corresponding
1386 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1388 % The format of the GetImageExtent() method is:
1390 % MagickSizeType GetImageExtent(const Image *image)
1392 % A description of each parameter follows:
1394 % o image: the image.
1397 MagickExport MagickSizeType GetImageExtent(const Image *image)
1403 id = GetOpenMPThreadId();
1405 assert(image != (Image *) NULL);
1406 assert(image->signature == MagickSignature);
1407 if (image->debug != MagickFalse)
1408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1409 assert(image->cache != (Cache) NULL);
1410 cache_info=(CacheInfo *) image->cache;
1411 assert(cache_info->signature == MagickSignature);
1412 assert(id < (int) cache_info->number_threads);
1413 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 + G e t I m a g e P i x e l C a c h e %
1425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427 % GetImagePixelCache() ensures that there is only a single reference to the
1428 % pixel cache to be modified, updating the provided cache pointer to point to
1429 % a clone of the original pixel cache if necessary.
1431 % The format of the GetImagePixelCache method is:
1433 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1434 % ExceptionInfo *exception)
1436 % A description of each parameter follows:
1438 % o image: the image.
1440 % o clone: any value other than MagickFalse clones the cache pixels.
1442 % o exception: return any errors or warnings in this structure.
1446 static inline MagickBooleanType ValidatePixelCacheMorphology(
1447 const Image *restrict image)
1450 *restrict cache_info;
1452 const PixelChannelMap
1457 Does the image match the pixel cache morphology?
1459 cache_info=(CacheInfo *) image->cache;
1460 p=image->channel_map;
1461 q=cache_info->channel_map;
1462 if ((image->storage_class != cache_info->storage_class) ||
1463 (image->colorspace != cache_info->colorspace) ||
1464 (image->alpha_trait != cache_info->alpha_trait) ||
1465 (image->mask != cache_info->mask) ||
1466 (image->columns != cache_info->columns) ||
1467 (image->rows != cache_info->rows) ||
1468 (image->number_channels != cache_info->number_channels) ||
1469 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1470 (image->metacontent_extent != cache_info->metacontent_extent) ||
1471 (cache_info->nexus_info == (NexusInfo **) NULL))
1472 return(MagickFalse);
1476 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1477 ExceptionInfo *exception)
1486 static MagickSizeType
1492 cache_timestamp = 0;
1495 LockSemaphoreInfo(image->semaphore);
1496 if (cpu_throttle == 0)
1497 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1498 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1499 MagickDelay(cpu_throttle);
1500 if (time_limit == 0)
1503 Set the expire time in seconds.
1505 time_limit=GetMagickResourceLimit(TimeResource);
1506 cache_timestamp=time((time_t *) NULL);
1508 if ((time_limit != MagickResourceInfinity) &&
1509 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1510 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1511 assert(image->cache != (Cache) NULL);
1512 cache_info=(CacheInfo *) image->cache;
1513 destroy=MagickFalse;
1514 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1516 LockSemaphoreInfo(cache_info->semaphore);
1517 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1528 clone_image=(*image);
1529 clone_image.semaphore=AllocateSemaphoreInfo();
1530 clone_image.reference_count=1;
1531 clone_image.cache=ClonePixelCache(cache_info);
1532 clone_info=(CacheInfo *) clone_image.cache;
1533 status=OpenPixelCache(&clone_image,IOMode,exception);
1534 if (status != MagickFalse)
1536 if (clone != MagickFalse)
1537 status=ClonePixelCacheRepository(clone_info,cache_info,
1539 if (status != MagickFalse)
1541 if (cache_info->reference_count == 1)
1542 cache_info->nexus_info=(NexusInfo **) NULL;
1544 image->cache=clone_image.cache;
1547 DestroySemaphoreInfo(&clone_image.semaphore);
1549 UnlockSemaphoreInfo(cache_info->semaphore);
1551 if (destroy != MagickFalse)
1552 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1553 if (status != MagickFalse)
1556 Ensure the image matches the pixel cache morphology.
1558 image->taint=MagickTrue;
1559 image->type=UndefinedType;
1560 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1562 status=OpenPixelCache(image,IOMode,exception);
1563 cache_info=(CacheInfo *) image->cache;
1564 if (cache_info->type == DiskCache)
1565 (void) ClosePixelCacheOnDisk(cache_info);
1568 UnlockSemaphoreInfo(image->semaphore);
1569 if (status == MagickFalse)
1570 return((Cache) NULL);
1571 return(image->cache);
1575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579 + G e t I m a g e P i x e l C a c h e T y p e %
1583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1586 % DiskCache, MemoryCache, MapCache, or PingCache.
1588 % The format of the GetImagePixelCacheType() method is:
1590 % CacheType GetImagePixelCacheType(const Image *image)
1592 % A description of each parameter follows:
1594 % o image: the image.
1597 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1602 assert(image != (Image *) NULL);
1603 assert(image->signature == MagickSignature);
1604 assert(image->cache != (Cache) NULL);
1605 cache_info=(CacheInfo *) image->cache;
1606 assert(cache_info->signature == MagickSignature);
1607 return(cache_info->type);
1611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615 % G e t O n e A u t h e n t i c P i x e l %
1619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1622 % location. The image background color is returned if an error occurs.
1624 % The format of the GetOneAuthenticPixel() method is:
1626 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1627 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1629 % A description of each parameter follows:
1631 % o image: the image.
1633 % o x,y: These values define the location of the pixel to return.
1635 % o pixel: return a pixel at the specified (x,y) location.
1637 % o exception: return any errors or warnings in this structure.
1640 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1641 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1652 assert(image != (Image *) NULL);
1653 assert(image->signature == MagickSignature);
1654 assert(image->cache != (Cache) NULL);
1655 cache_info=(CacheInfo *) image->cache;
1656 assert(cache_info->signature == MagickSignature);
1657 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1658 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1659 (GetOneAuthenticPixelFromHandler) NULL)
1660 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1662 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1663 if (q == (Quantum *) NULL)
1665 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1666 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1667 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1668 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1669 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1670 return(MagickFalse);
1672 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1677 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++)
1752 channel=GetPixelChannelChannel(image,i);
1753 pixel[channel]=q[i];
1759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763 % G e t O n e V i r t u a l P i x e l %
1767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1770 % (x,y) location. The image background color is returned if an error occurs.
1771 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1773 % The format of the GetOneVirtualPixel() method is:
1775 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1776 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1778 % A description of each parameter follows:
1780 % o image: the image.
1782 % o x,y: These values define the location of the pixel to return.
1784 % o pixel: return a pixel at the specified (x,y) location.
1786 % o exception: return any errors or warnings in this structure.
1789 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1790 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1796 id = GetOpenMPThreadId();
1804 assert(image != (const Image *) NULL);
1805 assert(image->signature == MagickSignature);
1806 assert(image->cache != (Cache) NULL);
1807 cache_info=(CacheInfo *) image->cache;
1808 assert(cache_info->signature == MagickSignature);
1809 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1810 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1811 (GetOneVirtualPixelFromHandler) NULL)
1812 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1813 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1814 assert(id < (int) cache_info->number_threads);
1815 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1816 1UL,1UL,cache_info->nexus_info[id],exception);
1817 if (p == (const Quantum *) NULL)
1819 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1820 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1821 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1822 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1823 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1824 return(MagickFalse);
1826 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1831 channel=GetPixelChannelChannel(image,i);
1832 pixel[channel]=p[i];
1838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1842 + 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 %
1846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1848 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1849 % specified (x,y) location. The image background color is returned if an
1852 % The format of the GetOneVirtualPixelFromCache() method is:
1854 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1855 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1856 % Quantum *pixel,ExceptionInfo *exception)
1858 % A description of each parameter follows:
1860 % o image: the image.
1862 % o virtual_pixel_method: the virtual pixel method.
1864 % o x,y: These values define the location of the pixel to return.
1866 % o pixel: return a pixel at the specified (x,y) location.
1868 % o exception: return any errors or warnings in this structure.
1871 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1872 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1873 Quantum *pixel,ExceptionInfo *exception)
1879 id = GetOpenMPThreadId();
1887 assert(image != (const Image *) NULL);
1888 assert(image->signature == MagickSignature);
1889 assert(image->cache != (Cache) NULL);
1890 cache_info=(CacheInfo *) image->cache;
1891 assert(cache_info->signature == MagickSignature);
1892 assert(id < (int) cache_info->number_threads);
1893 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1894 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1895 cache_info->nexus_info[id],exception);
1896 if (p == (const Quantum *) NULL)
1898 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1899 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1900 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1901 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1902 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1903 return(MagickFalse);
1905 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1910 channel=GetPixelChannelChannel(image,i);
1911 pixel[channel]=p[i];
1917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1921 % G e t O n e V i r t u a l P i x e l I n f o %
1925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1927 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1928 % location. The image background color is returned if an error occurs. If
1929 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1931 % The format of the GetOneVirtualPixelInfo() method is:
1933 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1934 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1935 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1937 % A description of each parameter follows:
1939 % o image: the image.
1941 % o virtual_pixel_method: the virtual pixel method.
1943 % o x,y: these values define the location of the pixel to return.
1945 % o pixel: return a pixel at the specified (x,y) location.
1947 % o exception: return any errors or warnings in this structure.
1950 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1951 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1952 PixelInfo *pixel,ExceptionInfo *exception)
1958 id = GetOpenMPThreadId();
1960 register const Quantum
1963 assert(image != (const Image *) NULL);
1964 assert(image->signature == MagickSignature);
1965 assert(image->cache != (Cache) NULL);
1966 cache_info=(CacheInfo *) image->cache;
1967 assert(cache_info->signature == MagickSignature);
1968 assert(id < (int) cache_info->number_threads);
1969 GetPixelInfo(image,pixel);
1970 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1971 cache_info->nexus_info[id],exception);
1972 if (p == (const Quantum *) NULL)
1973 return(MagickFalse);
1974 GetPixelInfoPixel(image,p,pixel);
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983 + G e t P i x e l C a c h e C o l o r s p a c e %
1987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1991 % The format of the GetPixelCacheColorspace() method is:
1993 % Colorspace GetPixelCacheColorspace(Cache cache)
1995 % A description of each parameter follows:
1997 % o cache: the pixel cache.
2000 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2005 assert(cache != (Cache) NULL);
2006 cache_info=(CacheInfo *) cache;
2007 assert(cache_info->signature == MagickSignature);
2008 if (cache_info->debug != MagickFalse)
2009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2010 cache_info->filename);
2011 return(cache_info->colorspace);
2015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019 + G e t P i x e l C a c h e M e t h o d s %
2023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2025 % GetPixelCacheMethods() initializes the CacheMethods structure.
2027 % The format of the GetPixelCacheMethods() method is:
2029 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2031 % A description of each parameter follows:
2033 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2036 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2038 assert(cache_methods != (CacheMethods *) NULL);
2039 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2040 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2041 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2042 cache_methods->get_virtual_metacontent_from_handler=
2043 GetVirtualMetacontentFromCache;
2044 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2045 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2046 cache_methods->get_authentic_metacontent_from_handler=
2047 GetAuthenticMetacontentFromCache;
2048 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2049 cache_methods->get_one_authentic_pixel_from_handler=
2050 GetOneAuthenticPixelFromCache;
2051 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2052 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2053 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2061 + G e t P i x e l C a c h e N e x u s E x t e n t %
2065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2067 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2068 % corresponding with the last call to SetPixelCacheNexusPixels() or
2069 % GetPixelCacheNexusPixels().
2071 % The format of the GetPixelCacheNexusExtent() method is:
2073 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2074 % NexusInfo *nexus_info)
2076 % A description of each parameter follows:
2078 % o nexus_info: the nexus info.
2081 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2082 NexusInfo *nexus_info)
2090 assert(cache != NULL);
2091 cache_info=(CacheInfo *) cache;
2092 assert(cache_info->signature == MagickSignature);
2093 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2095 return((MagickSizeType) cache_info->columns*cache_info->rows);
2100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2104 + 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 %
2108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2113 % The format of the GetPixelCacheNexusMetacontent() method is:
2115 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2116 % NexusInfo *nexus_info)
2118 % A description of each parameter follows:
2120 % o cache: the pixel cache.
2122 % o nexus_info: the cache nexus to return the meta-content.
2125 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2126 NexusInfo *nexus_info)
2131 assert(cache != NULL);
2132 cache_info=(CacheInfo *) cache;
2133 assert(cache_info->signature == MagickSignature);
2134 if (cache_info->storage_class == UndefinedClass)
2135 return((void *) NULL);
2136 return(nexus_info->metacontent);
2140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2144 + G e t P i x e l C a c h e N e x u s P i x e l s %
2148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2150 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2153 % The format of the GetPixelCacheNexusPixels() method is:
2155 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2156 % NexusInfo *nexus_info)
2158 % A description of each parameter follows:
2160 % o cache: the pixel cache.
2162 % o nexus_info: the cache nexus to return the pixels.
2165 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2166 NexusInfo *nexus_info)
2171 assert(cache != NULL);
2172 cache_info=(CacheInfo *) cache;
2173 assert(cache_info->signature == MagickSignature);
2174 if (cache_info->storage_class == UndefinedClass)
2175 return((Quantum *) NULL);
2176 return(nexus_info->pixels);
2180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184 + G e t P i x e l C a c h e P i x e l s %
2188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2190 % GetPixelCachePixels() returns the pixels associated with the specified image.
2192 % The format of the GetPixelCachePixels() method is:
2194 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2195 % ExceptionInfo *exception)
2197 % A description of each parameter follows:
2199 % o image: the image.
2201 % o length: the pixel cache length.
2203 % o exception: return any errors or warnings in this structure.
2206 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2207 ExceptionInfo *exception)
2212 assert(image != (const Image *) NULL);
2213 assert(image->signature == MagickSignature);
2214 assert(image->cache != (Cache) NULL);
2215 assert(length != (MagickSizeType *) NULL);
2216 assert(exception != (ExceptionInfo *) NULL);
2217 assert(exception->signature == MagickSignature);
2218 cache_info=(CacheInfo *) image->cache;
2219 assert(cache_info->signature == MagickSignature);
2221 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2222 return((void *) NULL);
2223 *length=cache_info->length;
2224 return((void *) cache_info->pixels);
2228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2232 + 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 %
2236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2238 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2240 % The format of the GetPixelCacheStorageClass() method is:
2242 % ClassType GetPixelCacheStorageClass(Cache cache)
2244 % A description of each parameter follows:
2246 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2248 % o cache: the pixel cache.
2251 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2256 assert(cache != (Cache) NULL);
2257 cache_info=(CacheInfo *) cache;
2258 assert(cache_info->signature == MagickSignature);
2259 if (cache_info->debug != MagickFalse)
2260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2261 cache_info->filename);
2262 return(cache_info->storage_class);
2266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270 + G e t P i x e l C a c h e T i l e S i z e %
2274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2276 % GetPixelCacheTileSize() returns the pixel cache tile size.
2278 % The format of the GetPixelCacheTileSize() method is:
2280 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2283 % A description of each parameter follows:
2285 % o image: the image.
2287 % o width: the optimize cache tile width in pixels.
2289 % o height: the optimize cache tile height in pixels.
2292 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2298 assert(image != (Image *) NULL);
2299 assert(image->signature == MagickSignature);
2300 if (image->debug != MagickFalse)
2301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2302 cache_info=(CacheInfo *) image->cache;
2303 assert(cache_info->signature == MagickSignature);
2304 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2305 if (GetImagePixelCacheType(image) == DiskCache)
2306 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315 + 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 %
2319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2322 % pixel cache. A virtual pixel is any pixel access that is outside the
2323 % boundaries of the image cache.
2325 % The format of the GetPixelCacheVirtualMethod() method is:
2327 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2329 % A description of each parameter follows:
2331 % o image: the image.
2334 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2339 assert(image != (Image *) NULL);
2340 assert(image->signature == MagickSignature);
2341 assert(image->cache != (Cache) NULL);
2342 cache_info=(CacheInfo *) image->cache;
2343 assert(cache_info->signature == MagickSignature);
2344 return(cache_info->virtual_pixel_method);
2348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352 + 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 %
2356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2359 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2361 % The format of the GetVirtualMetacontentFromCache() method is:
2363 % void *GetVirtualMetacontentFromCache(const Image *image)
2365 % A description of each parameter follows:
2367 % o image: the image.
2370 static const void *GetVirtualMetacontentFromCache(const Image *image)
2376 id = GetOpenMPThreadId();
2381 assert(image != (const Image *) NULL);
2382 assert(image->signature == MagickSignature);
2383 assert(image->cache != (Cache) NULL);
2384 cache_info=(CacheInfo *) image->cache;
2385 assert(cache_info->signature == MagickSignature);
2386 assert(id < (int) cache_info->number_threads);
2387 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2388 cache_info->nexus_info[id]);
2389 return(metacontent);
2393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2397 + 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 %
2401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2406 % The format of the GetVirtualMetacontentFromNexus() method is:
2408 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2409 % NexusInfo *nexus_info)
2411 % A description of each parameter follows:
2413 % o cache: the pixel cache.
2415 % o nexus_info: the cache nexus to return the meta-content.
2418 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2419 NexusInfo *nexus_info)
2424 assert(cache != (Cache) NULL);
2425 cache_info=(CacheInfo *) cache;
2426 assert(cache_info->signature == MagickSignature);
2427 if (cache_info->storage_class == UndefinedClass)
2428 return((void *) NULL);
2429 return(nexus_info->metacontent);
2433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2437 % G e t V i r t u a l M e t a c o n t e n t %
2441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2443 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2444 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2445 % returned if the meta-content are not available.
2447 % The format of the GetVirtualMetacontent() method is:
2449 % const void *GetVirtualMetacontent(const Image *image)
2451 % A description of each parameter follows:
2453 % o image: the image.
2456 MagickExport const void *GetVirtualMetacontent(const Image *image)
2462 id = GetOpenMPThreadId();
2467 assert(image != (const Image *) NULL);
2468 assert(image->signature == MagickSignature);
2469 assert(image->cache != (Cache) NULL);
2470 cache_info=(CacheInfo *) image->cache;
2471 assert(cache_info->signature == MagickSignature);
2472 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2473 if (metacontent != (void *) NULL)
2474 return(metacontent);
2475 assert(id < (int) cache_info->number_threads);
2476 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2477 cache_info->nexus_info[id]);
2478 return(metacontent);
2482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2486 + 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 %
2490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2492 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2493 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2494 % is returned if the pixels are transferred, otherwise a NULL is returned.
2496 % The format of the GetVirtualPixelsFromNexus() method is:
2498 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2499 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2500 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2501 % ExceptionInfo *exception)
2503 % A description of each parameter follows:
2505 % o image: the image.
2507 % o virtual_pixel_method: the virtual pixel method.
2509 % o x,y,columns,rows: These values define the perimeter of a region of
2512 % o nexus_info: the cache nexus to acquire.
2514 % o exception: return any errors or warnings in this structure.
2521 0, 48, 12, 60, 3, 51, 15, 63,
2522 32, 16, 44, 28, 35, 19, 47, 31,
2523 8, 56, 4, 52, 11, 59, 7, 55,
2524 40, 24, 36, 20, 43, 27, 39, 23,
2525 2, 50, 14, 62, 1, 49, 13, 61,
2526 34, 18, 46, 30, 33, 17, 45, 29,
2527 10, 58, 6, 54, 9, 57, 5, 53,
2528 42, 26, 38, 22, 41, 25, 37, 21
2531 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2536 index=x+DitherMatrix[x & 0x07]-32L;
2539 if (index >= (ssize_t) columns)
2540 return((ssize_t) columns-1L);
2544 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2549 index=y+DitherMatrix[y & 0x07]-32L;
2552 if (index >= (ssize_t) rows)
2553 return((ssize_t) rows-1L);
2557 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2561 if (x >= (ssize_t) columns)
2562 return((ssize_t) (columns-1));
2566 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2570 if (y >= (ssize_t) rows)
2571 return((ssize_t) (rows-1));
2575 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2577 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2580 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2582 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2585 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2586 const size_t extent)
2592 Compute the remainder of dividing offset by extent. It returns not only
2593 the quotient (tile the offset falls in) but also the positive remainer
2594 within that tile such that 0 <= remainder < extent. This method is
2595 essentially a ldiv() using a floored modulo division rather than the
2596 normal default truncated modulo division.
2598 modulo.quotient=offset/(ssize_t) extent;
2601 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2605 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2606 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2607 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2608 ExceptionInfo *exception)
2625 virtual_pixel[CompositePixelChannel];
2630 register const Quantum
2643 register unsigned char
2650 *virtual_metacontent;
2655 assert(image != (const Image *) NULL);
2656 assert(image->signature == MagickSignature);
2657 assert(image->cache != (Cache) NULL);
2658 cache_info=(CacheInfo *) image->cache;
2659 assert(cache_info->signature == MagickSignature);
2660 if (cache_info->type == UndefinedCache)
2661 return((const Quantum *) NULL);
2664 region.width=columns;
2666 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2668 if (pixels == (Quantum *) NULL)
2669 return((const Quantum *) NULL);
2671 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2672 nexus_info->region.x;
2673 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2674 nexus_info->region.width-1L;
2675 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2676 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2677 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2678 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2684 Pixel request is inside cache extents.
2686 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2688 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2689 if (status == MagickFalse)
2690 return((const Quantum *) NULL);
2691 if (cache_info->metacontent_extent != 0)
2693 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2694 if (status == MagickFalse)
2695 return((const Quantum *) NULL);
2700 Pixel request is outside cache extents.
2702 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2703 virtual_nexus=AcquirePixelCacheNexus(1);
2704 if (virtual_nexus == (NexusInfo **) NULL)
2706 if (virtual_nexus != (NexusInfo **) NULL)
2707 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2708 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2709 "UnableToGetCacheNexus","`%s'",image->filename);
2710 return((const Quantum *) NULL);
2712 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2713 sizeof(*virtual_pixel));
2714 virtual_metacontent=(void *) NULL;
2715 switch (virtual_pixel_method)
2717 case BackgroundVirtualPixelMethod:
2718 case BlackVirtualPixelMethod:
2719 case GrayVirtualPixelMethod:
2720 case TransparentVirtualPixelMethod:
2721 case MaskVirtualPixelMethod:
2722 case WhiteVirtualPixelMethod:
2723 case EdgeVirtualPixelMethod:
2724 case CheckerTileVirtualPixelMethod:
2725 case HorizontalTileVirtualPixelMethod:
2726 case VerticalTileVirtualPixelMethod:
2728 if (cache_info->metacontent_extent != 0)
2731 Acquire a metacontent buffer.
2733 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2734 cache_info->metacontent_extent);
2735 if (virtual_metacontent == (void *) NULL)
2737 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2738 (void) ThrowMagickException(exception,GetMagickModule(),
2739 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2740 return((const Quantum *) NULL);
2742 (void) ResetMagickMemory(virtual_metacontent,0,
2743 cache_info->metacontent_extent);
2745 switch (virtual_pixel_method)
2747 case BlackVirtualPixelMethod:
2749 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2750 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2751 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2754 case GrayVirtualPixelMethod:
2756 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2757 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2759 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2762 case TransparentVirtualPixelMethod:
2764 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2765 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2766 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2769 case MaskVirtualPixelMethod:
2770 case WhiteVirtualPixelMethod:
2772 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2773 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2774 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2779 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2781 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2783 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2785 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2787 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2797 for (v=0; v < (ssize_t) rows; v++)
2799 for (u=0; u < (ssize_t) columns; u+=length)
2801 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
2802 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
2803 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
2811 Transfer a single pixel.
2813 length=(MagickSizeType) 1;
2814 switch (virtual_pixel_method)
2818 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2819 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
2820 1UL,1UL,*virtual_nexus,exception);
2821 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2824 case RandomVirtualPixelMethod:
2826 if (cache_info->random_info == (RandomInfo *) NULL)
2827 cache_info->random_info=AcquireRandomInfo();
2828 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2829 RandomX(cache_info->random_info,cache_info->columns),
2830 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2831 *virtual_nexus,exception);
2832 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2835 case DitherVirtualPixelMethod:
2837 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2838 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
2839 1UL,1UL,*virtual_nexus,exception);
2840 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2843 case TileVirtualPixelMethod:
2845 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2846 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2847 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2848 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2850 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2853 case MirrorVirtualPixelMethod:
2855 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2856 if ((x_modulo.quotient & 0x01) == 1L)
2857 x_modulo.remainder=(ssize_t) cache_info->columns-
2858 x_modulo.remainder-1L;
2859 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2860 if ((y_modulo.quotient & 0x01) == 1L)
2861 y_modulo.remainder=(ssize_t) cache_info->rows-
2862 y_modulo.remainder-1L;
2863 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2864 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2866 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2869 case HorizontalTileEdgeVirtualPixelMethod:
2871 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2872 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2873 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
2874 *virtual_nexus,exception);
2875 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2878 case VerticalTileEdgeVirtualPixelMethod:
2880 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2881 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2882 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
2883 *virtual_nexus,exception);
2884 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2887 case BackgroundVirtualPixelMethod:
2888 case BlackVirtualPixelMethod:
2889 case GrayVirtualPixelMethod:
2890 case TransparentVirtualPixelMethod:
2891 case MaskVirtualPixelMethod:
2892 case WhiteVirtualPixelMethod:
2895 r=virtual_metacontent;
2898 case EdgeVirtualPixelMethod:
2899 case CheckerTileVirtualPixelMethod:
2901 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2902 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2903 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2906 r=virtual_metacontent;
2909 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2910 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2912 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2915 case HorizontalTileVirtualPixelMethod:
2917 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
2920 r=virtual_metacontent;
2923 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2924 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2925 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2926 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2928 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2931 case VerticalTileVirtualPixelMethod:
2933 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
2936 r=virtual_metacontent;
2939 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2940 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2941 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2942 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2944 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2948 if (p == (const Quantum *) NULL)
2950 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2952 q+=cache_info->number_channels;
2953 if ((s != (void *) NULL) && (r != (const void *) NULL))
2955 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2956 s+=cache_info->metacontent_extent;
2961 Transfer a run of pixels.
2963 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
2964 length,1UL,*virtual_nexus,exception);
2965 if (p == (const Quantum *) NULL)
2967 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2968 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2969 q+=length*cache_info->number_channels;
2970 if ((r != (void *) NULL) && (s != (const void *) NULL))
2972 (void) memcpy(s,r,(size_t) length);
2973 s+=length*cache_info->metacontent_extent;
2980 if (virtual_metacontent != (void *) NULL)
2981 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2982 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2991 + G e t V i r t u a l P i x e l C a c h e %
2995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2997 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2998 % cache as defined by the geometry parameters. A pointer to the pixels
2999 % is returned if the pixels are transferred, otherwise a NULL is returned.
3001 % The format of the GetVirtualPixelCache() method is:
3003 % const Quantum *GetVirtualPixelCache(const Image *image,
3004 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3005 % const ssize_t y,const size_t columns,const size_t rows,
3006 % ExceptionInfo *exception)
3008 % A description of each parameter follows:
3010 % o image: the image.
3012 % o virtual_pixel_method: the virtual pixel method.
3014 % o x,y,columns,rows: These values define the perimeter of a region of
3017 % o exception: return any errors or warnings in this structure.
3020 static const Quantum *GetVirtualPixelCache(const Image *image,
3021 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3022 const size_t columns,const size_t rows,ExceptionInfo *exception)
3028 id = GetOpenMPThreadId();
3033 assert(image != (const Image *) NULL);
3034 assert(image->signature == MagickSignature);
3035 assert(image->cache != (Cache) NULL);
3036 cache_info=(CacheInfo *) image->cache;
3037 assert(cache_info->signature == MagickSignature);
3038 assert(id < (int) cache_info->number_threads);
3039 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3040 cache_info->nexus_info[id],exception);
3045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049 % G e t V i r t u a l P i x e l Q u e u e %
3053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3056 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3058 % The format of the GetVirtualPixelQueue() method is:
3060 % const Quantum *GetVirtualPixelQueue(const Image image)
3062 % A description of each parameter follows:
3064 % o image: the image.
3067 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3073 id = GetOpenMPThreadId();
3075 assert(image != (const Image *) NULL);
3076 assert(image->signature == MagickSignature);
3077 assert(image->cache != (Cache) NULL);
3078 cache_info=(CacheInfo *) image->cache;
3079 assert(cache_info->signature == MagickSignature);
3080 if (cache_info->methods.get_virtual_pixels_handler !=
3081 (GetVirtualPixelsHandler) NULL)
3082 return(cache_info->methods.get_virtual_pixels_handler(image));
3083 assert(id < (int) cache_info->number_threads);
3084 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3092 % G e t V i r t u a l P i x e l s %
3096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3098 % GetVirtualPixels() returns an immutable pixel region. If the
3099 % region is successfully accessed, a pointer to it is returned, otherwise
3100 % NULL is returned. The returned pointer may point to a temporary working
3101 % copy of the pixels or it may point to the original pixels in memory.
3102 % Performance is maximized if the selected region is part of one row, or one
3103 % or more full rows, since there is opportunity to access the pixels in-place
3104 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3105 % returned pointer must *never* be deallocated by the user.
3107 % Pixels accessed via the returned pointer represent a simple array of type
3108 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3109 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3110 % access the meta-content (of type void) corresponding to the the
3113 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3115 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3116 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3117 % GetCacheViewAuthenticPixels() instead.
3119 % The format of the GetVirtualPixels() method is:
3121 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3122 % const ssize_t y,const size_t columns,const size_t rows,
3123 % ExceptionInfo *exception)
3125 % A description of each parameter follows:
3127 % o image: the image.
3129 % o x,y,columns,rows: These values define the perimeter of a region of
3132 % o exception: return any errors or warnings in this structure.
3135 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3136 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3137 ExceptionInfo *exception)
3143 id = GetOpenMPThreadId();
3148 assert(image != (const Image *) NULL);
3149 assert(image->signature == MagickSignature);
3150 assert(image->cache != (Cache) NULL);
3151 cache_info=(CacheInfo *) image->cache;
3152 assert(cache_info->signature == MagickSignature);
3153 if (cache_info->methods.get_virtual_pixel_handler !=
3154 (GetVirtualPixelHandler) NULL)
3155 return(cache_info->methods.get_virtual_pixel_handler(image,
3156 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3157 assert(id < (int) cache_info->number_threads);
3158 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3159 columns,rows,cache_info->nexus_info[id],exception);
3164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3168 + 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 %
3172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3174 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3175 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3177 % The format of the GetVirtualPixelsCache() method is:
3179 % Quantum *GetVirtualPixelsCache(const Image *image)
3181 % A description of each parameter follows:
3183 % o image: the image.
3186 static const Quantum *GetVirtualPixelsCache(const Image *image)
3192 id = GetOpenMPThreadId();
3194 assert(image != (const Image *) NULL);
3195 assert(image->signature == MagickSignature);
3196 assert(image->cache != (Cache) NULL);
3197 cache_info=(CacheInfo *) image->cache;
3198 assert(cache_info->signature == MagickSignature);
3199 assert(id < (int) cache_info->number_threads);
3200 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3208 + G e t V i r t u a l P i x e l s N e x u s %
3212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3214 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3217 % The format of the GetVirtualPixelsNexus() method is:
3219 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3220 % NexusInfo *nexus_info)
3222 % A description of each parameter follows:
3224 % o cache: the pixel cache.
3226 % o nexus_info: the cache nexus to return the colormap pixels.
3229 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3230 NexusInfo *nexus_info)
3235 assert(cache != (Cache) NULL);
3236 cache_info=(CacheInfo *) cache;
3237 assert(cache_info->signature == MagickSignature);
3238 if (cache_info->storage_class == UndefinedClass)
3239 return((Quantum *) NULL);
3240 return((const Quantum *) nexus_info->pixels);
3244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3248 + O p e n P i x e l C a c h e %
3252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3254 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3255 % dimensions, allocating space for the image pixels and optionally the
3256 % metacontent, and memory mapping the cache if it is disk based. The cache
3257 % nexus array is initialized as well.
3259 % The format of the OpenPixelCache() method is:
3261 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3262 % ExceptionInfo *exception)
3264 % A description of each parameter follows:
3266 % o image: the image.
3268 % o mode: ReadMode, WriteMode, or IOMode.
3270 % o exception: return any errors or warnings in this structure.
3274 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3276 cache_info->mapped=MagickFalse;
3277 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3278 (size_t) cache_info->length));
3279 if (cache_info->pixels == (Quantum *) NULL)
3281 cache_info->mapped=MagickTrue;
3282 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3283 cache_info->length);
3287 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3294 Open pixel cache on disk.
3296 if (cache_info->file != -1)
3297 return(MagickTrue); /* cache already open */
3298 if (*cache_info->cache_filename == '\0')
3299 file=AcquireUniqueFileResource(cache_info->cache_filename);
3305 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3310 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3311 O_BINARY | O_EXCL,S_MODE);
3313 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3319 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3322 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3327 return(MagickFalse);
3328 (void) AcquireMagickResource(FileResource,1);
3329 cache_info->file=file;
3330 cache_info->mode=mode;
3334 static inline MagickOffsetType WritePixelCacheRegion(
3335 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3336 const MagickSizeType length,const unsigned char *restrict buffer)
3338 register MagickOffsetType
3344 #if !defined(MAGICKCORE_HAVE_PWRITE)
3345 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3346 return((MagickOffsetType) -1);
3349 for (i=0; i < (MagickOffsetType) length; i+=count)
3351 #if !defined(MAGICKCORE_HAVE_PWRITE)
3352 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3353 (MagickSizeType) SSIZE_MAX));
3355 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3356 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3368 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3378 cache_info=(CacheInfo *) image->cache;
3379 if (image->debug != MagickFalse)
3382 format[MaxTextExtent],
3383 message[MaxTextExtent];
3385 (void) FormatMagickSize(length,MagickFalse,format);
3386 (void) FormatLocaleString(message,MaxTextExtent,
3387 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3388 cache_info->cache_filename,cache_info->file,format);
3389 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3391 if (length != (MagickSizeType) ((MagickOffsetType) length))
3392 return(MagickFalse);
3393 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3395 return(MagickFalse);
3396 if ((MagickSizeType) offset >= length)
3398 extent=(MagickOffsetType) length-1;
3399 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3400 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3401 if (cache_info->synchronize != MagickFalse)
3406 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3408 return(MagickFalse);
3411 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3414 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3415 ExceptionInfo *exception)
3422 format[MaxTextExtent],
3423 message[MaxTextExtent];
3439 assert(image != (const Image *) NULL);
3440 assert(image->signature == MagickSignature);
3441 assert(image->cache != (Cache) NULL);
3442 if (image->debug != MagickFalse)
3443 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3444 if ((image->columns == 0) || (image->rows == 0))
3445 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3446 cache_info=(CacheInfo *) image->cache;
3447 assert(cache_info->signature == MagickSignature);
3448 source_info=(*cache_info);
3449 source_info.file=(-1);
3450 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3451 image->filename,(double) GetImageIndexInList(image));
3452 cache_info->storage_class=image->storage_class;
3453 cache_info->colorspace=image->colorspace;
3454 cache_info->alpha_trait=image->alpha_trait;
3455 cache_info->mask=image->mask;
3456 cache_info->rows=image->rows;
3457 cache_info->columns=image->columns;
3458 InitializePixelChannelMap(image);
3459 cache_info->number_channels=GetPixelChannels(image);
3460 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3461 sizeof(*image->channel_map));
3462 cache_info->metacontent_extent=image->metacontent_extent;
3463 cache_info->mode=mode;
3464 if (image->ping != MagickFalse)
3466 cache_info->type=PingCache;
3467 cache_info->pixels=(Quantum *) NULL;
3468 cache_info->metacontent=(void *) NULL;
3469 cache_info->length=0;
3472 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3473 packet_size=cache_info->number_channels*sizeof(Quantum);
3474 if (image->metacontent_extent != 0)
3475 packet_size+=cache_info->metacontent_extent;
3476 length=number_pixels*packet_size;
3477 columns=(size_t) (length/cache_info->rows/packet_size);
3478 if (cache_info->columns != columns)
3479 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3481 cache_info->length=length;
3482 status=AcquireMagickResource(AreaResource,cache_info->length);
3483 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3484 cache_info->metacontent_extent);
3485 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3487 status=AcquireMagickResource(MemoryResource,cache_info->length);
3488 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3489 (cache_info->type == MemoryCache))
3491 AllocatePixelCachePixels(cache_info);
3492 if (cache_info->pixels == (Quantum *) NULL)
3493 cache_info->pixels=source_info.pixels;
3497 Create memory pixel cache.
3500 cache_info->type=MemoryCache;
3501 cache_info->metacontent=(void *) NULL;
3502 if (cache_info->metacontent_extent != 0)
3503 cache_info->metacontent=(void *) (cache_info->pixels+
3504 number_pixels*cache_info->number_channels);
3505 if ((source_info.storage_class != UndefinedClass) &&
3508 status=ClonePixelCacheRepository(cache_info,&source_info,
3510 RelinquishPixelCachePixels(&source_info);
3512 if (image->debug != MagickFalse)
3514 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3515 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3517 (void) FormatLocaleString(message,MaxTextExtent,
3518 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3519 cache_info->filename,cache_info->mapped != MagickFalse ?
3520 "Anonymous" : "Heap",type,(double) cache_info->columns,
3521 (double) cache_info->rows,(double)
3522 cache_info->number_channels,format);
3523 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3529 RelinquishMagickResource(MemoryResource,cache_info->length);
3532 Create pixel cache on disk.
3534 status=AcquireMagickResource(DiskResource,cache_info->length);
3535 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3540 if (cache_info->type == DistributedCache)
3541 RelinquishMagickResource(DiskResource,cache_info->length);
3542 server_info=AcquireDistributeCacheInfo(exception);
3543 if (server_info != (DistributeCacheInfo *) NULL)
3545 status=OpenDistributePixelCache(server_info,image);
3546 if (status == MagickFalse)
3548 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3549 GetDistributeCacheHostname(server_info));
3550 server_info=DestroyDistributeCacheInfo(server_info);
3555 Create a distributed pixel cache.
3557 cache_info->type=DistributedCache;
3558 cache_info->server_info=server_info;
3559 (void) FormatLocaleString(cache_info->cache_filename,
3560 MaxTextExtent,"%s:%d",
3561 GetDistributeCacheHostname(cache_info->server_info),
3562 GetDistributeCachePort(cache_info->server_info));
3563 if ((source_info.storage_class != UndefinedClass) &&
3566 status=ClonePixelCacheRepository(cache_info,&source_info,
3568 RelinquishPixelCachePixels(&source_info);
3570 if (image->debug != MagickFalse)
3572 (void) FormatMagickSize(cache_info->length,MagickFalse,
3574 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3576 (void) FormatLocaleString(message,MaxTextExtent,
3577 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3578 cache_info->filename,cache_info->cache_filename,
3579 GetDistributeCacheFile(cache_info->server_info),type,
3580 (double) cache_info->columns,(double) cache_info->rows,
3581 (double) cache_info->number_channels,format);
3582 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3588 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3589 "CacheResourcesExhausted","`%s'",image->filename);
3590 return(MagickFalse);
3592 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3594 (void) ClosePixelCacheOnDisk(cache_info);
3595 *cache_info->cache_filename='\0';
3597 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3599 RelinquishMagickResource(DiskResource,cache_info->length);
3600 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3602 return(MagickFalse);
3604 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3605 cache_info->length);
3606 if (status == MagickFalse)
3608 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3610 return(MagickFalse);
3612 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3613 cache_info->metacontent_extent);
3614 if (length != (MagickSizeType) ((size_t) length))
3615 cache_info->type=DiskCache;
3618 status=AcquireMagickResource(MapResource,cache_info->length);
3619 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3620 (cache_info->type != MemoryCache))
3621 cache_info->type=DiskCache;
3624 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3625 cache_info->offset,(size_t) cache_info->length);
3626 if (cache_info->pixels == (Quantum *) NULL)
3628 cache_info->type=DiskCache;
3629 cache_info->pixels=source_info.pixels;
3634 Create file-backed memory-mapped pixel cache.
3637 (void) ClosePixelCacheOnDisk(cache_info);
3638 cache_info->type=MapCache;
3639 cache_info->mapped=MagickTrue;
3640 cache_info->metacontent=(void *) NULL;
3641 if (cache_info->metacontent_extent != 0)
3642 cache_info->metacontent=(void *) (cache_info->pixels+
3643 number_pixels*cache_info->number_channels);
3644 if ((source_info.storage_class != UndefinedClass) &&
3647 status=ClonePixelCacheRepository(cache_info,&source_info,
3649 RelinquishPixelCachePixels(&source_info);
3651 if (image->debug != MagickFalse)
3653 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3654 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3656 (void) FormatLocaleString(message,MaxTextExtent,
3657 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3658 cache_info->filename,cache_info->cache_filename,
3659 cache_info->file,type,(double) cache_info->columns,(double)
3660 cache_info->rows,(double) cache_info->number_channels,
3662 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3668 RelinquishMagickResource(MapResource,cache_info->length);
3671 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3673 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3674 RelinquishPixelCachePixels(&source_info);
3676 if (image->debug != MagickFalse)
3678 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3679 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3681 (void) FormatLocaleString(message,MaxTextExtent,
3682 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3683 cache_info->cache_filename,cache_info->file,type,(double)
3684 cache_info->columns,(double) cache_info->rows,(double)
3685 cache_info->number_channels,format);
3686 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3696 + P e r s i s t P i x e l C a c h e %
3700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3702 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3703 % persistent pixel cache is one that resides on disk and is not destroyed
3704 % when the program exits.
3706 % The format of the PersistPixelCache() method is:
3708 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3709 % const MagickBooleanType attach,MagickOffsetType *offset,
3710 % ExceptionInfo *exception)
3712 % A description of each parameter follows:
3714 % o image: the image.
3716 % o filename: the persistent pixel cache filename.
3718 % o attach: A value other than zero initializes the persistent pixel cache.
3720 % o initialize: A value other than zero initializes the persistent pixel
3723 % o offset: the offset in the persistent cache to store pixels.
3725 % o exception: return any errors or warnings in this structure.
3728 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3729 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3730 ExceptionInfo *exception)
3745 assert(image != (Image *) NULL);
3746 assert(image->signature == MagickSignature);
3747 if (image->debug != MagickFalse)
3748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3749 assert(image->cache != (void *) NULL);
3750 assert(filename != (const char *) NULL);
3751 assert(offset != (MagickOffsetType *) NULL);
3752 page_size=GetMagickPageSize();
3753 cache_info=(CacheInfo *) image->cache;
3754 assert(cache_info->signature == MagickSignature);
3755 if (attach != MagickFalse)
3758 Attach existing persistent pixel cache.
3760 if (image->debug != MagickFalse)
3761 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3762 "attach persistent cache");
3763 (void) CopyMagickString(cache_info->cache_filename,filename,
3765 cache_info->type=DiskCache;
3766 cache_info->offset=(*offset);
3767 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3768 return(MagickFalse);
3769 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3772 if ((cache_info->mode != ReadMode) &&
3773 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3774 (cache_info->reference_count == 1))
3776 LockSemaphoreInfo(cache_info->semaphore);
3777 if ((cache_info->mode != ReadMode) &&
3778 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3779 (cache_info->reference_count == 1))
3785 Usurp existing persistent pixel cache.
3787 status=rename_utf8(cache_info->cache_filename,filename);
3790 (void) CopyMagickString(cache_info->cache_filename,filename,
3792 *offset+=cache_info->length+page_size-(cache_info->length %
3794 UnlockSemaphoreInfo(cache_info->semaphore);
3795 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3796 if (image->debug != MagickFalse)
3797 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3798 "Usurp resident persistent cache");
3802 UnlockSemaphoreInfo(cache_info->semaphore);
3805 Clone persistent pixel cache.
3807 clone_image=(*image);
3808 clone_info=(CacheInfo *) clone_image.cache;
3809 image->cache=ClonePixelCache(cache_info);
3810 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3811 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3812 cache_info->type=DiskCache;
3813 cache_info->offset=(*offset);
3814 cache_info=(CacheInfo *) image->cache;
3815 status=OpenPixelCache(image,IOMode,exception);
3816 if (status != MagickFalse)
3817 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3818 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3819 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3828 + 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 %
3832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3834 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3835 % defined by the region rectangle and returns a pointer to the region. This
3836 % region is subsequently transferred from the pixel cache with
3837 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3838 % pixels are transferred, otherwise a NULL is returned.
3840 % The format of the QueueAuthenticPixelCacheNexus() method is:
3842 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3843 % const ssize_t y,const size_t columns,const size_t rows,
3844 % const MagickBooleanType clone,NexusInfo *nexus_info,
3845 % ExceptionInfo *exception)
3847 % A description of each parameter follows:
3849 % o image: the image.
3851 % o x,y,columns,rows: These values define the perimeter of a region of
3854 % o nexus_info: the cache nexus to set.
3856 % o clone: clone the pixel cache.
3858 % o exception: return any errors or warnings in this structure.
3861 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3862 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3863 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3881 Validate pixel cache geometry.
3883 assert(image != (const Image *) NULL);
3884 assert(image->signature == MagickSignature);
3885 assert(image->cache != (Cache) NULL);
3886 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3887 if (cache_info == (Cache) NULL)
3888 return((Quantum *) NULL);
3889 assert(cache_info->signature == MagickSignature);
3890 if ((cache_info->columns == 0) && (cache_info->rows == 0))
3892 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3893 "NoPixelsDefinedInCache","`%s'",image->filename);
3894 return((Quantum *) NULL);
3896 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3897 (y >= (ssize_t) cache_info->rows))
3899 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3900 "PixelsAreNotAuthentic","`%s'",image->filename);
3901 return((Quantum *) NULL);
3903 offset=(MagickOffsetType) y*cache_info->columns+x;
3905 return((Quantum *) NULL);
3906 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3907 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3908 if ((MagickSizeType) offset >= number_pixels)
3909 return((Quantum *) NULL);
3915 region.width=columns;
3917 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3927 + 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 %
3931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3933 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3934 % defined by the region rectangle and returns a pointer to the region. This
3935 % region is subsequently transferred from the pixel cache with
3936 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3937 % pixels are transferred, otherwise a NULL is returned.
3939 % The format of the QueueAuthenticPixelsCache() method is:
3941 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3942 % const ssize_t y,const size_t columns,const size_t rows,
3943 % ExceptionInfo *exception)
3945 % A description of each parameter follows:
3947 % o image: the image.
3949 % o x,y,columns,rows: These values define the perimeter of a region of
3952 % o exception: return any errors or warnings in this structure.
3955 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3956 const ssize_t y,const size_t columns,const size_t rows,
3957 ExceptionInfo *exception)
3963 id = GetOpenMPThreadId();
3968 assert(image != (const Image *) NULL);
3969 assert(image->signature == MagickSignature);
3970 assert(image->cache != (Cache) NULL);
3971 cache_info=(CacheInfo *) image->cache;
3972 assert(cache_info->signature == MagickSignature);
3973 assert(id < (int) cache_info->number_threads);
3974 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3975 cache_info->nexus_info[id],exception);
3980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3984 % Q u e u e A u t h e n t i c P i x e l s %
3988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3990 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3991 % successfully initialized a pointer to a Quantum array representing the
3992 % region is returned, otherwise NULL is returned. The returned pointer may
3993 % point to a temporary working buffer for the pixels or it may point to the
3994 % final location of the pixels in memory.
3996 % Write-only access means that any existing pixel values corresponding to
3997 % the region are ignored. This is useful if the initial image is being
3998 % created from scratch, or if the existing pixel values are to be
3999 % completely replaced without need to refer to their pre-existing values.
4000 % The application is free to read and write the pixel buffer returned by
4001 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4002 % initialize the pixel array values. Initializing pixel array values is the
4003 % application's responsibility.
4005 % Performance is maximized if the selected region is part of one row, or
4006 % one or more full rows, since then there is opportunity to access the
4007 % pixels in-place (without a copy) if the image is in memory, or in a
4008 % memory-mapped file. The returned pointer must *never* be deallocated
4011 % Pixels accessed via the returned pointer represent a simple array of type
4012 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4013 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4014 % obtain the meta-content (of type void) corresponding to the region.
4015 % Once the Quantum (and/or Quantum) array has been updated, the
4016 % changes must be saved back to the underlying image using
4017 % SyncAuthenticPixels() or they may be lost.
4019 % The format of the QueueAuthenticPixels() method is:
4021 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4022 % const ssize_t y,const size_t columns,const size_t rows,
4023 % ExceptionInfo *exception)
4025 % A description of each parameter follows:
4027 % o image: the image.
4029 % o x,y,columns,rows: These values define the perimeter of a region of
4032 % o exception: return any errors or warnings in this structure.
4035 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4036 const ssize_t y,const size_t columns,const size_t rows,
4037 ExceptionInfo *exception)
4043 id = GetOpenMPThreadId();
4048 assert(image != (Image *) NULL);
4049 assert(image->signature == MagickSignature);
4050 assert(image->cache != (Cache) NULL);
4051 cache_info=(CacheInfo *) image->cache;
4052 assert(cache_info->signature == MagickSignature);
4053 if (cache_info->methods.queue_authentic_pixels_handler !=
4054 (QueueAuthenticPixelsHandler) NULL)
4056 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4060 assert(id < (int) cache_info->number_threads);
4061 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4062 cache_info->nexus_info[id],exception);
4067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4071 + 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 %
4075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4077 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4080 % The format of the ReadPixelCacheMetacontent() method is:
4082 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4083 % NexusInfo *nexus_info,ExceptionInfo *exception)
4085 % A description of each parameter follows:
4087 % o cache_info: the pixel cache.
4089 % o nexus_info: the cache nexus to read the metacontent.
4091 % o exception: return any errors or warnings in this structure.
4095 static inline MagickOffsetType ReadPixelCacheRegion(
4096 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4097 const MagickSizeType length,unsigned char *restrict buffer)
4099 register MagickOffsetType
4105 #if !defined(MAGICKCORE_HAVE_PREAD)
4106 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4107 return((MagickOffsetType) -1);
4110 for (i=0; i < (MagickOffsetType) length; i+=count)
4112 #if !defined(MAGICKCORE_HAVE_PREAD)
4113 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4114 (MagickSizeType) SSIZE_MAX));
4116 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4117 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4129 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4130 NexusInfo *nexus_info,ExceptionInfo *exception)
4143 register unsigned char
4149 if (cache_info->metacontent_extent == 0)
4150 return(MagickFalse);
4151 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4153 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4154 nexus_info->region.x;
4155 length=(MagickSizeType) nexus_info->region.width*
4156 cache_info->metacontent_extent;
4157 extent=length*nexus_info->region.height;
4158 rows=nexus_info->region.height;
4160 q=(unsigned char *) nexus_info->metacontent;
4161 switch (cache_info->type)
4166 register unsigned char
4170 Read meta-content from memory.
4172 if ((cache_info->columns == nexus_info->region.width) &&
4173 (extent == (MagickSizeType) ((size_t) extent)))
4178 p=(unsigned char *) cache_info->metacontent+offset*
4179 cache_info->metacontent_extent;
4180 for (y=0; y < (ssize_t) rows; y++)
4182 (void) memcpy(q,p,(size_t) length);
4183 p+=cache_info->metacontent_extent*cache_info->columns;
4184 q+=cache_info->metacontent_extent*nexus_info->region.width;
4191 Read meta content from disk.
4193 LockSemaphoreInfo(cache_info->file_semaphore);
4194 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4196 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4197 cache_info->cache_filename);
4198 UnlockSemaphoreInfo(cache_info->file_semaphore);
4199 return(MagickFalse);
4201 if ((cache_info->columns == nexus_info->region.width) &&
4202 (extent <= MagickMaxBufferExtent))
4207 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4208 for (y=0; y < (ssize_t) rows; y++)
4210 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4211 cache_info->number_channels*sizeof(Quantum)+offset*
4212 cache_info->metacontent_extent,length,(unsigned char *) q);
4213 if (count != (MagickOffsetType) length)
4215 offset+=cache_info->columns;
4216 q+=cache_info->metacontent_extent*nexus_info->region.width;
4218 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4219 (void) ClosePixelCacheOnDisk(cache_info);
4220 UnlockSemaphoreInfo(cache_info->file_semaphore);
4223 case DistributedCache:
4229 Read metacontent from distributed cache.
4231 LockSemaphoreInfo(cache_info->file_semaphore);
4232 region=nexus_info->region;
4233 if ((cache_info->columns != nexus_info->region.width) ||
4234 (extent > MagickMaxBufferExtent))
4241 for (y=0; y < (ssize_t) rows; y++)
4243 count=ReadDistributePixelCacheMetacontent(cache_info->server_info,
4244 ®ion,length,(unsigned char *) q);
4245 if (count != (MagickOffsetType) length)
4247 q+=cache_info->metacontent_extent*nexus_info->region.width;
4250 UnlockSemaphoreInfo(cache_info->file_semaphore);
4256 if (y < (ssize_t) rows)
4258 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4259 cache_info->cache_filename);
4260 return(MagickFalse);
4262 if ((cache_info->debug != MagickFalse) &&
4263 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4264 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4265 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4266 nexus_info->region.width,(double) nexus_info->region.height,(double)
4267 nexus_info->region.x,(double) nexus_info->region.y);
4272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4276 + R e a d P i x e l C a c h e P i x e l s %
4280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4282 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4285 % The format of the ReadPixelCachePixels() method is:
4287 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4288 % NexusInfo *nexus_info,ExceptionInfo *exception)
4290 % A description of each parameter follows:
4292 % o cache_info: the pixel cache.
4294 % o nexus_info: the cache nexus to read the pixels.
4296 % o exception: return any errors or warnings in this structure.
4299 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4300 NexusInfo *nexus_info,ExceptionInfo *exception)
4319 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4321 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4322 nexus_info->region.x;
4323 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4325 extent=length*nexus_info->region.height;
4326 rows=nexus_info->region.height;
4328 q=nexus_info->pixels;
4329 switch (cache_info->type)
4338 Read pixels from memory.
4340 if ((cache_info->columns == nexus_info->region.width) &&
4341 (extent == (MagickSizeType) ((size_t) extent)))
4346 p=cache_info->pixels+offset*cache_info->number_channels;
4347 for (y=0; y < (ssize_t) rows; y++)
4349 (void) memcpy(q,p,(size_t) length);
4350 p+=cache_info->number_channels*cache_info->columns;
4351 q+=cache_info->number_channels*nexus_info->region.width;
4358 Read pixels from disk.
4360 LockSemaphoreInfo(cache_info->file_semaphore);
4361 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4363 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4364 cache_info->cache_filename);
4365 UnlockSemaphoreInfo(cache_info->file_semaphore);
4366 return(MagickFalse);
4368 if ((cache_info->columns == nexus_info->region.width) &&
4369 (extent <= MagickMaxBufferExtent))
4374 for (y=0; y < (ssize_t) rows; y++)
4376 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4377 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4378 if (count != (MagickOffsetType) length)
4380 offset+=cache_info->columns;
4381 q+=cache_info->number_channels*nexus_info->region.width;
4383 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4384 (void) ClosePixelCacheOnDisk(cache_info);
4385 UnlockSemaphoreInfo(cache_info->file_semaphore);
4388 case DistributedCache:
4394 Read pixels from distributed cache.
4396 LockSemaphoreInfo(cache_info->file_semaphore);
4397 region=nexus_info->region;
4398 if ((cache_info->columns != nexus_info->region.width) ||
4399 (extent > MagickMaxBufferExtent))
4406 for (y=0; y < (ssize_t) rows; y++)
4408 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4409 length,(unsigned char *) q);
4410 if (count != (MagickOffsetType) length)
4412 q+=cache_info->number_channels*nexus_info->region.width;
4415 UnlockSemaphoreInfo(cache_info->file_semaphore);
4421 if (y < (ssize_t) rows)
4423 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4424 cache_info->cache_filename);
4425 return(MagickFalse);
4427 if ((cache_info->debug != MagickFalse) &&
4428 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4429 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4430 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4431 nexus_info->region.width,(double) nexus_info->region.height,(double)
4432 nexus_info->region.x,(double) nexus_info->region.y);
4437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4441 + R e f e r e n c e P i x e l C a c h e %
4445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447 % ReferencePixelCache() increments the reference count associated with the
4448 % pixel cache returning a pointer to the cache.
4450 % The format of the ReferencePixelCache method is:
4452 % Cache ReferencePixelCache(Cache cache_info)
4454 % A description of each parameter follows:
4456 % o cache_info: the pixel cache.
4459 MagickPrivate Cache ReferencePixelCache(Cache cache)
4464 assert(cache != (Cache *) NULL);
4465 cache_info=(CacheInfo *) cache;
4466 assert(cache_info->signature == MagickSignature);
4467 LockSemaphoreInfo(cache_info->semaphore);
4468 cache_info->reference_count++;
4469 UnlockSemaphoreInfo(cache_info->semaphore);
4474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4478 + S e t P i x e l C a c h e M e t h o d s %
4482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4484 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4486 % The format of the SetPixelCacheMethods() method is:
4488 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4490 % A description of each parameter follows:
4492 % o cache: the pixel cache.
4494 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4497 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4502 GetOneAuthenticPixelFromHandler
4503 get_one_authentic_pixel_from_handler;
4505 GetOneVirtualPixelFromHandler
4506 get_one_virtual_pixel_from_handler;
4509 Set cache pixel methods.
4511 assert(cache != (Cache) NULL);
4512 assert(cache_methods != (CacheMethods *) NULL);
4513 cache_info=(CacheInfo *) cache;
4514 assert(cache_info->signature == MagickSignature);
4515 if (cache_info->debug != MagickFalse)
4516 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4517 cache_info->filename);
4518 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4519 cache_info->methods.get_virtual_pixel_handler=
4520 cache_methods->get_virtual_pixel_handler;
4521 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4522 cache_info->methods.destroy_pixel_handler=
4523 cache_methods->destroy_pixel_handler;
4524 if (cache_methods->get_virtual_metacontent_from_handler !=
4525 (GetVirtualMetacontentFromHandler) NULL)
4526 cache_info->methods.get_virtual_metacontent_from_handler=
4527 cache_methods->get_virtual_metacontent_from_handler;
4528 if (cache_methods->get_authentic_pixels_handler !=
4529 (GetAuthenticPixelsHandler) NULL)
4530 cache_info->methods.get_authentic_pixels_handler=
4531 cache_methods->get_authentic_pixels_handler;
4532 if (cache_methods->queue_authentic_pixels_handler !=
4533 (QueueAuthenticPixelsHandler) NULL)
4534 cache_info->methods.queue_authentic_pixels_handler=
4535 cache_methods->queue_authentic_pixels_handler;
4536 if (cache_methods->sync_authentic_pixels_handler !=
4537 (SyncAuthenticPixelsHandler) NULL)
4538 cache_info->methods.sync_authentic_pixels_handler=
4539 cache_methods->sync_authentic_pixels_handler;
4540 if (cache_methods->get_authentic_pixels_from_handler !=
4541 (GetAuthenticPixelsFromHandler) NULL)
4542 cache_info->methods.get_authentic_pixels_from_handler=
4543 cache_methods->get_authentic_pixels_from_handler;
4544 if (cache_methods->get_authentic_metacontent_from_handler !=
4545 (GetAuthenticMetacontentFromHandler) NULL)
4546 cache_info->methods.get_authentic_metacontent_from_handler=
4547 cache_methods->get_authentic_metacontent_from_handler;
4548 get_one_virtual_pixel_from_handler=
4549 cache_info->methods.get_one_virtual_pixel_from_handler;
4550 if (get_one_virtual_pixel_from_handler !=
4551 (GetOneVirtualPixelFromHandler) NULL)
4552 cache_info->methods.get_one_virtual_pixel_from_handler=
4553 cache_methods->get_one_virtual_pixel_from_handler;
4554 get_one_authentic_pixel_from_handler=
4555 cache_methods->get_one_authentic_pixel_from_handler;
4556 if (get_one_authentic_pixel_from_handler !=
4557 (GetOneAuthenticPixelFromHandler) NULL)
4558 cache_info->methods.get_one_authentic_pixel_from_handler=
4559 cache_methods->get_one_authentic_pixel_from_handler;
4563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4567 + S e t P i x e l C a c h e N e x u s P i x e l s %
4571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4573 % SetPixelCacheNexusPixels() defines the region of the cache for the
4574 % specified cache nexus.
4576 % The format of the SetPixelCacheNexusPixels() method is:
4578 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4579 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4580 % ExceptionInfo *exception)
4582 % A description of each parameter follows:
4584 % o cache_info: the pixel cache.
4586 % o mode: ReadMode, WriteMode, or IOMode.
4588 % o region: A pointer to the RectangleInfo structure that defines the
4589 % region of this particular cache nexus.
4591 % o nexus_info: the cache nexus to set.
4593 % o exception: return any errors or warnings in this structure.
4597 static inline MagickBooleanType AcquireCacheNexusPixels(
4598 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4599 ExceptionInfo *exception)
4601 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4602 return(MagickFalse);
4603 nexus_info->mapped=MagickFalse;
4604 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4605 (size_t) nexus_info->length));
4606 if (nexus_info->cache == (Quantum *) NULL)
4608 nexus_info->mapped=MagickTrue;
4609 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4610 nexus_info->length);
4612 if (nexus_info->cache == (Quantum *) NULL)
4614 (void) ThrowMagickException(exception,GetMagickModule(),
4615 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4616 cache_info->filename);
4617 return(MagickFalse);
4622 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4625 if (mode == ReadMode)
4627 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4630 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4633 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4634 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4635 ExceptionInfo *exception)
4644 assert(cache_info != (const CacheInfo *) NULL);
4645 assert(cache_info->signature == MagickSignature);
4646 if (cache_info->type == UndefinedCache)
4647 return((Quantum *) NULL);
4648 nexus_info->region=(*region);
4649 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4655 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4656 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4657 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4658 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4659 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4660 ((nexus_info->region.width == cache_info->columns) ||
4661 ((nexus_info->region.width % cache_info->columns) == 0)))))
4667 Pixels are accessed directly from memory.
4669 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4670 nexus_info->region.x;
4671 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4673 nexus_info->metacontent=(void *) NULL;
4674 if (cache_info->metacontent_extent != 0)
4675 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4676 offset*cache_info->metacontent_extent;
4677 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4678 return(nexus_info->pixels);
4682 Pixels are stored in a cache region until they are synced to the cache.
4684 number_pixels=(MagickSizeType) nexus_info->region.width*
4685 nexus_info->region.height;
4686 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4687 if (cache_info->metacontent_extent != 0)
4688 length+=number_pixels*cache_info->metacontent_extent;
4689 if (nexus_info->cache == (Quantum *) NULL)
4691 nexus_info->length=length;
4692 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4693 if (status == MagickFalse)
4695 nexus_info->length=0;
4696 return((Quantum *) NULL);
4700 if (nexus_info->length != length)
4702 RelinquishCacheNexusPixels(nexus_info);
4703 nexus_info->length=length;
4704 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4705 if (status == MagickFalse)
4707 nexus_info->length=0;
4708 return((Quantum *) NULL);
4711 nexus_info->pixels=nexus_info->cache;
4712 nexus_info->metacontent=(void *) NULL;
4713 if (cache_info->metacontent_extent != 0)
4714 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4715 cache_info->number_channels);
4716 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4717 return(nexus_info->pixels);
4721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4725 % 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 %
4729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4731 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4732 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4733 % access that is outside the boundaries of the image cache.
4735 % The format of the SetPixelCacheVirtualMethod() method is:
4737 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4738 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4740 % A description of each parameter follows:
4742 % o image: the image.
4744 % o virtual_pixel_method: choose the type of virtual pixel.
4746 % o exception: return any errors or warnings in this structure.
4750 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4751 ExceptionInfo *exception)
4765 assert(image != (Image *) NULL);
4766 assert(image->signature == MagickSignature);
4767 if (image->debug != MagickFalse)
4768 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4769 assert(image->cache != (Cache) NULL);
4770 cache_info=(CacheInfo *) image->cache;
4771 assert(cache_info->signature == MagickSignature);
4772 image->alpha_trait=BlendPixelTrait;
4774 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4775 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4776 #pragma omp parallel for schedule(static,4) shared(status) \
4777 magick_threads(image,image,1,1)
4779 for (y=0; y < (ssize_t) image->rows; y++)
4787 if (status == MagickFalse)
4789 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4790 if (q == (Quantum *) NULL)
4795 for (x=0; x < (ssize_t) image->columns; x++)
4797 SetPixelAlpha(image,alpha,q);
4798 q+=GetPixelChannels(image);
4800 status=SyncCacheViewAuthenticPixels(image_view,exception);
4802 image_view=DestroyCacheView(image_view);
4806 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4807 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4815 assert(image != (Image *) NULL);
4816 assert(image->signature == MagickSignature);
4817 if (image->debug != MagickFalse)
4818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4819 assert(image->cache != (Cache) NULL);
4820 cache_info=(CacheInfo *) image->cache;
4821 assert(cache_info->signature == MagickSignature);
4822 method=cache_info->virtual_pixel_method;
4823 cache_info->virtual_pixel_method=virtual_pixel_method;
4824 if ((image->columns != 0) && (image->rows != 0))
4825 switch (virtual_pixel_method)
4827 case BackgroundVirtualPixelMethod:
4829 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4830 (image->alpha_trait != BlendPixelTrait))
4831 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4832 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4833 (IsGrayColorspace(image->colorspace) != MagickFalse))
4834 (void) TransformImageColorspace(image,RGBColorspace,exception);
4837 case TransparentVirtualPixelMethod:
4839 if (image->alpha_trait != BlendPixelTrait)
4840 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4854 + 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 %
4858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4860 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4861 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4862 % is synced, otherwise MagickFalse.
4864 % The format of the SyncAuthenticPixelCacheNexus() method is:
4866 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4867 % NexusInfo *nexus_info,ExceptionInfo *exception)
4869 % A description of each parameter follows:
4871 % o image: the image.
4873 % o nexus_info: the cache nexus to sync.
4875 % o exception: return any errors or warnings in this structure.
4878 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4879 NexusInfo *nexus_info,ExceptionInfo *exception)
4888 Transfer pixels to the cache.
4890 assert(image != (Image *) NULL);
4891 assert(image->signature == MagickSignature);
4892 if (image->cache == (Cache) NULL)
4893 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4894 cache_info=(CacheInfo *) image->cache;
4895 assert(cache_info->signature == MagickSignature);
4896 if (cache_info->type == UndefinedCache)
4897 return(MagickFalse);
4898 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4900 assert(cache_info->signature == MagickSignature);
4901 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4902 if ((cache_info->metacontent_extent != 0) &&
4903 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4904 return(MagickFalse);
4909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4913 + S y n c A u t h e n t i c P i x e l C a c h e %
4917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4919 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4920 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4921 % otherwise MagickFalse.
4923 % The format of the SyncAuthenticPixelsCache() method is:
4925 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4926 % ExceptionInfo *exception)
4928 % A description of each parameter follows:
4930 % o image: the image.
4932 % o exception: return any errors or warnings in this structure.
4935 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4936 ExceptionInfo *exception)
4942 id = GetOpenMPThreadId();
4947 assert(image != (Image *) NULL);
4948 assert(image->signature == MagickSignature);
4949 assert(image->cache != (Cache) NULL);
4950 cache_info=(CacheInfo *) image->cache;
4951 assert(cache_info->signature == MagickSignature);
4952 assert(id < (int) cache_info->number_threads);
4953 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4963 % S y n c A u t h e n t i c P i x e l s %
4967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4969 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4970 % The method returns MagickTrue if the pixel region is flushed, otherwise
4973 % The format of the SyncAuthenticPixels() method is:
4975 % MagickBooleanType SyncAuthenticPixels(Image *image,
4976 % ExceptionInfo *exception)
4978 % A description of each parameter follows:
4980 % o image: the image.
4982 % o exception: return any errors or warnings in this structure.
4985 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4986 ExceptionInfo *exception)
4992 id = GetOpenMPThreadId();
4997 assert(image != (Image *) NULL);
4998 assert(image->signature == MagickSignature);
4999 assert(image->cache != (Cache) NULL);
5000 cache_info=(CacheInfo *) image->cache;
5001 assert(cache_info->signature == MagickSignature);
5002 if (cache_info->methods.sync_authentic_pixels_handler !=
5003 (SyncAuthenticPixelsHandler) NULL)
5005 status=cache_info->methods.sync_authentic_pixels_handler(image,
5009 assert(id < (int) cache_info->number_threads);
5010 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5020 + S y n c I m a g e P i x e l C a c h e %
5024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5026 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5027 % The method returns MagickTrue if the pixel region is flushed, otherwise
5030 % The format of the SyncImagePixelCache() method is:
5032 % MagickBooleanType SyncImagePixelCache(Image *image,
5033 % ExceptionInfo *exception)
5035 % A description of each parameter follows:
5037 % o image: the image.
5039 % o exception: return any errors or warnings in this structure.
5042 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5043 ExceptionInfo *exception)
5048 assert(image != (Image *) NULL);
5049 assert(exception != (ExceptionInfo *) NULL);
5050 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5051 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5059 + 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 %
5063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5065 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5066 % of the pixel cache.
5068 % The format of the WritePixelCacheMetacontent() method is:
5070 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5071 % NexusInfo *nexus_info,ExceptionInfo *exception)
5073 % A description of each parameter follows:
5075 % o cache_info: the pixel cache.
5077 % o nexus_info: the cache nexus to write the meta-content.
5079 % o exception: return any errors or warnings in this structure.
5082 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5083 NexusInfo *nexus_info,ExceptionInfo *exception)
5093 register const unsigned char
5102 if (cache_info->metacontent_extent == 0)
5103 return(MagickFalse);
5104 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5106 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5107 nexus_info->region.x;
5108 length=(MagickSizeType) nexus_info->region.width*
5109 cache_info->metacontent_extent;
5110 extent=(MagickSizeType) length*nexus_info->region.height;
5111 rows=nexus_info->region.height;
5113 p=(unsigned char *) nexus_info->metacontent;
5114 switch (cache_info->type)
5119 register unsigned char
5123 Write associated pixels to memory.
5125 if ((cache_info->columns == nexus_info->region.width) &&
5126 (extent == (MagickSizeType) ((size_t) extent)))
5131 q=(unsigned char *) cache_info->metacontent+offset*
5132 cache_info->metacontent_extent;
5133 for (y=0; y < (ssize_t) rows; y++)
5135 (void) memcpy(q,p,(size_t) length);
5136 p+=nexus_info->region.width*cache_info->metacontent_extent;
5137 q+=cache_info->columns*cache_info->metacontent_extent;
5144 Write associated pixels to disk.
5146 LockSemaphoreInfo(cache_info->file_semaphore);
5147 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5149 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5150 cache_info->cache_filename);
5151 UnlockSemaphoreInfo(cache_info->file_semaphore);
5152 return(MagickFalse);
5154 if ((cache_info->columns == nexus_info->region.width) &&
5155 (extent <= MagickMaxBufferExtent))
5160 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5161 for (y=0; y < (ssize_t) rows; y++)
5163 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5164 cache_info->number_channels*sizeof(Quantum)+offset*
5165 cache_info->metacontent_extent,length,(const unsigned char *) p);
5166 if (count != (MagickOffsetType) length)
5168 p+=cache_info->metacontent_extent*nexus_info->region.width;
5169 offset+=cache_info->columns;
5171 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5172 (void) ClosePixelCacheOnDisk(cache_info);
5173 UnlockSemaphoreInfo(cache_info->file_semaphore);
5176 case DistributedCache:
5182 Write metacontent to distributed cache.
5184 LockSemaphoreInfo(cache_info->file_semaphore);
5185 region=nexus_info->region;
5186 if ((cache_info->columns != nexus_info->region.width) ||
5187 (extent > MagickMaxBufferExtent))
5194 for (y=0; y < (ssize_t) rows; y++)
5196 count=WriteDistributePixelCacheMetacontent(cache_info->server_info,
5197 ®ion,length,(const unsigned char *) p);
5198 if (count != (MagickOffsetType) length)
5200 p+=cache_info->metacontent_extent*nexus_info->region.width;
5203 UnlockSemaphoreInfo(cache_info->file_semaphore);
5209 if (y < (ssize_t) rows)
5211 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5212 cache_info->cache_filename);
5213 return(MagickFalse);
5215 if ((cache_info->debug != MagickFalse) &&
5216 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5218 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5219 nexus_info->region.width,(double) nexus_info->region.height,(double)
5220 nexus_info->region.x,(double) nexus_info->region.y);
5225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5229 + W r i t e C a c h e P i x e l s %
5233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5235 % WritePixelCachePixels() writes image pixels to the specified region of the
5238 % The format of the WritePixelCachePixels() method is:
5240 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5241 % NexusInfo *nexus_info,ExceptionInfo *exception)
5243 % A description of each parameter follows:
5245 % o cache_info: the pixel cache.
5247 % o nexus_info: the cache nexus to write the pixels.
5249 % o exception: return any errors or warnings in this structure.
5252 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5253 NexusInfo *nexus_info,ExceptionInfo *exception)
5263 register const Quantum
5272 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5274 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5275 nexus_info->region.x;
5276 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5278 extent=length*nexus_info->region.height;
5279 rows=nexus_info->region.height;
5281 p=nexus_info->pixels;
5282 switch (cache_info->type)
5291 Write pixels to memory.
5293 if ((cache_info->columns == nexus_info->region.width) &&
5294 (extent == (MagickSizeType) ((size_t) extent)))
5299 q=cache_info->pixels+offset*cache_info->number_channels;
5300 for (y=0; y < (ssize_t) rows; y++)
5302 (void) memcpy(q,p,(size_t) length);
5303 p+=cache_info->number_channels*nexus_info->region.width;
5304 q+=cache_info->columns*cache_info->number_channels;
5311 Write pixels to disk.
5313 LockSemaphoreInfo(cache_info->file_semaphore);
5314 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5316 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5317 cache_info->cache_filename);
5318 UnlockSemaphoreInfo(cache_info->file_semaphore);
5319 return(MagickFalse);
5321 if ((cache_info->columns == nexus_info->region.width) &&
5322 (extent <= MagickMaxBufferExtent))
5327 for (y=0; y < (ssize_t) rows; y++)
5329 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5330 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5332 if (count != (MagickOffsetType) length)
5334 p+=cache_info->number_channels*nexus_info->region.width;
5335 offset+=cache_info->columns;
5337 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5338 (void) ClosePixelCacheOnDisk(cache_info);
5339 UnlockSemaphoreInfo(cache_info->file_semaphore);
5342 case DistributedCache:
5348 Write pixels to distributed cache.
5350 LockSemaphoreInfo(cache_info->file_semaphore);
5351 region=nexus_info->region;
5352 if ((cache_info->columns != nexus_info->region.width) ||
5353 (extent > MagickMaxBufferExtent))
5360 for (y=0; y < (ssize_t) rows; y++)
5362 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5363 length,(const unsigned char *) p);
5364 if (count != (MagickOffsetType) length)
5366 p+=cache_info->number_channels*nexus_info->region.width;
5369 UnlockSemaphoreInfo(cache_info->file_semaphore);
5375 if (y < (ssize_t) rows)
5377 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5378 cache_info->cache_filename);
5379 return(MagickFalse);
5381 if ((cache_info->debug != MagickFalse) &&
5382 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5383 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5384 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5385 nexus_info->region.width,(double) nexus_info->region.height,(double)
5386 nexus_info->region.x,(double) nexus_info->region.y);