2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
120 Forward declarations.
122 #if defined(__cplusplus) || defined(c_plusplus)
127 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
131 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
132 const ssize_t,const size_t,const size_t,ExceptionInfo *),
133 *GetVirtualPixelsCache(const Image *);
136 *GetVirtualMetacontentFromCache(const Image *);
138 static MagickBooleanType
139 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
141 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
142 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
143 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
144 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
146 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
147 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
148 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
151 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
152 const size_t,ExceptionInfo *),
153 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
154 const size_t,ExceptionInfo *),
155 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
156 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
158 #if defined(__cplusplus) || defined(c_plusplus)
165 static volatile MagickBooleanType
166 instantiate_cache = MagickFalse;
169 *cache_semaphore = (SemaphoreInfo *) NULL;
172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 + A c q u i r e P i x e l C a c h e %
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 % AcquirePixelCache() acquires a pixel cache.
184 % The format of the AcquirePixelCache() method is:
186 % Cache AcquirePixelCache(const size_t number_threads)
188 % A description of each parameter follows:
190 % o number_threads: the number of nexus threads.
193 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
201 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
202 if (cache_info == (CacheInfo *) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
205 cache_info->type=UndefinedCache;
206 cache_info->mode=IOMode;
207 cache_info->colorspace=sRGBColorspace;
208 cache_info->file=(-1);
209 cache_info->id=GetMagickThreadId();
210 cache_info->number_threads=number_threads;
211 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
212 cache_info->number_threads=GetOpenMPMaximumThreads();
213 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
214 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
215 if (cache_info->number_threads == 0)
216 cache_info->number_threads=1;
217 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
218 if (cache_info->nexus_info == (NexusInfo **) NULL)
219 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
220 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
221 if (synchronize != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(synchronize);
224 synchronize=DestroyString(synchronize);
226 cache_info->semaphore=AllocateSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AllocateSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickSignature;
231 return((Cache ) cache_info);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % A c q u i r e P i x e l C a c h e N e x u s %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
247 % The format of the AcquirePixelCacheNexus method is:
249 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 % A description of each parameter follows:
253 % o number_threads: the number of nexus threads.
256 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
264 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
265 number_threads,sizeof(*nexus_info)));
266 if (nexus_info == (NexusInfo **) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
269 sizeof(**nexus_info));
270 if (nexus_info[0] == (NexusInfo *) NULL)
271 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
272 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
273 for (i=0; i < (ssize_t) number_threads; i++)
275 nexus_info[i]=(&nexus_info[0][i]);
276 nexus_info[i]->signature=MagickSignature;
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 + A c q u i r e P i x e l C a c h e P i x e l s %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % AcquirePixelCachePixels() returns the pixels associated with the specified
295 % The format of the AcquirePixelCachePixels() method is:
297 % const void *AcquirePixelCachePixels(const Image *image,
298 % MagickSizeType *length,ExceptionInfo *exception)
300 % A description of each parameter follows:
302 % o image: the image.
304 % o length: the pixel cache length.
306 % o exception: return any errors or warnings in this structure.
309 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
310 MagickSizeType *length,ExceptionInfo *exception)
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickSignature);
323 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
324 return((const void *) NULL);
325 *length=cache_info->length;
326 return((const void *) cache_info->pixels);
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 + C a c h e C o m p o n e n t G e n e s i s %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % CacheComponentGenesis() instantiates the cache component.
342 % The format of the CacheComponentGenesis method is:
344 % MagickBooleanType CacheComponentGenesis(void)
347 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
349 AcquireSemaphoreInfo(&cache_semaphore);
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 + C a c h e C o m p o n e n t T e r m i n u s %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 % CacheComponentTerminus() destroys the cache component.
366 % The format of the CacheComponentTerminus() method is:
368 % CacheComponentTerminus(void)
371 MagickPrivate void CacheComponentTerminus(void)
373 if (cache_semaphore == (SemaphoreInfo *) NULL)
374 AcquireSemaphoreInfo(&cache_semaphore);
375 LockSemaphoreInfo(cache_semaphore);
376 instantiate_cache=MagickFalse;
377 UnlockSemaphoreInfo(cache_semaphore);
378 DestroySemaphoreInfo(&cache_semaphore);
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 + C l o n e P i x e l C a c h e %
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 % ClonePixelCache() clones a pixel cache.
394 % The format of the ClonePixelCache() method is:
396 % Cache ClonePixelCache(const Cache cache)
398 % A description of each parameter follows:
400 % o cache: the pixel cache.
403 MagickPrivate Cache ClonePixelCache(const Cache cache)
411 assert(cache != NULL);
412 cache_info=(const CacheInfo *) cache;
413 assert(cache_info->signature == MagickSignature);
414 if (cache_info->debug != MagickFalse)
415 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
416 cache_info->filename);
417 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
418 if (clone_info == (Cache) NULL)
419 return((Cache) NULL);
420 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
421 return((Cache ) clone_info);
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 + C l o n e P i x e l C a c h e M e t h o d s %
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
438 % The format of the ClonePixelCacheMethods() method is:
440 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
442 % A description of each parameter follows:
444 % o clone: Specifies a pointer to a Cache structure.
446 % o cache: the pixel cache.
449 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
455 assert(clone != (Cache) NULL);
456 source_info=(CacheInfo *) clone;
457 assert(source_info->signature == MagickSignature);
458 if (source_info->debug != MagickFalse)
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
460 source_info->filename);
461 assert(cache != (Cache) NULL);
462 cache_info=(CacheInfo *) cache;
463 assert(cache_info->signature == MagickSignature);
464 source_info->methods=cache_info->methods;
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 + C l o n e P i x e l C a c h e R e p o s i t o r y %
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
477 % ClonePixelCacheRepository() clones the source pixel cache to the destination
480 % The format of the ClonePixelCacheRepository() method is:
482 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
483 % CacheInfo *source_info,ExceptionInfo *exception)
485 % A description of each parameter follows:
487 % o cache_info: the pixel cache.
489 % o source_info: the source pixel cache.
491 % o exception: return any errors or warnings in this structure.
495 static inline MagickSizeType MagickMin(const MagickSizeType x,
496 const MagickSizeType y)
503 static MagickBooleanType ClonePixelCacheRepository(CacheInfo *clone_info,
504 CacheInfo *cache_info,ExceptionInfo *exception)
506 #define MaxCacheThreads 2
507 #define cache_threads(source,destination,chunk) \
508 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
509 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
510 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
526 assert(cache_info != (CacheInfo *) NULL);
527 assert(clone_info != (CacheInfo *) NULL);
528 assert(exception != (ExceptionInfo *) NULL);
529 if (cache_info->type == PingCache)
531 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
532 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
533 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
534 (cache_info->columns == clone_info->columns) &&
535 (cache_info->rows == clone_info->rows) &&
536 (cache_info->number_channels == clone_info->number_channels) &&
537 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
538 (cache_info->metacontent_extent == clone_info->metacontent_extent))
541 Identical pixel cache morphology.
543 (void) memcpy(clone_info->pixels,cache_info->pixels,cache_info->columns*
544 cache_info->number_channels*cache_info->rows*
545 sizeof(*cache_info->pixels));
546 if (cache_info->metacontent_extent != 0)
547 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
548 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
549 sizeof(cache_info->metacontent));
553 Mismatched pixel cache morphology.
555 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
556 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
557 if ((cache_nexus == (NexusInfo **) NULL) ||
558 (clone_nexus == (NexusInfo **) NULL))
559 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
560 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
561 optimize=(cache_info->number_channels == clone_info->number_channels) &&
562 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
563 MagickTrue : MagickFalse;
564 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
565 clone_info->columns*clone_info->number_channels);
567 #if defined(MAGICKCORE_OPENMP_SUPPORT)
568 #pragma omp parallel for schedule(static,4) shared(status) \
569 cache_threads(cache_info,clone_info,cache_info->rows)
571 for (y=0; y < (ssize_t) cache_info->rows; y++)
574 id = GetOpenMPThreadId();
585 if (status == MagickFalse)
587 if (y >= (ssize_t) clone_info->rows)
589 region.width=cache_info->columns;
593 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
595 if (pixels == (Quantum *) NULL)
597 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
598 if (status == MagickFalse)
600 region.width=clone_info->columns;
601 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
602 clone_nexus[id],exception);
603 if (pixels == (Quantum *) NULL)
605 if (optimize != MagickFalse)
606 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
610 register const Quantum
617 Mismatched pixel channel map.
619 p=cache_nexus[id]->pixels;
620 q=clone_nexus[id]->pixels;
621 for (x=0; x < (ssize_t) cache_info->columns; x++)
626 if (x == (ssize_t) clone_info->columns)
628 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
636 channel=clone_info->channel_map[i].channel;
637 traits=cache_info->channel_map[channel].traits;
638 if (traits != UndefinedPixelTrait)
639 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
643 p+=cache_info->number_channels;
646 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
648 if ((cache_info->metacontent_extent != 0) &&
649 (clone_info->metacontent_extent != 0))
654 length=(size_t) MagickMin(cache_info->metacontent_extent,
655 clone_info->metacontent_extent);
656 #if defined(MAGICKCORE_OPENMP_SUPPORT)
657 #pragma omp parallel for schedule(static,4) shared(status) \
658 cache_threads(cache_info,clone_info,cache_info->rows)
660 for (y=0; y < (ssize_t) cache_info->rows; y++)
663 id = GetOpenMPThreadId();
671 if (status == MagickFalse)
673 if (y >= (ssize_t) clone_info->rows)
675 region.width=cache_info->columns;
679 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
680 cache_nexus[id],exception);
681 if (pixels == (Quantum *) NULL)
683 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
684 if (status == MagickFalse)
686 region.width=clone_info->columns;
687 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
688 clone_nexus[id],exception);
689 if (pixels == (Quantum *) NULL)
691 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
692 length*sizeof(cache_nexus[id]->metacontent));
693 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
696 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
697 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
698 if (cache_info->debug != MagickFalse)
701 message[MaxTextExtent];
703 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
704 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
705 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 + D e s t r o y I m a g e P i x e l C a c h e %
720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
724 % The format of the DestroyImagePixelCache() method is:
726 % void DestroyImagePixelCache(Image *image)
728 % A description of each parameter follows:
730 % o image: the image.
733 static void DestroyImagePixelCache(Image *image)
735 assert(image != (Image *) NULL);
736 assert(image->signature == MagickSignature);
737 if (image->debug != MagickFalse)
738 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
739 if (image->cache == (void *) NULL)
741 image->cache=DestroyPixelCache(image->cache);
745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749 + D e s t r o y I m a g e P i x e l s %
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755 % DestroyImagePixels() deallocates memory associated with the pixel cache.
757 % The format of the DestroyImagePixels() method is:
759 % void DestroyImagePixels(Image *image)
761 % A description of each parameter follows:
763 % o image: the image.
766 MagickExport void DestroyImagePixels(Image *image)
771 assert(image != (const Image *) NULL);
772 assert(image->signature == MagickSignature);
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
775 assert(image->cache != (Cache) NULL);
776 cache_info=(CacheInfo *) image->cache;
777 assert(cache_info->signature == MagickSignature);
778 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
780 cache_info->methods.destroy_pixel_handler(image);
783 image->cache=DestroyPixelCache(image->cache);
787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
791 + D e s t r o y P i x e l C a c h e %
795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797 % DestroyPixelCache() deallocates memory associated with the pixel cache.
799 % The format of the DestroyPixelCache() method is:
801 % Cache DestroyPixelCache(Cache cache)
803 % A description of each parameter follows:
805 % o cache: the pixel cache.
809 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
815 if (cache_info->file != -1)
817 status=close(cache_info->file);
818 cache_info->file=(-1);
819 RelinquishMagickResource(FileResource,1);
821 return(status == -1 ? MagickFalse : MagickTrue);
824 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
826 switch (cache_info->type)
830 if (cache_info->mapped == MagickFalse)
831 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
834 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
835 (size_t) cache_info->length);
836 RelinquishMagickResource(MemoryResource,cache_info->length);
841 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
843 if (cache_info->mode != ReadMode)
844 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
845 *cache_info->cache_filename='\0';
846 RelinquishMagickResource(MapResource,cache_info->length);
850 if (cache_info->file != -1)
851 (void) ClosePixelCacheOnDisk(cache_info);
852 if (cache_info->mode != ReadMode)
853 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
854 *cache_info->cache_filename='\0';
855 RelinquishMagickResource(DiskResource,cache_info->length);
858 case DistributedCache:
860 *cache_info->cache_filename='\0';
861 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
862 cache_info->server_info);
868 cache_info->type=UndefinedCache;
869 cache_info->mapped=MagickFalse;
870 cache_info->metacontent=(void *) NULL;
873 MagickPrivate Cache DestroyPixelCache(Cache cache)
878 assert(cache != (Cache) NULL);
879 cache_info=(CacheInfo *) cache;
880 assert(cache_info->signature == MagickSignature);
881 if (cache_info->debug != MagickFalse)
882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
883 cache_info->filename);
884 LockSemaphoreInfo(cache_info->semaphore);
885 cache_info->reference_count--;
886 if (cache_info->reference_count != 0)
888 UnlockSemaphoreInfo(cache_info->semaphore);
889 return((Cache) NULL);
891 UnlockSemaphoreInfo(cache_info->semaphore);
892 if (cache_info->debug != MagickFalse)
895 message[MaxTextExtent];
897 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
898 cache_info->filename);
899 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
901 RelinquishPixelCachePixels(cache_info);
902 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
903 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
904 cache_info->server_info);
905 if (cache_info->nexus_info != (NexusInfo **) NULL)
906 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
907 cache_info->number_threads);
908 if (cache_info->random_info != (RandomInfo *) NULL)
909 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
910 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
911 DestroySemaphoreInfo(&cache_info->file_semaphore);
912 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
913 DestroySemaphoreInfo(&cache_info->semaphore);
914 cache_info->signature=(~MagickSignature);
915 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
925 + D e s t r o y P i x e l C a c h e N e x u s %
929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
933 % The format of the DestroyPixelCacheNexus() method is:
935 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
936 % const size_t number_threads)
938 % A description of each parameter follows:
940 % o nexus_info: the nexus to destroy.
942 % o number_threads: the number of nexus threads.
946 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
948 if (nexus_info->mapped == MagickFalse)
949 (void) RelinquishAlignedMemory(nexus_info->cache);
951 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
952 nexus_info->cache=(Quantum *) NULL;
953 nexus_info->pixels=(Quantum *) NULL;
954 nexus_info->metacontent=(void *) NULL;
955 nexus_info->length=0;
956 nexus_info->mapped=MagickFalse;
959 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
960 const size_t number_threads)
965 assert(nexus_info != (NexusInfo **) NULL);
966 for (i=0; i < (ssize_t) number_threads; i++)
968 if (nexus_info[i]->cache != (Quantum *) NULL)
969 RelinquishCacheNexusPixels(nexus_info[i]);
970 nexus_info[i]->signature=(~MagickSignature);
972 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
973 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 % G e t A u t h e n t i c M e t a c o n t e n t %
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
989 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
990 % returned if the associated pixels are not available.
992 % The format of the GetAuthenticMetacontent() method is:
994 % void *GetAuthenticMetacontent(const Image *image)
996 % A description of each parameter follows:
998 % o image: the image.
1001 MagickExport void *GetAuthenticMetacontent(const Image *image)
1007 id = GetOpenMPThreadId();
1012 assert(image != (const Image *) NULL);
1013 assert(image->signature == MagickSignature);
1014 assert(image->cache != (Cache) NULL);
1015 cache_info=(CacheInfo *) image->cache;
1016 assert(cache_info->signature == MagickSignature);
1017 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1018 (GetAuthenticMetacontentFromHandler) NULL)
1020 metacontent=cache_info->methods.
1021 get_authentic_metacontent_from_handler(image);
1022 return(metacontent);
1024 assert(id < (int) cache_info->number_threads);
1025 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1026 cache_info->nexus_info[id]);
1027 return(metacontent);
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 + G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
1039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1042 % with the last call to QueueAuthenticPixelsCache() or
1043 % GetAuthenticPixelsCache().
1045 % The format of the GetAuthenticMetacontentFromCache() method is:
1047 % void *GetAuthenticMetacontentFromCache(const Image *image)
1049 % A description of each parameter follows:
1051 % o image: the image.
1054 static void *GetAuthenticMetacontentFromCache(const Image *image)
1060 id = GetOpenMPThreadId();
1065 assert(image != (const Image *) NULL);
1066 assert(image->signature == MagickSignature);
1067 assert(image->cache != (Cache) NULL);
1068 cache_info=(CacheInfo *) image->cache;
1069 assert(cache_info->signature == MagickSignature);
1070 assert(id < (int) cache_info->number_threads);
1071 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1072 cache_info->nexus_info[id]);
1073 return(metacontent);
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 + G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1088 % disk pixel cache as defined by the geometry parameters. A pointer to the
1089 % pixels is returned if the pixels are transferred, otherwise a NULL is
1092 % The format of the GetAuthenticPixelCacheNexus() method is:
1094 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1095 % const ssize_t y,const size_t columns,const size_t rows,
1096 % NexusInfo *nexus_info,ExceptionInfo *exception)
1098 % A description of each parameter follows:
1100 % o image: the image.
1102 % o x,y,columns,rows: These values define the perimeter of a region of
1105 % o nexus_info: the cache nexus to return.
1107 % o exception: return any errors or warnings in this structure.
1111 static inline MagickBooleanType IsPixelAuthentic(
1112 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1120 if (cache_info->type == PingCache)
1122 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1123 nexus_info->region.x;
1124 status=nexus_info->pixels == (cache_info->pixels+offset*
1125 cache_info->number_channels) ? MagickTrue : MagickFalse;
1129 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1130 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1131 ExceptionInfo *exception)
1140 Transfer pixels from the cache.
1142 assert(image != (Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1145 nexus_info,exception);
1146 if (pixels == (Quantum *) NULL)
1147 return((Quantum *) NULL);
1148 cache_info=(CacheInfo *) image->cache;
1149 assert(cache_info->signature == MagickSignature);
1150 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1152 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1153 return((Quantum *) NULL);
1154 if (cache_info->metacontent_extent != 0)
1155 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1156 return((Quantum *) NULL);
1161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 + G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1171 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1172 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1174 % The format of the GetAuthenticPixelsFromCache() method is:
1176 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1178 % A description of each parameter follows:
1180 % o image: the image.
1183 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1189 id = GetOpenMPThreadId();
1191 assert(image != (const Image *) NULL);
1192 assert(image->signature == MagickSignature);
1193 assert(image->cache != (Cache) NULL);
1194 cache_info=(CacheInfo *) image->cache;
1195 assert(cache_info->signature == MagickSignature);
1196 assert(id < (int) cache_info->number_threads);
1197 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % G e t A u t h e n t i c P i x e l Q u e u e %
1209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 % GetAuthenticPixelQueue() returns the authentic pixels associated
1212 % corresponding with the last call to QueueAuthenticPixels() or
1213 % GetAuthenticPixels().
1215 % The format of the GetAuthenticPixelQueue() method is:
1217 % Quantum *GetAuthenticPixelQueue(const Image image)
1219 % A description of each parameter follows:
1221 % o image: the image.
1224 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1230 id = GetOpenMPThreadId();
1232 assert(image != (const Image *) NULL);
1233 assert(image->signature == MagickSignature);
1234 assert(image->cache != (Cache) NULL);
1235 cache_info=(CacheInfo *) image->cache;
1236 assert(cache_info->signature == MagickSignature);
1237 if (cache_info->methods.get_authentic_pixels_from_handler !=
1238 (GetAuthenticPixelsFromHandler) NULL)
1239 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1240 assert(id < (int) cache_info->number_threads);
1241 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249 % G e t A u t h e n t i c P i x e l s %
1252 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1254 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1255 % region is successfully accessed, a pointer to a Quantum array
1256 % representing the region is returned, otherwise NULL is returned.
1258 % The returned pointer may point to a temporary working copy of the pixels
1259 % or it may point to the original pixels in memory. Performance is maximized
1260 % if the selected region is part of one row, or one or more full rows, since
1261 % then there is opportunity to access the pixels in-place (without a copy)
1262 % if the image is in memory, or in a memory-mapped file. The returned pointer
1263 % must *never* be deallocated by the user.
1265 % Pixels accessed via the returned pointer represent a simple array of type
1266 % Quantum. If the image has corresponding metacontent,call
1267 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1268 % meta-content corresponding to the region. Once the Quantum array has
1269 % been updated, the changes must be saved back to the underlying image using
1270 % SyncAuthenticPixels() or they may be lost.
1272 % The format of the GetAuthenticPixels() method is:
1274 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1275 % const ssize_t y,const size_t columns,const size_t rows,
1276 % ExceptionInfo *exception)
1278 % A description of each parameter follows:
1280 % o image: the image.
1282 % o x,y,columns,rows: These values define the perimeter of a region of
1285 % o exception: return any errors or warnings in this structure.
1288 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1289 const ssize_t y,const size_t columns,const size_t rows,
1290 ExceptionInfo *exception)
1296 id = GetOpenMPThreadId();
1301 assert(image != (Image *) NULL);
1302 assert(image->signature == MagickSignature);
1303 assert(image->cache != (Cache) NULL);
1304 cache_info=(CacheInfo *) image->cache;
1305 assert(cache_info->signature == MagickSignature);
1306 if (cache_info->methods.get_authentic_pixels_handler !=
1307 (GetAuthenticPixelsHandler) NULL)
1309 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1313 assert(id < (int) cache_info->number_threads);
1314 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1315 cache_info->nexus_info[id],exception);
1320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324 + G e t A u t h e n t i c P i x e l s C a c h e %
1328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1331 % as defined by the geometry parameters. A pointer to the pixels is returned
1332 % if the pixels are transferred, otherwise a NULL is returned.
1334 % The format of the GetAuthenticPixelsCache() method is:
1336 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1337 % const ssize_t y,const size_t columns,const size_t rows,
1338 % ExceptionInfo *exception)
1340 % A description of each parameter follows:
1342 % o image: the image.
1344 % o x,y,columns,rows: These values define the perimeter of a region of
1347 % o exception: return any errors or warnings in this structure.
1350 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1351 const ssize_t y,const size_t columns,const size_t rows,
1352 ExceptionInfo *exception)
1358 id = GetOpenMPThreadId();
1363 assert(image != (const Image *) NULL);
1364 assert(image->signature == MagickSignature);
1365 assert(image->cache != (Cache) NULL);
1366 cache_info=(CacheInfo *) image->cache;
1367 if (cache_info == (Cache) NULL)
1368 return((Quantum *) NULL);
1369 assert(cache_info->signature == MagickSignature);
1370 assert(id < (int) cache_info->number_threads);
1371 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1372 cache_info->nexus_info[id],exception);
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 + G e t I m a g e E x t e n t %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % GetImageExtent() returns the extent of the pixels associated corresponding
1388 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1390 % The format of the GetImageExtent() method is:
1392 % MagickSizeType GetImageExtent(const Image *image)
1394 % A description of each parameter follows:
1396 % o image: the image.
1399 MagickExport MagickSizeType GetImageExtent(const Image *image)
1405 id = GetOpenMPThreadId();
1407 assert(image != (Image *) NULL);
1408 assert(image->signature == MagickSignature);
1409 if (image->debug != MagickFalse)
1410 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1411 assert(image->cache != (Cache) NULL);
1412 cache_info=(CacheInfo *) image->cache;
1413 assert(cache_info->signature == MagickSignature);
1414 assert(id < (int) cache_info->number_threads);
1415 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 + G e t I m a g e P i x e l C a c h e %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 % GetImagePixelCache() ensures that there is only a single reference to the
1430 % pixel cache to be modified, updating the provided cache pointer to point to
1431 % a clone of the original pixel cache if necessary.
1433 % The format of the GetImagePixelCache method is:
1435 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1436 % ExceptionInfo *exception)
1438 % A description of each parameter follows:
1440 % o image: the image.
1442 % o clone: any value other than MagickFalse clones the cache pixels.
1444 % o exception: return any errors or warnings in this structure.
1448 static inline MagickBooleanType ValidatePixelCacheMorphology(
1449 const Image *restrict image)
1452 *restrict cache_info;
1454 const PixelChannelMap
1459 Does the image match the pixel cache morphology?
1461 cache_info=(CacheInfo *) image->cache;
1462 p=image->channel_map;
1463 q=cache_info->channel_map;
1464 if ((image->storage_class != cache_info->storage_class) ||
1465 (image->colorspace != cache_info->colorspace) ||
1466 (image->alpha_trait != cache_info->alpha_trait) ||
1467 (image->mask != cache_info->mask) ||
1468 (image->columns != cache_info->columns) ||
1469 (image->rows != cache_info->rows) ||
1470 (image->number_channels != cache_info->number_channels) ||
1471 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1472 (image->metacontent_extent != cache_info->metacontent_extent) ||
1473 (cache_info->nexus_info == (NexusInfo **) NULL))
1474 return(MagickFalse);
1478 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1479 ExceptionInfo *exception)
1488 static MagickSizeType
1494 cache_timestamp = 0;
1497 LockSemaphoreInfo(image->semaphore);
1498 if (cpu_throttle == 0)
1499 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1500 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1501 MagickDelay(cpu_throttle);
1502 if (time_limit == 0)
1505 Set the expire time in seconds.
1507 time_limit=GetMagickResourceLimit(TimeResource);
1508 cache_timestamp=time((time_t *) NULL);
1510 if ((time_limit != MagickResourceInfinity) &&
1511 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1512 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1513 assert(image->cache != (Cache) NULL);
1514 cache_info=(CacheInfo *) image->cache;
1515 destroy=MagickFalse;
1516 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1518 LockSemaphoreInfo(cache_info->semaphore);
1519 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1530 clone_image=(*image);
1531 clone_image.semaphore=AllocateSemaphoreInfo();
1532 clone_image.reference_count=1;
1533 clone_image.cache=ClonePixelCache(cache_info);
1534 clone_info=(CacheInfo *) clone_image.cache;
1535 status=OpenPixelCache(&clone_image,IOMode,exception);
1536 if (status != MagickFalse)
1538 if (clone != MagickFalse)
1539 status=ClonePixelCacheRepository(clone_info,cache_info,
1541 if (status != MagickFalse)
1543 if (cache_info->reference_count == 1)
1544 cache_info->nexus_info=(NexusInfo **) NULL;
1546 image->cache=clone_image.cache;
1549 DestroySemaphoreInfo(&clone_image.semaphore);
1551 UnlockSemaphoreInfo(cache_info->semaphore);
1553 if (destroy != MagickFalse)
1554 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1555 if (status != MagickFalse)
1558 Ensure the image matches the pixel cache morphology.
1560 image->taint=MagickTrue;
1561 image->type=UndefinedType;
1562 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1564 status=OpenPixelCache(image,IOMode,exception);
1565 cache_info=(CacheInfo *) image->cache;
1566 if (cache_info->type == DiskCache)
1567 (void) ClosePixelCacheOnDisk(cache_info);
1570 UnlockSemaphoreInfo(image->semaphore);
1571 if (status == MagickFalse)
1572 return((Cache) NULL);
1573 return(image->cache);
1577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581 + G e t I m a g e P i x e l C a c h e T y p e %
1585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1588 % DiskCache, MemoryCache, MapCache, or PingCache.
1590 % The format of the GetImagePixelCacheType() method is:
1592 % CacheType GetImagePixelCacheType(const Image *image)
1594 % A description of each parameter follows:
1596 % o image: the image.
1599 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1604 assert(image != (Image *) NULL);
1605 assert(image->signature == MagickSignature);
1606 assert(image->cache != (Cache) NULL);
1607 cache_info=(CacheInfo *) image->cache;
1608 assert(cache_info->signature == MagickSignature);
1609 return(cache_info->type);
1613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 % G e t O n e A u t h e n t i c P i x e l %
1621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1624 % location. The image background color is returned if an error occurs.
1626 % The format of the GetOneAuthenticPixel() method is:
1628 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1629 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1631 % A description of each parameter follows:
1633 % o image: the image.
1635 % o x,y: These values define the location of the pixel to return.
1637 % o pixel: return a pixel at the specified (x,y) location.
1639 % o exception: return any errors or warnings in this structure.
1642 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1643 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1654 assert(image != (Image *) NULL);
1655 assert(image->signature == MagickSignature);
1656 assert(image->cache != (Cache) NULL);
1657 cache_info=(CacheInfo *) image->cache;
1658 assert(cache_info->signature == MagickSignature);
1659 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1660 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1661 (GetOneAuthenticPixelFromHandler) NULL)
1662 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1664 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1665 if (q == (Quantum *) NULL)
1667 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1668 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1669 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1670 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1671 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1672 return(MagickFalse);
1674 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1679 channel=GetPixelChannelChannel(image,i);
1680 pixel[channel]=q[i];
1686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1690 + 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 %
1694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1696 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1697 % location. The image background color is returned if an error occurs.
1699 % The format of the GetOneAuthenticPixelFromCache() method is:
1701 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1702 % const ssize_t x,const ssize_t y,Quantum *pixel,
1703 % ExceptionInfo *exception)
1705 % A description of each parameter follows:
1707 % o image: the image.
1709 % o x,y: These values define the location of the pixel to return.
1711 % o pixel: return a pixel at the specified (x,y) location.
1713 % o exception: return any errors or warnings in this structure.
1716 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1717 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1723 id = GetOpenMPThreadId();
1731 assert(image != (const Image *) NULL);
1732 assert(image->signature == MagickSignature);
1733 assert(image->cache != (Cache) NULL);
1734 cache_info=(CacheInfo *) image->cache;
1735 assert(cache_info->signature == MagickSignature);
1736 assert(id < (int) cache_info->number_threads);
1737 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1738 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1740 if (q == (Quantum *) NULL)
1742 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1743 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1744 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1745 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1746 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1747 return(MagickFalse);
1749 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1754 channel=GetPixelChannelChannel(image,i);
1755 pixel[channel]=q[i];
1761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765 % G e t O n e V i r t u a l P i x e l %
1769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1772 % (x,y) location. The image background color is returned if an error occurs.
1773 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1775 % The format of the GetOneVirtualPixel() method is:
1777 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1778 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1780 % A description of each parameter follows:
1782 % o image: the image.
1784 % o x,y: These values define the location of the pixel to return.
1786 % o pixel: return a pixel at the specified (x,y) location.
1788 % o exception: return any errors or warnings in this structure.
1791 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1792 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1798 id = GetOpenMPThreadId();
1806 assert(image != (const Image *) NULL);
1807 assert(image->signature == MagickSignature);
1808 assert(image->cache != (Cache) NULL);
1809 cache_info=(CacheInfo *) image->cache;
1810 assert(cache_info->signature == MagickSignature);
1811 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1812 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1813 (GetOneVirtualPixelFromHandler) NULL)
1814 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1815 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1816 assert(id < (int) cache_info->number_threads);
1817 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1818 1UL,1UL,cache_info->nexus_info[id],exception);
1819 if (p == (const Quantum *) NULL)
1821 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1822 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1823 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1824 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1825 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1826 return(MagickFalse);
1828 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1833 channel=GetPixelChannelChannel(image,i);
1834 pixel[channel]=p[i];
1840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1844 + 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 %
1848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1850 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1851 % specified (x,y) location. The image background color is returned if an
1854 % The format of the GetOneVirtualPixelFromCache() method is:
1856 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1857 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1858 % Quantum *pixel,ExceptionInfo *exception)
1860 % A description of each parameter follows:
1862 % o image: the image.
1864 % o virtual_pixel_method: the virtual pixel method.
1866 % o x,y: These values define the location of the pixel to return.
1868 % o pixel: return a pixel at the specified (x,y) location.
1870 % o exception: return any errors or warnings in this structure.
1873 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1874 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1875 Quantum *pixel,ExceptionInfo *exception)
1881 id = GetOpenMPThreadId();
1889 assert(image != (const Image *) NULL);
1890 assert(image->signature == MagickSignature);
1891 assert(image->cache != (Cache) NULL);
1892 cache_info=(CacheInfo *) image->cache;
1893 assert(cache_info->signature == MagickSignature);
1894 assert(id < (int) cache_info->number_threads);
1895 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1896 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1897 cache_info->nexus_info[id],exception);
1898 if (p == (const Quantum *) NULL)
1900 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1901 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1902 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1903 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1904 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1905 return(MagickFalse);
1907 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1912 channel=GetPixelChannelChannel(image,i);
1913 pixel[channel]=p[i];
1919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1923 % G e t O n e V i r t u a l P i x e l I n f o %
1927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1929 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1930 % location. The image background color is returned if an error occurs. If
1931 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1933 % The format of the GetOneVirtualPixelInfo() method is:
1935 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1936 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1937 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1939 % A description of each parameter follows:
1941 % o image: the image.
1943 % o virtual_pixel_method: the virtual pixel method.
1945 % o x,y: these values define the location of the pixel to return.
1947 % o pixel: return a pixel at the specified (x,y) location.
1949 % o exception: return any errors or warnings in this structure.
1952 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1953 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1954 PixelInfo *pixel,ExceptionInfo *exception)
1960 id = GetOpenMPThreadId();
1962 register const Quantum
1965 assert(image != (const Image *) NULL);
1966 assert(image->signature == MagickSignature);
1967 assert(image->cache != (Cache) NULL);
1968 cache_info=(CacheInfo *) image->cache;
1969 assert(cache_info->signature == MagickSignature);
1970 assert(id < (int) cache_info->number_threads);
1971 GetPixelInfo(image,pixel);
1972 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1973 cache_info->nexus_info[id],exception);
1974 if (p == (const Quantum *) NULL)
1975 return(MagickFalse);
1976 GetPixelInfoPixel(image,p,pixel);
1981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985 + G e t P i x e l C a c h e C o l o r s p a c e %
1989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1991 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1993 % The format of the GetPixelCacheColorspace() method is:
1995 % Colorspace GetPixelCacheColorspace(Cache cache)
1997 % A description of each parameter follows:
1999 % o cache: the pixel cache.
2002 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2007 assert(cache != (Cache) NULL);
2008 cache_info=(CacheInfo *) cache;
2009 assert(cache_info->signature == MagickSignature);
2010 if (cache_info->debug != MagickFalse)
2011 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2012 cache_info->filename);
2013 return(cache_info->colorspace);
2017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2021 + G e t P i x e l C a c h e M e t h o d s %
2025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2027 % GetPixelCacheMethods() initializes the CacheMethods structure.
2029 % The format of the GetPixelCacheMethods() method is:
2031 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2033 % A description of each parameter follows:
2035 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2038 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2040 assert(cache_methods != (CacheMethods *) NULL);
2041 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2042 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2043 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2044 cache_methods->get_virtual_metacontent_from_handler=
2045 GetVirtualMetacontentFromCache;
2046 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2047 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2048 cache_methods->get_authentic_metacontent_from_handler=
2049 GetAuthenticMetacontentFromCache;
2050 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2051 cache_methods->get_one_authentic_pixel_from_handler=
2052 GetOneAuthenticPixelFromCache;
2053 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2054 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2055 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063 + G e t P i x e l C a c h e N e x u s E x t e n t %
2067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2069 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2070 % corresponding with the last call to SetPixelCacheNexusPixels() or
2071 % GetPixelCacheNexusPixels().
2073 % The format of the GetPixelCacheNexusExtent() method is:
2075 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2076 % NexusInfo *nexus_info)
2078 % A description of each parameter follows:
2080 % o nexus_info: the nexus info.
2083 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2084 NexusInfo *nexus_info)
2092 assert(cache != NULL);
2093 cache_info=(CacheInfo *) cache;
2094 assert(cache_info->signature == MagickSignature);
2095 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2097 return((MagickSizeType) cache_info->columns*cache_info->rows);
2102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2106 + 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 %
2110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2112 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2115 % The format of the GetPixelCacheNexusMetacontent() method is:
2117 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2118 % NexusInfo *nexus_info)
2120 % A description of each parameter follows:
2122 % o cache: the pixel cache.
2124 % o nexus_info: the cache nexus to return the meta-content.
2127 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2128 NexusInfo *nexus_info)
2133 assert(cache != NULL);
2134 cache_info=(CacheInfo *) cache;
2135 assert(cache_info->signature == MagickSignature);
2136 if (cache_info->storage_class == UndefinedClass)
2137 return((void *) NULL);
2138 return(nexus_info->metacontent);
2142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2146 + G e t P i x e l C a c h e N e x u s P i x e l s %
2150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2152 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2155 % The format of the GetPixelCacheNexusPixels() method is:
2157 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2158 % NexusInfo *nexus_info)
2160 % A description of each parameter follows:
2162 % o cache: the pixel cache.
2164 % o nexus_info: the cache nexus to return the pixels.
2167 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2168 NexusInfo *nexus_info)
2173 assert(cache != NULL);
2174 cache_info=(CacheInfo *) cache;
2175 assert(cache_info->signature == MagickSignature);
2176 if (cache_info->storage_class == UndefinedClass)
2177 return((Quantum *) NULL);
2178 return(nexus_info->pixels);
2182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2186 + G e t P i x e l C a c h e P i x e l s %
2190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2192 % GetPixelCachePixels() returns the pixels associated with the specified image.
2194 % The format of the GetPixelCachePixels() method is:
2196 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2197 % ExceptionInfo *exception)
2199 % A description of each parameter follows:
2201 % o image: the image.
2203 % o length: the pixel cache length.
2205 % o exception: return any errors or warnings in this structure.
2208 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2209 ExceptionInfo *exception)
2214 assert(image != (const Image *) NULL);
2215 assert(image->signature == MagickSignature);
2216 assert(image->cache != (Cache) NULL);
2217 assert(length != (MagickSizeType *) NULL);
2218 assert(exception != (ExceptionInfo *) NULL);
2219 assert(exception->signature == MagickSignature);
2220 cache_info=(CacheInfo *) image->cache;
2221 assert(cache_info->signature == MagickSignature);
2223 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2224 return((void *) NULL);
2225 *length=cache_info->length;
2226 return((void *) cache_info->pixels);
2230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2234 + 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 %
2238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2242 % The format of the GetPixelCacheStorageClass() method is:
2244 % ClassType GetPixelCacheStorageClass(Cache cache)
2246 % A description of each parameter follows:
2248 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2250 % o cache: the pixel cache.
2253 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2258 assert(cache != (Cache) NULL);
2259 cache_info=(CacheInfo *) cache;
2260 assert(cache_info->signature == MagickSignature);
2261 if (cache_info->debug != MagickFalse)
2262 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2263 cache_info->filename);
2264 return(cache_info->storage_class);
2268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2272 + G e t P i x e l C a c h e T i l e S i z e %
2276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 % GetPixelCacheTileSize() returns the pixel cache tile size.
2280 % The format of the GetPixelCacheTileSize() method is:
2282 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2285 % A description of each parameter follows:
2287 % o image: the image.
2289 % o width: the optimize cache tile width in pixels.
2291 % o height: the optimize cache tile height in pixels.
2294 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2300 assert(image != (Image *) NULL);
2301 assert(image->signature == MagickSignature);
2302 if (image->debug != MagickFalse)
2303 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2304 cache_info=(CacheInfo *) image->cache;
2305 assert(cache_info->signature == MagickSignature);
2306 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2307 if (GetImagePixelCacheType(image) == DiskCache)
2308 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2317 + 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 %
2321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2323 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2324 % pixel cache. A virtual pixel is any pixel access that is outside the
2325 % boundaries of the image cache.
2327 % The format of the GetPixelCacheVirtualMethod() method is:
2329 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2331 % A description of each parameter follows:
2333 % o image: the image.
2336 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2341 assert(image != (Image *) NULL);
2342 assert(image->signature == MagickSignature);
2343 assert(image->cache != (Cache) NULL);
2344 cache_info=(CacheInfo *) image->cache;
2345 assert(cache_info->signature == MagickSignature);
2346 return(cache_info->virtual_pixel_method);
2350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2354 + 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 %
2358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2360 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2361 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2363 % The format of the GetVirtualMetacontentFromCache() method is:
2365 % void *GetVirtualMetacontentFromCache(const Image *image)
2367 % A description of each parameter follows:
2369 % o image: the image.
2372 static const void *GetVirtualMetacontentFromCache(const Image *image)
2378 id = GetOpenMPThreadId();
2383 assert(image != (const Image *) NULL);
2384 assert(image->signature == MagickSignature);
2385 assert(image->cache != (Cache) NULL);
2386 cache_info=(CacheInfo *) image->cache;
2387 assert(cache_info->signature == MagickSignature);
2388 assert(id < (int) cache_info->number_threads);
2389 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2390 cache_info->nexus_info[id]);
2391 return(metacontent);
2395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2399 + 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 %
2403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2405 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2408 % The format of the GetVirtualMetacontentFromNexus() method is:
2410 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2411 % NexusInfo *nexus_info)
2413 % A description of each parameter follows:
2415 % o cache: the pixel cache.
2417 % o nexus_info: the cache nexus to return the meta-content.
2420 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2421 NexusInfo *nexus_info)
2426 assert(cache != (Cache) NULL);
2427 cache_info=(CacheInfo *) cache;
2428 assert(cache_info->signature == MagickSignature);
2429 if (cache_info->storage_class == UndefinedClass)
2430 return((void *) NULL);
2431 return(nexus_info->metacontent);
2435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2439 % G e t V i r t u a l M e t a c o n t e n t %
2443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2445 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2446 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2447 % returned if the meta-content are not available.
2449 % The format of the GetVirtualMetacontent() method is:
2451 % const void *GetVirtualMetacontent(const Image *image)
2453 % A description of each parameter follows:
2455 % o image: the image.
2458 MagickExport const void *GetVirtualMetacontent(const Image *image)
2464 id = GetOpenMPThreadId();
2469 assert(image != (const Image *) NULL);
2470 assert(image->signature == MagickSignature);
2471 assert(image->cache != (Cache) NULL);
2472 cache_info=(CacheInfo *) image->cache;
2473 assert(cache_info->signature == MagickSignature);
2474 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2475 if (metacontent != (void *) NULL)
2476 return(metacontent);
2477 assert(id < (int) cache_info->number_threads);
2478 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2479 cache_info->nexus_info[id]);
2480 return(metacontent);
2484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2488 + 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 %
2492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2494 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2495 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2496 % is returned if the pixels are transferred, otherwise a NULL is returned.
2498 % The format of the GetVirtualPixelsFromNexus() method is:
2500 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2501 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2502 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2503 % ExceptionInfo *exception)
2505 % A description of each parameter follows:
2507 % o image: the image.
2509 % o virtual_pixel_method: the virtual pixel method.
2511 % o x,y,columns,rows: These values define the perimeter of a region of
2514 % o nexus_info: the cache nexus to acquire.
2516 % o exception: return any errors or warnings in this structure.
2523 0, 48, 12, 60, 3, 51, 15, 63,
2524 32, 16, 44, 28, 35, 19, 47, 31,
2525 8, 56, 4, 52, 11, 59, 7, 55,
2526 40, 24, 36, 20, 43, 27, 39, 23,
2527 2, 50, 14, 62, 1, 49, 13, 61,
2528 34, 18, 46, 30, 33, 17, 45, 29,
2529 10, 58, 6, 54, 9, 57, 5, 53,
2530 42, 26, 38, 22, 41, 25, 37, 21
2533 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2538 index=x+DitherMatrix[x & 0x07]-32L;
2541 if (index >= (ssize_t) columns)
2542 return((ssize_t) columns-1L);
2546 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2551 index=y+DitherMatrix[y & 0x07]-32L;
2554 if (index >= (ssize_t) rows)
2555 return((ssize_t) rows-1L);
2559 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2563 if (x >= (ssize_t) columns)
2564 return((ssize_t) (columns-1));
2568 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2572 if (y >= (ssize_t) rows)
2573 return((ssize_t) (rows-1));
2577 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2579 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2582 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2584 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2587 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2588 const size_t extent)
2594 Compute the remainder of dividing offset by extent. It returns not only
2595 the quotient (tile the offset falls in) but also the positive remainer
2596 within that tile such that 0 <= remainder < extent. This method is
2597 essentially a ldiv() using a floored modulo division rather than the
2598 normal default truncated modulo division.
2600 modulo.quotient=offset/(ssize_t) extent;
2603 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2607 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2608 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2609 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2610 ExceptionInfo *exception)
2627 virtual_pixel[CompositePixelChannel];
2632 register const Quantum
2645 register unsigned char
2652 *virtual_metacontent;
2657 assert(image != (const Image *) NULL);
2658 assert(image->signature == MagickSignature);
2659 assert(image->cache != (Cache) NULL);
2660 cache_info=(CacheInfo *) image->cache;
2661 assert(cache_info->signature == MagickSignature);
2662 if (cache_info->type == UndefinedCache)
2663 return((const Quantum *) NULL);
2666 region.width=columns;
2668 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2670 if (pixels == (Quantum *) NULL)
2671 return((const Quantum *) NULL);
2673 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2674 nexus_info->region.x;
2675 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2676 nexus_info->region.width-1L;
2677 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2678 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2679 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2680 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2686 Pixel request is inside cache extents.
2688 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2690 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2691 if (status == MagickFalse)
2692 return((const Quantum *) NULL);
2693 if (cache_info->metacontent_extent != 0)
2695 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2696 if (status == MagickFalse)
2697 return((const Quantum *) NULL);
2702 Pixel request is outside cache extents.
2704 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2705 virtual_nexus=AcquirePixelCacheNexus(1);
2706 if (virtual_nexus == (NexusInfo **) NULL)
2708 if (virtual_nexus != (NexusInfo **) NULL)
2709 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2710 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2711 "UnableToGetCacheNexus","`%s'",image->filename);
2712 return((const Quantum *) NULL);
2714 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2715 sizeof(*virtual_pixel));
2716 virtual_metacontent=(void *) NULL;
2717 switch (virtual_pixel_method)
2719 case BackgroundVirtualPixelMethod:
2720 case BlackVirtualPixelMethod:
2721 case GrayVirtualPixelMethod:
2722 case TransparentVirtualPixelMethod:
2723 case MaskVirtualPixelMethod:
2724 case WhiteVirtualPixelMethod:
2725 case EdgeVirtualPixelMethod:
2726 case CheckerTileVirtualPixelMethod:
2727 case HorizontalTileVirtualPixelMethod:
2728 case VerticalTileVirtualPixelMethod:
2730 if (cache_info->metacontent_extent != 0)
2733 Acquire a metacontent buffer.
2735 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2736 cache_info->metacontent_extent);
2737 if (virtual_metacontent == (void *) NULL)
2739 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2740 (void) ThrowMagickException(exception,GetMagickModule(),
2741 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2742 return((const Quantum *) NULL);
2744 (void) ResetMagickMemory(virtual_metacontent,0,
2745 cache_info->metacontent_extent);
2747 switch (virtual_pixel_method)
2749 case BlackVirtualPixelMethod:
2751 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2752 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2753 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2756 case GrayVirtualPixelMethod:
2758 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2759 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2761 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2764 case TransparentVirtualPixelMethod:
2766 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2767 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2768 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2771 case MaskVirtualPixelMethod:
2772 case WhiteVirtualPixelMethod:
2774 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2775 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2776 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2781 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2783 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2785 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2787 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2789 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2799 for (v=0; v < (ssize_t) rows; v++)
2805 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2806 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2807 y_offset=EdgeY(y_offset,cache_info->rows);
2808 for (u=0; u < (ssize_t) columns; u+=length)
2814 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2815 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2816 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2824 Transfer a single pixel.
2826 length=(MagickSizeType) 1;
2827 switch (virtual_pixel_method)
2829 case EdgeVirtualPixelMethod:
2832 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2833 EdgeX(x_offset,cache_info->columns),
2834 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2836 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2839 case RandomVirtualPixelMethod:
2841 if (cache_info->random_info == (RandomInfo *) NULL)
2842 cache_info->random_info=AcquireRandomInfo();
2843 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2844 RandomX(cache_info->random_info,cache_info->columns),
2845 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2846 *virtual_nexus,exception);
2847 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2850 case DitherVirtualPixelMethod:
2852 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2853 DitherX(x_offset,cache_info->columns),
2854 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2856 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2859 case TileVirtualPixelMethod:
2861 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2862 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2863 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2864 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2866 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2869 case MirrorVirtualPixelMethod:
2871 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2872 if ((x_modulo.quotient & 0x01) == 1L)
2873 x_modulo.remainder=(ssize_t) cache_info->columns-
2874 x_modulo.remainder-1L;
2875 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2876 if ((y_modulo.quotient & 0x01) == 1L)
2877 y_modulo.remainder=(ssize_t) cache_info->rows-
2878 y_modulo.remainder-1L;
2879 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2880 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2882 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2885 case HorizontalTileEdgeVirtualPixelMethod:
2887 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2888 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2889 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2890 *virtual_nexus,exception);
2891 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2894 case VerticalTileEdgeVirtualPixelMethod:
2896 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2897 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2898 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2899 *virtual_nexus,exception);
2900 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2903 case BackgroundVirtualPixelMethod:
2904 case BlackVirtualPixelMethod:
2905 case GrayVirtualPixelMethod:
2906 case TransparentVirtualPixelMethod:
2907 case MaskVirtualPixelMethod:
2908 case WhiteVirtualPixelMethod:
2911 r=virtual_metacontent;
2914 case CheckerTileVirtualPixelMethod:
2916 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2917 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2918 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2921 r=virtual_metacontent;
2924 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2925 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2927 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2930 case HorizontalTileVirtualPixelMethod:
2932 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2935 r=virtual_metacontent;
2938 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2939 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2940 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2941 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2943 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2946 case VerticalTileVirtualPixelMethod:
2948 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2951 r=virtual_metacontent;
2954 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2955 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2956 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2957 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2959 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2963 if (p == (const Quantum *) NULL)
2965 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2967 q+=cache_info->number_channels;
2968 if ((s != (void *) NULL) && (r != (const void *) NULL))
2970 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2971 s+=cache_info->metacontent_extent;
2976 Transfer a run of pixels.
2978 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2979 (size_t) length,1UL,*virtual_nexus,exception);
2980 if (p == (const Quantum *) NULL)
2982 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2983 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2984 q+=length*cache_info->number_channels;
2985 if ((r != (void *) NULL) && (s != (const void *) NULL))
2987 (void) memcpy(s,r,(size_t) length);
2988 s+=length*cache_info->metacontent_extent;
2995 if (virtual_metacontent != (void *) NULL)
2996 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2997 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006 + G e t V i r t u a l P i x e l C a c h e %
3010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3012 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3013 % cache as defined by the geometry parameters. A pointer to the pixels
3014 % is returned if the pixels are transferred, otherwise a NULL is returned.
3016 % The format of the GetVirtualPixelCache() method is:
3018 % const Quantum *GetVirtualPixelCache(const Image *image,
3019 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3020 % const ssize_t y,const size_t columns,const size_t rows,
3021 % ExceptionInfo *exception)
3023 % A description of each parameter follows:
3025 % o image: the image.
3027 % o virtual_pixel_method: the virtual pixel method.
3029 % o x,y,columns,rows: These values define the perimeter of a region of
3032 % o exception: return any errors or warnings in this structure.
3035 static const Quantum *GetVirtualPixelCache(const Image *image,
3036 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3037 const size_t columns,const size_t rows,ExceptionInfo *exception)
3043 id = GetOpenMPThreadId();
3048 assert(image != (const Image *) NULL);
3049 assert(image->signature == MagickSignature);
3050 assert(image->cache != (Cache) NULL);
3051 cache_info=(CacheInfo *) image->cache;
3052 assert(cache_info->signature == MagickSignature);
3053 assert(id < (int) cache_info->number_threads);
3054 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3055 cache_info->nexus_info[id],exception);
3060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3064 % G e t V i r t u a l P i x e l Q u e u e %
3068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3070 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3071 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3073 % The format of the GetVirtualPixelQueue() method is:
3075 % const Quantum *GetVirtualPixelQueue(const Image image)
3077 % A description of each parameter follows:
3079 % o image: the image.
3082 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3088 id = GetOpenMPThreadId();
3090 assert(image != (const Image *) NULL);
3091 assert(image->signature == MagickSignature);
3092 assert(image->cache != (Cache) NULL);
3093 cache_info=(CacheInfo *) image->cache;
3094 assert(cache_info->signature == MagickSignature);
3095 if (cache_info->methods.get_virtual_pixels_handler !=
3096 (GetVirtualPixelsHandler) NULL)
3097 return(cache_info->methods.get_virtual_pixels_handler(image));
3098 assert(id < (int) cache_info->number_threads);
3099 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3107 % G e t V i r t u a l P i x e l s %
3111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3113 % GetVirtualPixels() returns an immutable pixel region. If the
3114 % region is successfully accessed, a pointer to it is returned, otherwise
3115 % NULL is returned. The returned pointer may point to a temporary working
3116 % copy of the pixels or it may point to the original pixels in memory.
3117 % Performance is maximized if the selected region is part of one row, or one
3118 % or more full rows, since there is opportunity to access the pixels in-place
3119 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3120 % returned pointer must *never* be deallocated by the user.
3122 % Pixels accessed via the returned pointer represent a simple array of type
3123 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3124 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3125 % access the meta-content (of type void) corresponding to the the
3128 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3130 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3131 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3132 % GetCacheViewAuthenticPixels() instead.
3134 % The format of the GetVirtualPixels() method is:
3136 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3137 % const ssize_t y,const size_t columns,const size_t rows,
3138 % ExceptionInfo *exception)
3140 % A description of each parameter follows:
3142 % o image: the image.
3144 % o x,y,columns,rows: These values define the perimeter of a region of
3147 % o exception: return any errors or warnings in this structure.
3150 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3151 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3152 ExceptionInfo *exception)
3158 id = GetOpenMPThreadId();
3163 assert(image != (const Image *) NULL);
3164 assert(image->signature == MagickSignature);
3165 assert(image->cache != (Cache) NULL);
3166 cache_info=(CacheInfo *) image->cache;
3167 assert(cache_info->signature == MagickSignature);
3168 if (cache_info->methods.get_virtual_pixel_handler !=
3169 (GetVirtualPixelHandler) NULL)
3170 return(cache_info->methods.get_virtual_pixel_handler(image,
3171 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3172 assert(id < (int) cache_info->number_threads);
3173 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3174 columns,rows,cache_info->nexus_info[id],exception);
3179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3183 + G e t V i r t u a l P i x e l s F r o m C a c h e %
3187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3189 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3190 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3192 % The format of the GetVirtualPixelsCache() method is:
3194 % Quantum *GetVirtualPixelsCache(const Image *image)
3196 % A description of each parameter follows:
3198 % o image: the image.
3201 static const Quantum *GetVirtualPixelsCache(const Image *image)
3207 id = GetOpenMPThreadId();
3209 assert(image != (const Image *) NULL);
3210 assert(image->signature == MagickSignature);
3211 assert(image->cache != (Cache) NULL);
3212 cache_info=(CacheInfo *) image->cache;
3213 assert(cache_info->signature == MagickSignature);
3214 assert(id < (int) cache_info->number_threads);
3215 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3223 + G e t V i r t u a l P i x e l s N e x u s %
3227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3229 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3232 % The format of the GetVirtualPixelsNexus() method is:
3234 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3235 % NexusInfo *nexus_info)
3237 % A description of each parameter follows:
3239 % o cache: the pixel cache.
3241 % o nexus_info: the cache nexus to return the colormap pixels.
3244 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3245 NexusInfo *nexus_info)
3250 assert(cache != (Cache) NULL);
3251 cache_info=(CacheInfo *) cache;
3252 assert(cache_info->signature == MagickSignature);
3253 if (cache_info->storage_class == UndefinedClass)
3254 return((Quantum *) NULL);
3255 return((const Quantum *) nexus_info->pixels);
3259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3263 + O p e n P i x e l C a c h e %
3267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3269 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3270 % dimensions, allocating space for the image pixels and optionally the
3271 % metacontent, and memory mapping the cache if it is disk based. The cache
3272 % nexus array is initialized as well.
3274 % The format of the OpenPixelCache() method is:
3276 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3277 % ExceptionInfo *exception)
3279 % A description of each parameter follows:
3281 % o image: the image.
3283 % o mode: ReadMode, WriteMode, or IOMode.
3285 % o exception: return any errors or warnings in this structure.
3289 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3291 cache_info->mapped=MagickFalse;
3292 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3293 (size_t) cache_info->length));
3294 if (cache_info->pixels == (Quantum *) NULL)
3296 cache_info->mapped=MagickTrue;
3297 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3298 cache_info->length);
3302 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3309 Open pixel cache on disk.
3311 if (cache_info->file != -1)
3312 return(MagickTrue); /* cache already open */
3313 if (*cache_info->cache_filename == '\0')
3314 file=AcquireUniqueFileResource(cache_info->cache_filename);
3320 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3325 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3326 O_BINARY | O_EXCL,S_MODE);
3328 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3334 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3337 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3342 return(MagickFalse);
3343 (void) AcquireMagickResource(FileResource,1);
3344 cache_info->file=file;
3345 cache_info->mode=mode;
3349 static inline MagickOffsetType WritePixelCacheRegion(
3350 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3351 const MagickSizeType length,const unsigned char *restrict buffer)
3353 register MagickOffsetType
3359 #if !defined(MAGICKCORE_HAVE_PWRITE)
3360 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3361 return((MagickOffsetType) -1);
3364 for (i=0; i < (MagickOffsetType) length; i+=count)
3366 #if !defined(MAGICKCORE_HAVE_PWRITE)
3367 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3368 (MagickSizeType) SSIZE_MAX));
3370 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3371 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3383 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3393 cache_info=(CacheInfo *) image->cache;
3394 if (image->debug != MagickFalse)
3397 format[MaxTextExtent],
3398 message[MaxTextExtent];
3400 (void) FormatMagickSize(length,MagickFalse,format);
3401 (void) FormatLocaleString(message,MaxTextExtent,
3402 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3403 cache_info->cache_filename,cache_info->file,format);
3404 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3406 if (length != (MagickSizeType) ((MagickOffsetType) length))
3407 return(MagickFalse);
3408 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3410 return(MagickFalse);
3411 if ((MagickSizeType) offset >= length)
3413 extent=(MagickOffsetType) length-1;
3414 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3415 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3416 if (cache_info->synchronize != MagickFalse)
3421 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3423 return(MagickFalse);
3426 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3429 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3430 ExceptionInfo *exception)
3437 format[MaxTextExtent],
3438 message[MaxTextExtent];
3454 assert(image != (const Image *) NULL);
3455 assert(image->signature == MagickSignature);
3456 assert(image->cache != (Cache) NULL);
3457 if (image->debug != MagickFalse)
3458 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3459 if ((image->columns == 0) || (image->rows == 0))
3460 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3461 cache_info=(CacheInfo *) image->cache;
3462 assert(cache_info->signature == MagickSignature);
3463 source_info=(*cache_info);
3464 source_info.file=(-1);
3465 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3466 image->filename,(double) GetImageIndexInList(image));
3467 cache_info->storage_class=image->storage_class;
3468 cache_info->colorspace=image->colorspace;
3469 cache_info->alpha_trait=image->alpha_trait;
3470 cache_info->mask=image->mask;
3471 cache_info->rows=image->rows;
3472 cache_info->columns=image->columns;
3473 InitializePixelChannelMap(image);
3474 cache_info->number_channels=GetPixelChannels(image);
3475 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3476 sizeof(*image->channel_map));
3477 cache_info->metacontent_extent=image->metacontent_extent;
3478 cache_info->mode=mode;
3479 if (image->ping != MagickFalse)
3481 cache_info->type=PingCache;
3482 cache_info->pixels=(Quantum *) NULL;
3483 cache_info->metacontent=(void *) NULL;
3484 cache_info->length=0;
3487 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3488 packet_size=cache_info->number_channels*sizeof(Quantum);
3489 if (image->metacontent_extent != 0)
3490 packet_size+=cache_info->metacontent_extent;
3491 length=number_pixels*packet_size;
3492 columns=(size_t) (length/cache_info->rows/packet_size);
3493 if (cache_info->columns != columns)
3494 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3496 cache_info->length=length;
3497 status=AcquireMagickResource(AreaResource,cache_info->length);
3498 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3499 cache_info->metacontent_extent);
3500 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3502 status=AcquireMagickResource(MemoryResource,cache_info->length);
3503 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3504 (cache_info->type == MemoryCache))
3506 AllocatePixelCachePixels(cache_info);
3507 if (cache_info->pixels == (Quantum *) NULL)
3508 cache_info->pixels=source_info.pixels;
3512 Create memory pixel cache.
3515 cache_info->type=MemoryCache;
3516 cache_info->metacontent=(void *) NULL;
3517 if (cache_info->metacontent_extent != 0)
3518 cache_info->metacontent=(void *) (cache_info->pixels+
3519 number_pixels*cache_info->number_channels);
3520 if ((source_info.storage_class != UndefinedClass) &&
3523 status=ClonePixelCacheRepository(cache_info,&source_info,
3525 RelinquishPixelCachePixels(&source_info);
3527 if (image->debug != MagickFalse)
3529 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3530 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3532 (void) FormatLocaleString(message,MaxTextExtent,
3533 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3534 cache_info->filename,cache_info->mapped != MagickFalse ?
3535 "Anonymous" : "Heap",type,(double) cache_info->columns,
3536 (double) cache_info->rows,(double)
3537 cache_info->number_channels,format);
3538 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3544 RelinquishMagickResource(MemoryResource,cache_info->length);
3547 Create pixel cache on disk.
3549 status=AcquireMagickResource(DiskResource,cache_info->length);
3550 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3555 if (cache_info->type == DistributedCache)
3556 RelinquishMagickResource(DiskResource,cache_info->length);
3557 server_info=AcquireDistributeCacheInfo(exception);
3558 if (server_info != (DistributeCacheInfo *) NULL)
3560 status=OpenDistributePixelCache(server_info,image);
3561 if (status == MagickFalse)
3563 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3564 GetDistributeCacheHostname(server_info));
3565 server_info=DestroyDistributeCacheInfo(server_info);
3570 Create a distributed pixel cache.
3572 cache_info->type=DistributedCache;
3573 cache_info->server_info=server_info;
3574 (void) FormatLocaleString(cache_info->cache_filename,
3575 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3576 (DistributeCacheInfo *) cache_info->server_info),
3577 GetDistributeCachePort((DistributeCacheInfo *)
3578 cache_info->server_info));
3579 if ((source_info.storage_class != UndefinedClass) &&
3582 status=ClonePixelCacheRepository(cache_info,&source_info,
3584 RelinquishPixelCachePixels(&source_info);
3586 if (image->debug != MagickFalse)
3588 (void) FormatMagickSize(cache_info->length,MagickFalse,
3590 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3592 (void) FormatLocaleString(message,MaxTextExtent,
3593 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3594 cache_info->filename,cache_info->cache_filename,
3595 GetDistributeCacheFile((DistributeCacheInfo *)
3596 cache_info->server_info),type,(double) cache_info->columns,
3597 (double) cache_info->rows,(double)
3598 cache_info->number_channels,format);
3599 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3605 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3606 "CacheResourcesExhausted","`%s'",image->filename);
3607 return(MagickFalse);
3609 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3611 (void) ClosePixelCacheOnDisk(cache_info);
3612 *cache_info->cache_filename='\0';
3614 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3616 RelinquishMagickResource(DiskResource,cache_info->length);
3617 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3619 return(MagickFalse);
3621 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3622 cache_info->length);
3623 if (status == MagickFalse)
3625 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3627 return(MagickFalse);
3629 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3630 cache_info->metacontent_extent);
3631 if (length != (MagickSizeType) ((size_t) length))
3632 cache_info->type=DiskCache;
3635 status=AcquireMagickResource(MapResource,cache_info->length);
3636 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3637 (cache_info->type != MemoryCache))
3638 cache_info->type=DiskCache;
3641 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3642 cache_info->offset,(size_t) cache_info->length);
3643 if (cache_info->pixels == (Quantum *) NULL)
3645 cache_info->type=DiskCache;
3646 cache_info->pixels=source_info.pixels;
3651 Create file-backed memory-mapped pixel cache.
3654 (void) ClosePixelCacheOnDisk(cache_info);
3655 cache_info->type=MapCache;
3656 cache_info->mapped=MagickTrue;
3657 cache_info->metacontent=(void *) NULL;
3658 if (cache_info->metacontent_extent != 0)
3659 cache_info->metacontent=(void *) (cache_info->pixels+
3660 number_pixels*cache_info->number_channels);
3661 if ((source_info.storage_class != UndefinedClass) &&
3664 status=ClonePixelCacheRepository(cache_info,&source_info,
3666 RelinquishPixelCachePixels(&source_info);
3668 if (image->debug != MagickFalse)
3670 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3671 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3673 (void) FormatLocaleString(message,MaxTextExtent,
3674 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3675 cache_info->filename,cache_info->cache_filename,
3676 cache_info->file,type,(double) cache_info->columns,(double)
3677 cache_info->rows,(double) cache_info->number_channels,
3679 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3685 RelinquishMagickResource(MapResource,cache_info->length);
3688 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3690 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3691 RelinquishPixelCachePixels(&source_info);
3693 if (image->debug != MagickFalse)
3695 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3696 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3698 (void) FormatLocaleString(message,MaxTextExtent,
3699 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3700 cache_info->cache_filename,cache_info->file,type,(double)
3701 cache_info->columns,(double) cache_info->rows,(double)
3702 cache_info->number_channels,format);
3703 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3713 + P e r s i s t P i x e l C a c h e %
3717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3719 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3720 % persistent pixel cache is one that resides on disk and is not destroyed
3721 % when the program exits.
3723 % The format of the PersistPixelCache() method is:
3725 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3726 % const MagickBooleanType attach,MagickOffsetType *offset,
3727 % ExceptionInfo *exception)
3729 % A description of each parameter follows:
3731 % o image: the image.
3733 % o filename: the persistent pixel cache filename.
3735 % o attach: A value other than zero initializes the persistent pixel cache.
3737 % o initialize: A value other than zero initializes the persistent pixel
3740 % o offset: the offset in the persistent cache to store pixels.
3742 % o exception: return any errors or warnings in this structure.
3745 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3746 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3747 ExceptionInfo *exception)
3762 assert(image != (Image *) NULL);
3763 assert(image->signature == MagickSignature);
3764 if (image->debug != MagickFalse)
3765 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3766 assert(image->cache != (void *) NULL);
3767 assert(filename != (const char *) NULL);
3768 assert(offset != (MagickOffsetType *) NULL);
3769 page_size=GetMagickPageSize();
3770 cache_info=(CacheInfo *) image->cache;
3771 assert(cache_info->signature == MagickSignature);
3772 if (attach != MagickFalse)
3775 Attach existing persistent pixel cache.
3777 if (image->debug != MagickFalse)
3778 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3779 "attach persistent cache");
3780 (void) CopyMagickString(cache_info->cache_filename,filename,
3782 cache_info->type=DiskCache;
3783 cache_info->offset=(*offset);
3784 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3785 return(MagickFalse);
3786 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3789 if ((cache_info->mode != ReadMode) &&
3790 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3791 (cache_info->reference_count == 1))
3793 LockSemaphoreInfo(cache_info->semaphore);
3794 if ((cache_info->mode != ReadMode) &&
3795 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3796 (cache_info->reference_count == 1))
3802 Usurp existing persistent pixel cache.
3804 status=rename_utf8(cache_info->cache_filename,filename);
3807 (void) CopyMagickString(cache_info->cache_filename,filename,
3809 *offset+=cache_info->length+page_size-(cache_info->length %
3811 UnlockSemaphoreInfo(cache_info->semaphore);
3812 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3813 if (image->debug != MagickFalse)
3814 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3815 "Usurp resident persistent cache");
3819 UnlockSemaphoreInfo(cache_info->semaphore);
3822 Clone persistent pixel cache.
3824 clone_image=(*image);
3825 clone_info=(CacheInfo *) clone_image.cache;
3826 image->cache=ClonePixelCache(cache_info);
3827 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3828 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3829 cache_info->type=DiskCache;
3830 cache_info->offset=(*offset);
3831 cache_info=(CacheInfo *) image->cache;
3832 status=OpenPixelCache(image,IOMode,exception);
3833 if (status != MagickFalse)
3834 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3835 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3836 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3845 + 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 %
3849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3851 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3852 % defined by the region rectangle and returns a pointer to the region. This
3853 % region is subsequently transferred from the pixel cache with
3854 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3855 % pixels are transferred, otherwise a NULL is returned.
3857 % The format of the QueueAuthenticPixelCacheNexus() method is:
3859 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3860 % const ssize_t y,const size_t columns,const size_t rows,
3861 % const MagickBooleanType clone,NexusInfo *nexus_info,
3862 % ExceptionInfo *exception)
3864 % A description of each parameter follows:
3866 % o image: the image.
3868 % o x,y,columns,rows: These values define the perimeter of a region of
3871 % o nexus_info: the cache nexus to set.
3873 % o clone: clone the pixel cache.
3875 % o exception: return any errors or warnings in this structure.
3878 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3879 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3880 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3898 Validate pixel cache geometry.
3900 assert(image != (const Image *) NULL);
3901 assert(image->signature == MagickSignature);
3902 assert(image->cache != (Cache) NULL);
3903 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3904 if (cache_info == (Cache) NULL)
3905 return((Quantum *) NULL);
3906 assert(cache_info->signature == MagickSignature);
3907 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3908 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3909 (y >= (ssize_t) cache_info->rows))
3911 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3912 "PixelsAreNotAuthentic","`%s'",image->filename);
3913 return((Quantum *) NULL);
3915 offset=(MagickOffsetType) y*cache_info->columns+x;
3917 return((Quantum *) NULL);
3918 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3919 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3920 if ((MagickSizeType) offset >= number_pixels)
3921 return((Quantum *) NULL);
3927 region.width=columns;
3929 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3935 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3939 + 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 %
3943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3945 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3946 % defined by the region rectangle and returns a pointer to the region. This
3947 % region is subsequently transferred from the pixel cache with
3948 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3949 % pixels are transferred, otherwise a NULL is returned.
3951 % The format of the QueueAuthenticPixelsCache() method is:
3953 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3954 % const ssize_t y,const size_t columns,const size_t rows,
3955 % ExceptionInfo *exception)
3957 % A description of each parameter follows:
3959 % o image: the image.
3961 % o x,y,columns,rows: These values define the perimeter of a region of
3964 % o exception: return any errors or warnings in this structure.
3967 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3968 const ssize_t y,const size_t columns,const size_t rows,
3969 ExceptionInfo *exception)
3975 id = GetOpenMPThreadId();
3980 assert(image != (const Image *) NULL);
3981 assert(image->signature == MagickSignature);
3982 assert(image->cache != (Cache) NULL);
3983 cache_info=(CacheInfo *) image->cache;
3984 assert(cache_info->signature == MagickSignature);
3985 assert(id < (int) cache_info->number_threads);
3986 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3987 cache_info->nexus_info[id],exception);
3992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3996 % Q u e u e A u t h e n t i c P i x e l s %
4000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4002 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4003 % successfully initialized a pointer to a Quantum array representing the
4004 % region is returned, otherwise NULL is returned. The returned pointer may
4005 % point to a temporary working buffer for the pixels or it may point to the
4006 % final location of the pixels in memory.
4008 % Write-only access means that any existing pixel values corresponding to
4009 % the region are ignored. This is useful if the initial image is being
4010 % created from scratch, or if the existing pixel values are to be
4011 % completely replaced without need to refer to their pre-existing values.
4012 % The application is free to read and write the pixel buffer returned by
4013 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4014 % initialize the pixel array values. Initializing pixel array values is the
4015 % application's responsibility.
4017 % Performance is maximized if the selected region is part of one row, or
4018 % one or more full rows, since then there is opportunity to access the
4019 % pixels in-place (without a copy) if the image is in memory, or in a
4020 % memory-mapped file. The returned pointer must *never* be deallocated
4023 % Pixels accessed via the returned pointer represent a simple array of type
4024 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4025 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4026 % obtain the meta-content (of type void) corresponding to the region.
4027 % Once the Quantum (and/or Quantum) array has been updated, the
4028 % changes must be saved back to the underlying image using
4029 % SyncAuthenticPixels() or they may be lost.
4031 % The format of the QueueAuthenticPixels() method is:
4033 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4034 % const ssize_t y,const size_t columns,const size_t rows,
4035 % ExceptionInfo *exception)
4037 % A description of each parameter follows:
4039 % o image: the image.
4041 % o x,y,columns,rows: These values define the perimeter of a region of
4044 % o exception: return any errors or warnings in this structure.
4047 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4048 const ssize_t y,const size_t columns,const size_t rows,
4049 ExceptionInfo *exception)
4055 id = GetOpenMPThreadId();
4060 assert(image != (Image *) NULL);
4061 assert(image->signature == MagickSignature);
4062 assert(image->cache != (Cache) NULL);
4063 cache_info=(CacheInfo *) image->cache;
4064 assert(cache_info->signature == MagickSignature);
4065 if (cache_info->methods.queue_authentic_pixels_handler !=
4066 (QueueAuthenticPixelsHandler) NULL)
4068 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4069 columns,rows,exception);
4072 assert(id < (int) cache_info->number_threads);
4073 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4074 cache_info->nexus_info[id],exception);
4079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4083 + 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 %
4087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4089 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4092 % The format of the ReadPixelCacheMetacontent() method is:
4094 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4095 % NexusInfo *nexus_info,ExceptionInfo *exception)
4097 % A description of each parameter follows:
4099 % o cache_info: the pixel cache.
4101 % o nexus_info: the cache nexus to read the metacontent.
4103 % o exception: return any errors or warnings in this structure.
4107 static inline MagickOffsetType ReadPixelCacheRegion(
4108 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4109 const MagickSizeType length,unsigned char *restrict buffer)
4111 register MagickOffsetType
4117 #if !defined(MAGICKCORE_HAVE_PREAD)
4118 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4119 return((MagickOffsetType) -1);
4122 for (i=0; i < (MagickOffsetType) length; i+=count)
4124 #if !defined(MAGICKCORE_HAVE_PREAD)
4125 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4126 (MagickSizeType) SSIZE_MAX));
4128 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4129 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4141 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4142 NexusInfo *nexus_info,ExceptionInfo *exception)
4155 register unsigned char
4161 if (cache_info->metacontent_extent == 0)
4162 return(MagickFalse);
4163 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4165 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4166 nexus_info->region.x;
4167 length=(MagickSizeType) nexus_info->region.width*
4168 cache_info->metacontent_extent;
4169 extent=length*nexus_info->region.height;
4170 rows=nexus_info->region.height;
4172 q=(unsigned char *) nexus_info->metacontent;
4173 switch (cache_info->type)
4178 register unsigned char
4182 Read meta-content from memory.
4184 if ((cache_info->columns == nexus_info->region.width) &&
4185 (extent == (MagickSizeType) ((size_t) extent)))
4190 p=(unsigned char *) cache_info->metacontent+offset*
4191 cache_info->metacontent_extent;
4192 for (y=0; y < (ssize_t) rows; y++)
4194 (void) memcpy(q,p,(size_t) length);
4195 p+=cache_info->metacontent_extent*cache_info->columns;
4196 q+=cache_info->metacontent_extent*nexus_info->region.width;
4203 Read meta content from disk.
4205 LockSemaphoreInfo(cache_info->file_semaphore);
4206 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4208 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4209 cache_info->cache_filename);
4210 UnlockSemaphoreInfo(cache_info->file_semaphore);
4211 return(MagickFalse);
4213 if ((cache_info->columns == nexus_info->region.width) &&
4214 (extent <= MagickMaxBufferExtent))
4219 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4220 for (y=0; y < (ssize_t) rows; y++)
4222 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4223 cache_info->number_channels*sizeof(Quantum)+offset*
4224 cache_info->metacontent_extent,length,(unsigned char *) q);
4225 if (count != (MagickOffsetType) length)
4227 offset+=cache_info->columns;
4228 q+=cache_info->metacontent_extent*nexus_info->region.width;
4230 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4231 (void) ClosePixelCacheOnDisk(cache_info);
4232 UnlockSemaphoreInfo(cache_info->file_semaphore);
4235 case DistributedCache:
4241 Read metacontent from distributed cache.
4243 LockSemaphoreInfo(cache_info->file_semaphore);
4244 region=nexus_info->region;
4245 if ((cache_info->columns != nexus_info->region.width) ||
4246 (extent > MagickMaxBufferExtent))
4253 for (y=0; y < (ssize_t) rows; y++)
4255 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4256 cache_info->server_info,®ion,length,(unsigned char *) q);
4257 if (count != (MagickOffsetType) length)
4259 q+=cache_info->metacontent_extent*nexus_info->region.width;
4262 UnlockSemaphoreInfo(cache_info->file_semaphore);
4268 if (y < (ssize_t) rows)
4270 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4271 cache_info->cache_filename);
4272 return(MagickFalse);
4274 if ((cache_info->debug != MagickFalse) &&
4275 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4276 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4277 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4278 nexus_info->region.width,(double) nexus_info->region.height,(double)
4279 nexus_info->region.x,(double) nexus_info->region.y);
4284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4288 + R e a d P i x e l C a c h e P i x e l s %
4292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4294 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4297 % The format of the ReadPixelCachePixels() method is:
4299 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4300 % NexusInfo *nexus_info,ExceptionInfo *exception)
4302 % A description of each parameter follows:
4304 % o cache_info: the pixel cache.
4306 % o nexus_info: the cache nexus to read the pixels.
4308 % o exception: return any errors or warnings in this structure.
4311 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4312 NexusInfo *nexus_info,ExceptionInfo *exception)
4331 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4333 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4334 nexus_info->region.x;
4335 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4337 extent=length*nexus_info->region.height;
4338 rows=nexus_info->region.height;
4340 q=nexus_info->pixels;
4341 switch (cache_info->type)
4350 Read pixels from memory.
4352 if ((cache_info->columns == nexus_info->region.width) &&
4353 (extent == (MagickSizeType) ((size_t) extent)))
4358 p=cache_info->pixels+offset*cache_info->number_channels;
4359 for (y=0; y < (ssize_t) rows; y++)
4361 (void) memcpy(q,p,(size_t) length);
4362 p+=cache_info->number_channels*cache_info->columns;
4363 q+=cache_info->number_channels*nexus_info->region.width;
4370 Read pixels from disk.
4372 LockSemaphoreInfo(cache_info->file_semaphore);
4373 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4375 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4376 cache_info->cache_filename);
4377 UnlockSemaphoreInfo(cache_info->file_semaphore);
4378 return(MagickFalse);
4380 if ((cache_info->columns == nexus_info->region.width) &&
4381 (extent <= MagickMaxBufferExtent))
4386 for (y=0; y < (ssize_t) rows; y++)
4388 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4389 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4390 if (count != (MagickOffsetType) length)
4392 offset+=cache_info->columns;
4393 q+=cache_info->number_channels*nexus_info->region.width;
4395 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4396 (void) ClosePixelCacheOnDisk(cache_info);
4397 UnlockSemaphoreInfo(cache_info->file_semaphore);
4400 case DistributedCache:
4406 Read pixels from distributed cache.
4408 LockSemaphoreInfo(cache_info->file_semaphore);
4409 region=nexus_info->region;
4410 if ((cache_info->columns != nexus_info->region.width) ||
4411 (extent > MagickMaxBufferExtent))
4418 for (y=0; y < (ssize_t) rows; y++)
4420 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4421 cache_info->server_info,®ion,length,(unsigned char *) q);
4422 if (count != (MagickOffsetType) length)
4424 q+=cache_info->number_channels*nexus_info->region.width;
4427 UnlockSemaphoreInfo(cache_info->file_semaphore);
4433 if (y < (ssize_t) rows)
4435 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4436 cache_info->cache_filename);
4437 return(MagickFalse);
4439 if ((cache_info->debug != MagickFalse) &&
4440 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4441 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4442 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4443 nexus_info->region.width,(double) nexus_info->region.height,(double)
4444 nexus_info->region.x,(double) nexus_info->region.y);
4449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4453 + R e f e r e n c e P i x e l C a c h e %
4457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4459 % ReferencePixelCache() increments the reference count associated with the
4460 % pixel cache returning a pointer to the cache.
4462 % The format of the ReferencePixelCache method is:
4464 % Cache ReferencePixelCache(Cache cache_info)
4466 % A description of each parameter follows:
4468 % o cache_info: the pixel cache.
4471 MagickPrivate Cache ReferencePixelCache(Cache cache)
4476 assert(cache != (Cache *) NULL);
4477 cache_info=(CacheInfo *) cache;
4478 assert(cache_info->signature == MagickSignature);
4479 LockSemaphoreInfo(cache_info->semaphore);
4480 cache_info->reference_count++;
4481 UnlockSemaphoreInfo(cache_info->semaphore);
4486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4490 + S e t P i x e l C a c h e M e t h o d s %
4494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4496 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4498 % The format of the SetPixelCacheMethods() method is:
4500 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4502 % A description of each parameter follows:
4504 % o cache: the pixel cache.
4506 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4509 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4514 GetOneAuthenticPixelFromHandler
4515 get_one_authentic_pixel_from_handler;
4517 GetOneVirtualPixelFromHandler
4518 get_one_virtual_pixel_from_handler;
4521 Set cache pixel methods.
4523 assert(cache != (Cache) NULL);
4524 assert(cache_methods != (CacheMethods *) NULL);
4525 cache_info=(CacheInfo *) cache;
4526 assert(cache_info->signature == MagickSignature);
4527 if (cache_info->debug != MagickFalse)
4528 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4529 cache_info->filename);
4530 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4531 cache_info->methods.get_virtual_pixel_handler=
4532 cache_methods->get_virtual_pixel_handler;
4533 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4534 cache_info->methods.destroy_pixel_handler=
4535 cache_methods->destroy_pixel_handler;
4536 if (cache_methods->get_virtual_metacontent_from_handler !=
4537 (GetVirtualMetacontentFromHandler) NULL)
4538 cache_info->methods.get_virtual_metacontent_from_handler=
4539 cache_methods->get_virtual_metacontent_from_handler;
4540 if (cache_methods->get_authentic_pixels_handler !=
4541 (GetAuthenticPixelsHandler) NULL)
4542 cache_info->methods.get_authentic_pixels_handler=
4543 cache_methods->get_authentic_pixels_handler;
4544 if (cache_methods->queue_authentic_pixels_handler !=
4545 (QueueAuthenticPixelsHandler) NULL)
4546 cache_info->methods.queue_authentic_pixels_handler=
4547 cache_methods->queue_authentic_pixels_handler;
4548 if (cache_methods->sync_authentic_pixels_handler !=
4549 (SyncAuthenticPixelsHandler) NULL)
4550 cache_info->methods.sync_authentic_pixels_handler=
4551 cache_methods->sync_authentic_pixels_handler;
4552 if (cache_methods->get_authentic_pixels_from_handler !=
4553 (GetAuthenticPixelsFromHandler) NULL)
4554 cache_info->methods.get_authentic_pixels_from_handler=
4555 cache_methods->get_authentic_pixels_from_handler;
4556 if (cache_methods->get_authentic_metacontent_from_handler !=
4557 (GetAuthenticMetacontentFromHandler) NULL)
4558 cache_info->methods.get_authentic_metacontent_from_handler=
4559 cache_methods->get_authentic_metacontent_from_handler;
4560 get_one_virtual_pixel_from_handler=
4561 cache_info->methods.get_one_virtual_pixel_from_handler;
4562 if (get_one_virtual_pixel_from_handler !=
4563 (GetOneVirtualPixelFromHandler) NULL)
4564 cache_info->methods.get_one_virtual_pixel_from_handler=
4565 cache_methods->get_one_virtual_pixel_from_handler;
4566 get_one_authentic_pixel_from_handler=
4567 cache_methods->get_one_authentic_pixel_from_handler;
4568 if (get_one_authentic_pixel_from_handler !=
4569 (GetOneAuthenticPixelFromHandler) NULL)
4570 cache_info->methods.get_one_authentic_pixel_from_handler=
4571 cache_methods->get_one_authentic_pixel_from_handler;
4575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4579 + S e t P i x e l C a c h e N e x u s P i x e l s %
4583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4585 % SetPixelCacheNexusPixels() defines the region of the cache for the
4586 % specified cache nexus.
4588 % The format of the SetPixelCacheNexusPixels() method is:
4590 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4591 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4592 % ExceptionInfo *exception)
4594 % A description of each parameter follows:
4596 % o cache_info: the pixel cache.
4598 % o mode: ReadMode, WriteMode, or IOMode.
4600 % o region: A pointer to the RectangleInfo structure that defines the
4601 % region of this particular cache nexus.
4603 % o nexus_info: the cache nexus to set.
4605 % o exception: return any errors or warnings in this structure.
4609 static inline MagickBooleanType AcquireCacheNexusPixels(
4610 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4611 ExceptionInfo *exception)
4613 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4614 return(MagickFalse);
4615 nexus_info->mapped=MagickFalse;
4616 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4617 (size_t) nexus_info->length));
4618 if (nexus_info->cache == (Quantum *) NULL)
4620 nexus_info->mapped=MagickTrue;
4621 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4622 nexus_info->length);
4624 if (nexus_info->cache == (Quantum *) NULL)
4626 (void) ThrowMagickException(exception,GetMagickModule(),
4627 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4628 cache_info->filename);
4629 return(MagickFalse);
4634 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4637 if (mode == ReadMode)
4639 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4642 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4645 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4646 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4647 ExceptionInfo *exception)
4656 assert(cache_info != (const CacheInfo *) NULL);
4657 assert(cache_info->signature == MagickSignature);
4658 if (cache_info->type == UndefinedCache)
4659 return((Quantum *) NULL);
4660 nexus_info->region=(*region);
4661 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4667 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4668 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4669 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4670 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4671 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4672 ((nexus_info->region.width == cache_info->columns) ||
4673 ((nexus_info->region.width % cache_info->columns) == 0)))))
4679 Pixels are accessed directly from memory.
4681 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4682 nexus_info->region.x;
4683 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4685 nexus_info->metacontent=(void *) NULL;
4686 if (cache_info->metacontent_extent != 0)
4687 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4688 offset*cache_info->metacontent_extent;
4689 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4690 return(nexus_info->pixels);
4694 Pixels are stored in a cache region until they are synced to the cache.
4696 number_pixels=(MagickSizeType) nexus_info->region.width*
4697 nexus_info->region.height;
4698 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4699 if (cache_info->metacontent_extent != 0)
4700 length+=number_pixels*cache_info->metacontent_extent;
4701 if (nexus_info->cache == (Quantum *) NULL)
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);
4712 if (nexus_info->length != length)
4714 RelinquishCacheNexusPixels(nexus_info);
4715 nexus_info->length=length;
4716 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4717 if (status == MagickFalse)
4719 nexus_info->length=0;
4720 return((Quantum *) NULL);
4723 nexus_info->pixels=nexus_info->cache;
4724 nexus_info->metacontent=(void *) NULL;
4725 if (cache_info->metacontent_extent != 0)
4726 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4727 cache_info->number_channels);
4728 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4729 return(nexus_info->pixels);
4733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4737 % 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 %
4741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4743 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4744 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4745 % access that is outside the boundaries of the image cache.
4747 % The format of the SetPixelCacheVirtualMethod() method is:
4749 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4750 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4752 % A description of each parameter follows:
4754 % o image: the image.
4756 % o virtual_pixel_method: choose the type of virtual pixel.
4758 % o exception: return any errors or warnings in this structure.
4762 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4763 ExceptionInfo *exception)
4777 assert(image != (Image *) NULL);
4778 assert(image->signature == MagickSignature);
4779 if (image->debug != MagickFalse)
4780 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4781 assert(image->cache != (Cache) NULL);
4782 cache_info=(CacheInfo *) image->cache;
4783 assert(cache_info->signature == MagickSignature);
4784 image->alpha_trait=BlendPixelTrait;
4786 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4787 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4788 #pragma omp parallel for schedule(static,4) shared(status) \
4789 magick_threads(image,image,1,1)
4791 for (y=0; y < (ssize_t) image->rows; y++)
4799 if (status == MagickFalse)
4801 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4802 if (q == (Quantum *) NULL)
4807 for (x=0; x < (ssize_t) image->columns; x++)
4809 SetPixelAlpha(image,alpha,q);
4810 q+=GetPixelChannels(image);
4812 status=SyncCacheViewAuthenticPixels(image_view,exception);
4814 image_view=DestroyCacheView(image_view);
4818 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4819 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4827 assert(image != (Image *) NULL);
4828 assert(image->signature == MagickSignature);
4829 if (image->debug != MagickFalse)
4830 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4831 assert(image->cache != (Cache) NULL);
4832 cache_info=(CacheInfo *) image->cache;
4833 assert(cache_info->signature == MagickSignature);
4834 method=cache_info->virtual_pixel_method;
4835 cache_info->virtual_pixel_method=virtual_pixel_method;
4836 if ((image->columns != 0) && (image->rows != 0))
4837 switch (virtual_pixel_method)
4839 case BackgroundVirtualPixelMethod:
4841 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4842 (image->alpha_trait != BlendPixelTrait))
4843 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4844 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4845 (IsGrayColorspace(image->colorspace) != MagickFalse))
4846 (void) TransformImageColorspace(image,RGBColorspace,exception);
4849 case TransparentVirtualPixelMethod:
4851 if (image->alpha_trait != BlendPixelTrait)
4852 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866 + 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 %
4870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4872 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4873 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4874 % is synced, otherwise MagickFalse.
4876 % The format of the SyncAuthenticPixelCacheNexus() method is:
4878 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4879 % NexusInfo *nexus_info,ExceptionInfo *exception)
4881 % A description of each parameter follows:
4883 % o image: the image.
4885 % o nexus_info: the cache nexus to sync.
4887 % o exception: return any errors or warnings in this structure.
4890 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4891 NexusInfo *nexus_info,ExceptionInfo *exception)
4900 Transfer pixels to the cache.
4902 assert(image != (Image *) NULL);
4903 assert(image->signature == MagickSignature);
4904 if (image->cache == (Cache) NULL)
4905 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4906 cache_info=(CacheInfo *) image->cache;
4907 assert(cache_info->signature == MagickSignature);
4908 if (cache_info->type == UndefinedCache)
4909 return(MagickFalse);
4910 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4912 assert(cache_info->signature == MagickSignature);
4913 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4914 if ((cache_info->metacontent_extent != 0) &&
4915 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4916 return(MagickFalse);
4921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4925 + S y n c A u t h e n t i c P i x e l C a c h e %
4929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4931 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4932 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4933 % otherwise MagickFalse.
4935 % The format of the SyncAuthenticPixelsCache() method is:
4937 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4938 % ExceptionInfo *exception)
4940 % A description of each parameter follows:
4942 % o image: the image.
4944 % o exception: return any errors or warnings in this structure.
4947 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4948 ExceptionInfo *exception)
4954 id = GetOpenMPThreadId();
4959 assert(image != (Image *) NULL);
4960 assert(image->signature == MagickSignature);
4961 assert(image->cache != (Cache) NULL);
4962 cache_info=(CacheInfo *) image->cache;
4963 assert(cache_info->signature == MagickSignature);
4964 assert(id < (int) cache_info->number_threads);
4965 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4975 % S y n c A u t h e n t i c P i x e l s %
4979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4981 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4982 % The method returns MagickTrue if the pixel region is flushed, otherwise
4985 % The format of the SyncAuthenticPixels() method is:
4987 % MagickBooleanType SyncAuthenticPixels(Image *image,
4988 % ExceptionInfo *exception)
4990 % A description of each parameter follows:
4992 % o image: the image.
4994 % o exception: return any errors or warnings in this structure.
4997 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4998 ExceptionInfo *exception)
5004 id = GetOpenMPThreadId();
5009 assert(image != (Image *) NULL);
5010 assert(image->signature == MagickSignature);
5011 assert(image->cache != (Cache) NULL);
5012 cache_info=(CacheInfo *) image->cache;
5013 assert(cache_info->signature == MagickSignature);
5014 if (cache_info->methods.sync_authentic_pixels_handler !=
5015 (SyncAuthenticPixelsHandler) NULL)
5017 status=cache_info->methods.sync_authentic_pixels_handler(image,
5021 assert(id < (int) cache_info->number_threads);
5022 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5032 + S y n c I m a g e P i x e l C a c h e %
5036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5038 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5039 % The method returns MagickTrue if the pixel region is flushed, otherwise
5042 % The format of the SyncImagePixelCache() method is:
5044 % MagickBooleanType SyncImagePixelCache(Image *image,
5045 % ExceptionInfo *exception)
5047 % A description of each parameter follows:
5049 % o image: the image.
5051 % o exception: return any errors or warnings in this structure.
5054 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5055 ExceptionInfo *exception)
5060 assert(image != (Image *) NULL);
5061 assert(exception != (ExceptionInfo *) NULL);
5062 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5063 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5071 + 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 %
5075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5077 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5078 % of the pixel cache.
5080 % The format of the WritePixelCacheMetacontent() method is:
5082 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5083 % NexusInfo *nexus_info,ExceptionInfo *exception)
5085 % A description of each parameter follows:
5087 % o cache_info: the pixel cache.
5089 % o nexus_info: the cache nexus to write the meta-content.
5091 % o exception: return any errors or warnings in this structure.
5094 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5095 NexusInfo *nexus_info,ExceptionInfo *exception)
5105 register const unsigned char
5114 if (cache_info->metacontent_extent == 0)
5115 return(MagickFalse);
5116 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5118 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5119 nexus_info->region.x;
5120 length=(MagickSizeType) nexus_info->region.width*
5121 cache_info->metacontent_extent;
5122 extent=(MagickSizeType) length*nexus_info->region.height;
5123 rows=nexus_info->region.height;
5125 p=(unsigned char *) nexus_info->metacontent;
5126 switch (cache_info->type)
5131 register unsigned char
5135 Write associated pixels to memory.
5137 if ((cache_info->columns == nexus_info->region.width) &&
5138 (extent == (MagickSizeType) ((size_t) extent)))
5143 q=(unsigned char *) cache_info->metacontent+offset*
5144 cache_info->metacontent_extent;
5145 for (y=0; y < (ssize_t) rows; y++)
5147 (void) memcpy(q,p,(size_t) length);
5148 p+=nexus_info->region.width*cache_info->metacontent_extent;
5149 q+=cache_info->columns*cache_info->metacontent_extent;
5156 Write associated pixels to disk.
5158 LockSemaphoreInfo(cache_info->file_semaphore);
5159 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5161 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5162 cache_info->cache_filename);
5163 UnlockSemaphoreInfo(cache_info->file_semaphore);
5164 return(MagickFalse);
5166 if ((cache_info->columns == nexus_info->region.width) &&
5167 (extent <= MagickMaxBufferExtent))
5172 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5173 for (y=0; y < (ssize_t) rows; y++)
5175 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5176 cache_info->number_channels*sizeof(Quantum)+offset*
5177 cache_info->metacontent_extent,length,(const unsigned char *) p);
5178 if (count != (MagickOffsetType) length)
5180 p+=cache_info->metacontent_extent*nexus_info->region.width;
5181 offset+=cache_info->columns;
5183 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5184 (void) ClosePixelCacheOnDisk(cache_info);
5185 UnlockSemaphoreInfo(cache_info->file_semaphore);
5188 case DistributedCache:
5194 Write metacontent to distributed cache.
5196 LockSemaphoreInfo(cache_info->file_semaphore);
5197 region=nexus_info->region;
5198 if ((cache_info->columns != nexus_info->region.width) ||
5199 (extent > MagickMaxBufferExtent))
5206 for (y=0; y < (ssize_t) rows; y++)
5208 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5209 cache_info->server_info,®ion,length,(const unsigned char *) p);
5210 if (count != (MagickOffsetType) length)
5212 p+=cache_info->metacontent_extent*nexus_info->region.width;
5215 UnlockSemaphoreInfo(cache_info->file_semaphore);
5221 if (y < (ssize_t) rows)
5223 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5224 cache_info->cache_filename);
5225 return(MagickFalse);
5227 if ((cache_info->debug != MagickFalse) &&
5228 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5229 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5230 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5231 nexus_info->region.width,(double) nexus_info->region.height,(double)
5232 nexus_info->region.x,(double) nexus_info->region.y);
5237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5241 + W r i t e C a c h e P i x e l s %
5245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5247 % WritePixelCachePixels() writes image pixels to the specified region of the
5250 % The format of the WritePixelCachePixels() method is:
5252 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5253 % NexusInfo *nexus_info,ExceptionInfo *exception)
5255 % A description of each parameter follows:
5257 % o cache_info: the pixel cache.
5259 % o nexus_info: the cache nexus to write the pixels.
5261 % o exception: return any errors or warnings in this structure.
5264 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5265 NexusInfo *nexus_info,ExceptionInfo *exception)
5275 register const Quantum
5284 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5286 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5287 nexus_info->region.x;
5288 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5290 extent=length*nexus_info->region.height;
5291 rows=nexus_info->region.height;
5293 p=nexus_info->pixels;
5294 switch (cache_info->type)
5303 Write pixels to memory.
5305 if ((cache_info->columns == nexus_info->region.width) &&
5306 (extent == (MagickSizeType) ((size_t) extent)))
5311 q=cache_info->pixels+offset*cache_info->number_channels;
5312 for (y=0; y < (ssize_t) rows; y++)
5314 (void) memcpy(q,p,(size_t) length);
5315 p+=cache_info->number_channels*nexus_info->region.width;
5316 q+=cache_info->columns*cache_info->number_channels;
5323 Write pixels to disk.
5325 LockSemaphoreInfo(cache_info->file_semaphore);
5326 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5328 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5329 cache_info->cache_filename);
5330 UnlockSemaphoreInfo(cache_info->file_semaphore);
5331 return(MagickFalse);
5333 if ((cache_info->columns == nexus_info->region.width) &&
5334 (extent <= MagickMaxBufferExtent))
5339 for (y=0; y < (ssize_t) rows; y++)
5341 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5342 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5344 if (count != (MagickOffsetType) length)
5346 p+=cache_info->number_channels*nexus_info->region.width;
5347 offset+=cache_info->columns;
5349 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5350 (void) ClosePixelCacheOnDisk(cache_info);
5351 UnlockSemaphoreInfo(cache_info->file_semaphore);
5354 case DistributedCache:
5360 Write pixels to distributed cache.
5362 LockSemaphoreInfo(cache_info->file_semaphore);
5363 region=nexus_info->region;
5364 if ((cache_info->columns != nexus_info->region.width) ||
5365 (extent > MagickMaxBufferExtent))
5372 for (y=0; y < (ssize_t) rows; y++)
5374 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5375 cache_info->server_info,®ion,length,(const unsigned char *) p);
5376 if (count != (MagickOffsetType) length)
5378 p+=cache_info->number_channels*nexus_info->region.width;
5381 UnlockSemaphoreInfo(cache_info->file_semaphore);
5387 if (y < (ssize_t) rows)
5389 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5390 cache_info->cache_filename);
5391 return(MagickFalse);
5393 if ((cache_info->debug != MagickFalse) &&
5394 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5395 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5396 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5397 nexus_info->region.width,(double) nexus_info->region.height,(double)
5398 nexus_info->region.x,(double) nexus_info->region.y);