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,
1130 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1131 NexusInfo *nexus_info,ExceptionInfo *exception)
1140 Transfer pixels from the cache.
1142 assert(image != (Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1146 if (q == (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 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1313 assert(id < (int) cache_info->number_threads);
1314 q=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 q=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))
3909 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3910 "NoPixelsDefinedInCache","`%s'",image->filename);
3911 return((Quantum *) NULL);
3913 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3914 (y >= (ssize_t) cache_info->rows))
3916 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3917 "PixelsAreNotAuthentic","`%s'",image->filename);
3918 return((Quantum *) NULL);
3920 offset=(MagickOffsetType) y*cache_info->columns+x;
3922 return((Quantum *) NULL);
3923 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3924 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3925 if ((MagickSizeType) offset >= number_pixels)
3926 return((Quantum *) NULL);
3932 region.width=columns;
3934 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3944 + 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 %
3948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3950 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3951 % defined by the region rectangle and returns a pointer to the region. This
3952 % region is subsequently transferred from the pixel cache with
3953 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3954 % pixels are transferred, otherwise a NULL is returned.
3956 % The format of the QueueAuthenticPixelsCache() method is:
3958 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3959 % const ssize_t y,const size_t columns,const size_t rows,
3960 % ExceptionInfo *exception)
3962 % A description of each parameter follows:
3964 % o image: the image.
3966 % o x,y,columns,rows: These values define the perimeter of a region of
3969 % o exception: return any errors or warnings in this structure.
3972 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3973 const ssize_t y,const size_t columns,const size_t rows,
3974 ExceptionInfo *exception)
3980 id = GetOpenMPThreadId();
3985 assert(image != (const Image *) NULL);
3986 assert(image->signature == MagickSignature);
3987 assert(image->cache != (Cache) NULL);
3988 cache_info=(CacheInfo *) image->cache;
3989 assert(cache_info->signature == MagickSignature);
3990 assert(id < (int) cache_info->number_threads);
3991 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3992 cache_info->nexus_info[id],exception);
3997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4001 % Q u e u e A u t h e n t i c P i x e l s %
4005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4007 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4008 % successfully initialized a pointer to a Quantum array representing the
4009 % region is returned, otherwise NULL is returned. The returned pointer may
4010 % point to a temporary working buffer for the pixels or it may point to the
4011 % final location of the pixels in memory.
4013 % Write-only access means that any existing pixel values corresponding to
4014 % the region are ignored. This is useful if the initial image is being
4015 % created from scratch, or if the existing pixel values are to be
4016 % completely replaced without need to refer to their pre-existing values.
4017 % The application is free to read and write the pixel buffer returned by
4018 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4019 % initialize the pixel array values. Initializing pixel array values is the
4020 % application's responsibility.
4022 % Performance is maximized if the selected region is part of one row, or
4023 % one or more full rows, since then there is opportunity to access the
4024 % pixels in-place (without a copy) if the image is in memory, or in a
4025 % memory-mapped file. The returned pointer must *never* be deallocated
4028 % Pixels accessed via the returned pointer represent a simple array of type
4029 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4030 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4031 % obtain the meta-content (of type void) corresponding to the region.
4032 % Once the Quantum (and/or Quantum) array has been updated, the
4033 % changes must be saved back to the underlying image using
4034 % SyncAuthenticPixels() or they may be lost.
4036 % The format of the QueueAuthenticPixels() method is:
4038 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4039 % const ssize_t y,const size_t columns,const size_t rows,
4040 % ExceptionInfo *exception)
4042 % A description of each parameter follows:
4044 % o image: the image.
4046 % o x,y,columns,rows: These values define the perimeter of a region of
4049 % o exception: return any errors or warnings in this structure.
4052 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4053 const ssize_t y,const size_t columns,const size_t rows,
4054 ExceptionInfo *exception)
4060 id = GetOpenMPThreadId();
4065 assert(image != (Image *) NULL);
4066 assert(image->signature == MagickSignature);
4067 assert(image->cache != (Cache) NULL);
4068 cache_info=(CacheInfo *) image->cache;
4069 assert(cache_info->signature == MagickSignature);
4070 if (cache_info->methods.queue_authentic_pixels_handler !=
4071 (QueueAuthenticPixelsHandler) NULL)
4073 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4077 assert(id < (int) cache_info->number_threads);
4078 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4079 cache_info->nexus_info[id],exception);
4084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4088 + 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 %
4092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4094 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4097 % The format of the ReadPixelCacheMetacontent() method is:
4099 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4100 % NexusInfo *nexus_info,ExceptionInfo *exception)
4102 % A description of each parameter follows:
4104 % o cache_info: the pixel cache.
4106 % o nexus_info: the cache nexus to read the metacontent.
4108 % o exception: return any errors or warnings in this structure.
4112 static inline MagickOffsetType ReadPixelCacheRegion(
4113 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4114 const MagickSizeType length,unsigned char *restrict buffer)
4116 register MagickOffsetType
4122 #if !defined(MAGICKCORE_HAVE_PREAD)
4123 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4124 return((MagickOffsetType) -1);
4127 for (i=0; i < (MagickOffsetType) length; i+=count)
4129 #if !defined(MAGICKCORE_HAVE_PREAD)
4130 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4131 (MagickSizeType) SSIZE_MAX));
4133 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4134 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4146 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4147 NexusInfo *nexus_info,ExceptionInfo *exception)
4160 register unsigned char
4166 if (cache_info->metacontent_extent == 0)
4167 return(MagickFalse);
4168 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4170 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4171 nexus_info->region.x;
4172 length=(MagickSizeType) nexus_info->region.width*
4173 cache_info->metacontent_extent;
4174 extent=length*nexus_info->region.height;
4175 rows=nexus_info->region.height;
4177 q=(unsigned char *) nexus_info->metacontent;
4178 switch (cache_info->type)
4183 register unsigned char
4187 Read meta-content from memory.
4189 if ((cache_info->columns == nexus_info->region.width) &&
4190 (extent == (MagickSizeType) ((size_t) extent)))
4195 p=(unsigned char *) cache_info->metacontent+offset*
4196 cache_info->metacontent_extent;
4197 for (y=0; y < (ssize_t) rows; y++)
4199 (void) memcpy(q,p,(size_t) length);
4200 p+=cache_info->metacontent_extent*cache_info->columns;
4201 q+=cache_info->metacontent_extent*nexus_info->region.width;
4208 Read meta content from disk.
4210 LockSemaphoreInfo(cache_info->file_semaphore);
4211 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4213 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4214 cache_info->cache_filename);
4215 UnlockSemaphoreInfo(cache_info->file_semaphore);
4216 return(MagickFalse);
4218 if ((cache_info->columns == nexus_info->region.width) &&
4219 (extent <= MagickMaxBufferExtent))
4224 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4225 for (y=0; y < (ssize_t) rows; y++)
4227 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4228 cache_info->number_channels*sizeof(Quantum)+offset*
4229 cache_info->metacontent_extent,length,(unsigned char *) q);
4230 if (count != (MagickOffsetType) length)
4232 offset+=cache_info->columns;
4233 q+=cache_info->metacontent_extent*nexus_info->region.width;
4235 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4236 (void) ClosePixelCacheOnDisk(cache_info);
4237 UnlockSemaphoreInfo(cache_info->file_semaphore);
4240 case DistributedCache:
4246 Read metacontent from distributed cache.
4248 LockSemaphoreInfo(cache_info->file_semaphore);
4249 region=nexus_info->region;
4250 if ((cache_info->columns != nexus_info->region.width) ||
4251 (extent > MagickMaxBufferExtent))
4258 for (y=0; y < (ssize_t) rows; y++)
4260 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4261 cache_info->server_info,®ion,length,(unsigned char *) q);
4262 if (count != (MagickOffsetType) length)
4264 q+=cache_info->metacontent_extent*nexus_info->region.width;
4267 UnlockSemaphoreInfo(cache_info->file_semaphore);
4273 if (y < (ssize_t) rows)
4275 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4276 cache_info->cache_filename);
4277 return(MagickFalse);
4279 if ((cache_info->debug != MagickFalse) &&
4280 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4281 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4282 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4283 nexus_info->region.width,(double) nexus_info->region.height,(double)
4284 nexus_info->region.x,(double) nexus_info->region.y);
4289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4293 + R e a d P i x e l C a c h e P i x e l s %
4297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4299 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4302 % The format of the ReadPixelCachePixels() method is:
4304 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4305 % NexusInfo *nexus_info,ExceptionInfo *exception)
4307 % A description of each parameter follows:
4309 % o cache_info: the pixel cache.
4311 % o nexus_info: the cache nexus to read the pixels.
4313 % o exception: return any errors or warnings in this structure.
4316 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4317 NexusInfo *nexus_info,ExceptionInfo *exception)
4336 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4338 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4339 nexus_info->region.x;
4340 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4342 extent=length*nexus_info->region.height;
4343 rows=nexus_info->region.height;
4345 q=nexus_info->pixels;
4346 switch (cache_info->type)
4355 Read pixels from memory.
4357 if ((cache_info->columns == nexus_info->region.width) &&
4358 (extent == (MagickSizeType) ((size_t) extent)))
4363 p=cache_info->pixels+offset*cache_info->number_channels;
4364 for (y=0; y < (ssize_t) rows; y++)
4366 (void) memcpy(q,p,(size_t) length);
4367 p+=cache_info->number_channels*cache_info->columns;
4368 q+=cache_info->number_channels*nexus_info->region.width;
4375 Read pixels from disk.
4377 LockSemaphoreInfo(cache_info->file_semaphore);
4378 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4380 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4381 cache_info->cache_filename);
4382 UnlockSemaphoreInfo(cache_info->file_semaphore);
4383 return(MagickFalse);
4385 if ((cache_info->columns == nexus_info->region.width) &&
4386 (extent <= MagickMaxBufferExtent))
4391 for (y=0; y < (ssize_t) rows; y++)
4393 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4394 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4395 if (count != (MagickOffsetType) length)
4397 offset+=cache_info->columns;
4398 q+=cache_info->number_channels*nexus_info->region.width;
4400 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4401 (void) ClosePixelCacheOnDisk(cache_info);
4402 UnlockSemaphoreInfo(cache_info->file_semaphore);
4405 case DistributedCache:
4411 Read pixels from distributed cache.
4413 LockSemaphoreInfo(cache_info->file_semaphore);
4414 region=nexus_info->region;
4415 if ((cache_info->columns != nexus_info->region.width) ||
4416 (extent > MagickMaxBufferExtent))
4423 for (y=0; y < (ssize_t) rows; y++)
4425 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4426 cache_info->server_info,®ion,length,(unsigned char *) q);
4427 if (count != (MagickOffsetType) length)
4429 q+=cache_info->number_channels*nexus_info->region.width;
4432 UnlockSemaphoreInfo(cache_info->file_semaphore);
4438 if (y < (ssize_t) rows)
4440 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4441 cache_info->cache_filename);
4442 return(MagickFalse);
4444 if ((cache_info->debug != MagickFalse) &&
4445 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4446 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4447 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4448 nexus_info->region.width,(double) nexus_info->region.height,(double)
4449 nexus_info->region.x,(double) nexus_info->region.y);
4454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4458 + R e f e r e n c e P i x e l C a c h e %
4462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4464 % ReferencePixelCache() increments the reference count associated with the
4465 % pixel cache returning a pointer to the cache.
4467 % The format of the ReferencePixelCache method is:
4469 % Cache ReferencePixelCache(Cache cache_info)
4471 % A description of each parameter follows:
4473 % o cache_info: the pixel cache.
4476 MagickPrivate Cache ReferencePixelCache(Cache cache)
4481 assert(cache != (Cache *) NULL);
4482 cache_info=(CacheInfo *) cache;
4483 assert(cache_info->signature == MagickSignature);
4484 LockSemaphoreInfo(cache_info->semaphore);
4485 cache_info->reference_count++;
4486 UnlockSemaphoreInfo(cache_info->semaphore);
4491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4495 + S e t P i x e l C a c h e M e t h o d s %
4499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4501 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4503 % The format of the SetPixelCacheMethods() method is:
4505 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4507 % A description of each parameter follows:
4509 % o cache: the pixel cache.
4511 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4514 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4519 GetOneAuthenticPixelFromHandler
4520 get_one_authentic_pixel_from_handler;
4522 GetOneVirtualPixelFromHandler
4523 get_one_virtual_pixel_from_handler;
4526 Set cache pixel methods.
4528 assert(cache != (Cache) NULL);
4529 assert(cache_methods != (CacheMethods *) NULL);
4530 cache_info=(CacheInfo *) cache;
4531 assert(cache_info->signature == MagickSignature);
4532 if (cache_info->debug != MagickFalse)
4533 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4534 cache_info->filename);
4535 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4536 cache_info->methods.get_virtual_pixel_handler=
4537 cache_methods->get_virtual_pixel_handler;
4538 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4539 cache_info->methods.destroy_pixel_handler=
4540 cache_methods->destroy_pixel_handler;
4541 if (cache_methods->get_virtual_metacontent_from_handler !=
4542 (GetVirtualMetacontentFromHandler) NULL)
4543 cache_info->methods.get_virtual_metacontent_from_handler=
4544 cache_methods->get_virtual_metacontent_from_handler;
4545 if (cache_methods->get_authentic_pixels_handler !=
4546 (GetAuthenticPixelsHandler) NULL)
4547 cache_info->methods.get_authentic_pixels_handler=
4548 cache_methods->get_authentic_pixels_handler;
4549 if (cache_methods->queue_authentic_pixels_handler !=
4550 (QueueAuthenticPixelsHandler) NULL)
4551 cache_info->methods.queue_authentic_pixels_handler=
4552 cache_methods->queue_authentic_pixels_handler;
4553 if (cache_methods->sync_authentic_pixels_handler !=
4554 (SyncAuthenticPixelsHandler) NULL)
4555 cache_info->methods.sync_authentic_pixels_handler=
4556 cache_methods->sync_authentic_pixels_handler;
4557 if (cache_methods->get_authentic_pixels_from_handler !=
4558 (GetAuthenticPixelsFromHandler) NULL)
4559 cache_info->methods.get_authentic_pixels_from_handler=
4560 cache_methods->get_authentic_pixels_from_handler;
4561 if (cache_methods->get_authentic_metacontent_from_handler !=
4562 (GetAuthenticMetacontentFromHandler) NULL)
4563 cache_info->methods.get_authentic_metacontent_from_handler=
4564 cache_methods->get_authentic_metacontent_from_handler;
4565 get_one_virtual_pixel_from_handler=
4566 cache_info->methods.get_one_virtual_pixel_from_handler;
4567 if (get_one_virtual_pixel_from_handler !=
4568 (GetOneVirtualPixelFromHandler) NULL)
4569 cache_info->methods.get_one_virtual_pixel_from_handler=
4570 cache_methods->get_one_virtual_pixel_from_handler;
4571 get_one_authentic_pixel_from_handler=
4572 cache_methods->get_one_authentic_pixel_from_handler;
4573 if (get_one_authentic_pixel_from_handler !=
4574 (GetOneAuthenticPixelFromHandler) NULL)
4575 cache_info->methods.get_one_authentic_pixel_from_handler=
4576 cache_methods->get_one_authentic_pixel_from_handler;
4580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4584 + S e t P i x e l C a c h e N e x u s P i x e l s %
4588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4590 % SetPixelCacheNexusPixels() defines the region of the cache for the
4591 % specified cache nexus.
4593 % The format of the SetPixelCacheNexusPixels() method is:
4595 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4596 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4597 % ExceptionInfo *exception)
4599 % A description of each parameter follows:
4601 % o cache_info: the pixel cache.
4603 % o mode: ReadMode, WriteMode, or IOMode.
4605 % o region: A pointer to the RectangleInfo structure that defines the
4606 % region of this particular cache nexus.
4608 % o nexus_info: the cache nexus to set.
4610 % o exception: return any errors or warnings in this structure.
4614 static inline MagickBooleanType AcquireCacheNexusPixels(
4615 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4616 ExceptionInfo *exception)
4618 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4619 return(MagickFalse);
4620 nexus_info->mapped=MagickFalse;
4621 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4622 (size_t) nexus_info->length));
4623 if (nexus_info->cache == (Quantum *) NULL)
4625 nexus_info->mapped=MagickTrue;
4626 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4627 nexus_info->length);
4629 if (nexus_info->cache == (Quantum *) NULL)
4631 (void) ThrowMagickException(exception,GetMagickModule(),
4632 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4633 cache_info->filename);
4634 return(MagickFalse);
4639 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4642 if (mode == ReadMode)
4644 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4647 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4650 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4651 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4652 ExceptionInfo *exception)
4661 assert(cache_info != (const CacheInfo *) NULL);
4662 assert(cache_info->signature == MagickSignature);
4663 if (cache_info->type == UndefinedCache)
4664 return((Quantum *) NULL);
4665 nexus_info->region=(*region);
4666 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4672 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4673 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4674 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4675 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4676 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4677 ((nexus_info->region.width == cache_info->columns) ||
4678 ((nexus_info->region.width % cache_info->columns) == 0)))))
4684 Pixels are accessed directly from memory.
4686 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4687 nexus_info->region.x;
4688 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4690 nexus_info->metacontent=(void *) NULL;
4691 if (cache_info->metacontent_extent != 0)
4692 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4693 offset*cache_info->metacontent_extent;
4694 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4695 return(nexus_info->pixels);
4699 Pixels are stored in a cache region until they are synced to the cache.
4701 number_pixels=(MagickSizeType) nexus_info->region.width*
4702 nexus_info->region.height;
4703 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4704 if (cache_info->metacontent_extent != 0)
4705 length+=number_pixels*cache_info->metacontent_extent;
4706 if (nexus_info->cache == (Quantum *) NULL)
4708 nexus_info->length=length;
4709 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4710 if (status == MagickFalse)
4712 nexus_info->length=0;
4713 return((Quantum *) NULL);
4717 if (nexus_info->length != length)
4719 RelinquishCacheNexusPixels(nexus_info);
4720 nexus_info->length=length;
4721 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4722 if (status == MagickFalse)
4724 nexus_info->length=0;
4725 return((Quantum *) NULL);
4728 nexus_info->pixels=nexus_info->cache;
4729 nexus_info->metacontent=(void *) NULL;
4730 if (cache_info->metacontent_extent != 0)
4731 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4732 cache_info->number_channels);
4733 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4734 return(nexus_info->pixels);
4738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4742 % 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 %
4746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4748 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4749 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4750 % access that is outside the boundaries of the image cache.
4752 % The format of the SetPixelCacheVirtualMethod() method is:
4754 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4755 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4757 % A description of each parameter follows:
4759 % o image: the image.
4761 % o virtual_pixel_method: choose the type of virtual pixel.
4763 % o exception: return any errors or warnings in this structure.
4767 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4768 ExceptionInfo *exception)
4782 assert(image != (Image *) NULL);
4783 assert(image->signature == MagickSignature);
4784 if (image->debug != MagickFalse)
4785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4786 assert(image->cache != (Cache) NULL);
4787 cache_info=(CacheInfo *) image->cache;
4788 assert(cache_info->signature == MagickSignature);
4789 image->alpha_trait=BlendPixelTrait;
4791 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4792 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4793 #pragma omp parallel for schedule(static,4) shared(status) \
4794 magick_threads(image,image,1,1)
4796 for (y=0; y < (ssize_t) image->rows; y++)
4804 if (status == MagickFalse)
4806 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4807 if (q == (Quantum *) NULL)
4812 for (x=0; x < (ssize_t) image->columns; x++)
4814 SetPixelAlpha(image,alpha,q);
4815 q+=GetPixelChannels(image);
4817 status=SyncCacheViewAuthenticPixels(image_view,exception);
4819 image_view=DestroyCacheView(image_view);
4823 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4824 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4832 assert(image != (Image *) NULL);
4833 assert(image->signature == MagickSignature);
4834 if (image->debug != MagickFalse)
4835 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4836 assert(image->cache != (Cache) NULL);
4837 cache_info=(CacheInfo *) image->cache;
4838 assert(cache_info->signature == MagickSignature);
4839 method=cache_info->virtual_pixel_method;
4840 cache_info->virtual_pixel_method=virtual_pixel_method;
4841 if ((image->columns != 0) && (image->rows != 0))
4842 switch (virtual_pixel_method)
4844 case BackgroundVirtualPixelMethod:
4846 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4847 (image->alpha_trait != BlendPixelTrait))
4848 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4849 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4850 (IsGrayColorspace(image->colorspace) != MagickFalse))
4851 (void) TransformImageColorspace(image,RGBColorspace,exception);
4854 case TransparentVirtualPixelMethod:
4856 if (image->alpha_trait != BlendPixelTrait)
4857 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871 + 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 %
4875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4877 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4878 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4879 % is synced, otherwise MagickFalse.
4881 % The format of the SyncAuthenticPixelCacheNexus() method is:
4883 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4884 % NexusInfo *nexus_info,ExceptionInfo *exception)
4886 % A description of each parameter follows:
4888 % o image: the image.
4890 % o nexus_info: the cache nexus to sync.
4892 % o exception: return any errors or warnings in this structure.
4895 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4896 NexusInfo *nexus_info,ExceptionInfo *exception)
4905 Transfer pixels to the cache.
4907 assert(image != (Image *) NULL);
4908 assert(image->signature == MagickSignature);
4909 if (image->cache == (Cache) NULL)
4910 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4911 cache_info=(CacheInfo *) image->cache;
4912 assert(cache_info->signature == MagickSignature);
4913 if (cache_info->type == UndefinedCache)
4914 return(MagickFalse);
4915 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4917 assert(cache_info->signature == MagickSignature);
4918 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4919 if ((cache_info->metacontent_extent != 0) &&
4920 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4921 return(MagickFalse);
4926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4930 + S y n c A u t h e n t i c P i x e l C a c h e %
4934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4936 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4937 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4938 % otherwise MagickFalse.
4940 % The format of the SyncAuthenticPixelsCache() method is:
4942 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4943 % ExceptionInfo *exception)
4945 % A description of each parameter follows:
4947 % o image: the image.
4949 % o exception: return any errors or warnings in this structure.
4952 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4953 ExceptionInfo *exception)
4959 id = GetOpenMPThreadId();
4964 assert(image != (Image *) NULL);
4965 assert(image->signature == MagickSignature);
4966 assert(image->cache != (Cache) NULL);
4967 cache_info=(CacheInfo *) image->cache;
4968 assert(cache_info->signature == MagickSignature);
4969 assert(id < (int) cache_info->number_threads);
4970 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4980 % S y n c A u t h e n t i c P i x e l s %
4984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4986 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4987 % The method returns MagickTrue if the pixel region is flushed, otherwise
4990 % The format of the SyncAuthenticPixels() method is:
4992 % MagickBooleanType SyncAuthenticPixels(Image *image,
4993 % ExceptionInfo *exception)
4995 % A description of each parameter follows:
4997 % o image: the image.
4999 % o exception: return any errors or warnings in this structure.
5002 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5003 ExceptionInfo *exception)
5009 id = GetOpenMPThreadId();
5014 assert(image != (Image *) NULL);
5015 assert(image->signature == MagickSignature);
5016 assert(image->cache != (Cache) NULL);
5017 cache_info=(CacheInfo *) image->cache;
5018 assert(cache_info->signature == MagickSignature);
5019 if (cache_info->methods.sync_authentic_pixels_handler !=
5020 (SyncAuthenticPixelsHandler) NULL)
5022 status=cache_info->methods.sync_authentic_pixels_handler(image,
5026 assert(id < (int) cache_info->number_threads);
5027 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5037 + S y n c I m a g e P i x e l C a c h e %
5041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5043 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5044 % The method returns MagickTrue if the pixel region is flushed, otherwise
5047 % The format of the SyncImagePixelCache() method is:
5049 % MagickBooleanType SyncImagePixelCache(Image *image,
5050 % ExceptionInfo *exception)
5052 % A description of each parameter follows:
5054 % o image: the image.
5056 % o exception: return any errors or warnings in this structure.
5059 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5060 ExceptionInfo *exception)
5065 assert(image != (Image *) NULL);
5066 assert(exception != (ExceptionInfo *) NULL);
5067 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5068 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076 + 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 %
5080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5082 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5083 % of the pixel cache.
5085 % The format of the WritePixelCacheMetacontent() method is:
5087 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5088 % NexusInfo *nexus_info,ExceptionInfo *exception)
5090 % A description of each parameter follows:
5092 % o cache_info: the pixel cache.
5094 % o nexus_info: the cache nexus to write the meta-content.
5096 % o exception: return any errors or warnings in this structure.
5099 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5100 NexusInfo *nexus_info,ExceptionInfo *exception)
5110 register const unsigned char
5119 if (cache_info->metacontent_extent == 0)
5120 return(MagickFalse);
5121 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5123 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5124 nexus_info->region.x;
5125 length=(MagickSizeType) nexus_info->region.width*
5126 cache_info->metacontent_extent;
5127 extent=(MagickSizeType) length*nexus_info->region.height;
5128 rows=nexus_info->region.height;
5130 p=(unsigned char *) nexus_info->metacontent;
5131 switch (cache_info->type)
5136 register unsigned char
5140 Write associated pixels to memory.
5142 if ((cache_info->columns == nexus_info->region.width) &&
5143 (extent == (MagickSizeType) ((size_t) extent)))
5148 q=(unsigned char *) cache_info->metacontent+offset*
5149 cache_info->metacontent_extent;
5150 for (y=0; y < (ssize_t) rows; y++)
5152 (void) memcpy(q,p,(size_t) length);
5153 p+=nexus_info->region.width*cache_info->metacontent_extent;
5154 q+=cache_info->columns*cache_info->metacontent_extent;
5161 Write associated pixels to disk.
5163 LockSemaphoreInfo(cache_info->file_semaphore);
5164 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5166 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5167 cache_info->cache_filename);
5168 UnlockSemaphoreInfo(cache_info->file_semaphore);
5169 return(MagickFalse);
5171 if ((cache_info->columns == nexus_info->region.width) &&
5172 (extent <= MagickMaxBufferExtent))
5177 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5178 for (y=0; y < (ssize_t) rows; y++)
5180 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5181 cache_info->number_channels*sizeof(Quantum)+offset*
5182 cache_info->metacontent_extent,length,(const unsigned char *) p);
5183 if (count != (MagickOffsetType) length)
5185 p+=cache_info->metacontent_extent*nexus_info->region.width;
5186 offset+=cache_info->columns;
5188 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5189 (void) ClosePixelCacheOnDisk(cache_info);
5190 UnlockSemaphoreInfo(cache_info->file_semaphore);
5193 case DistributedCache:
5199 Write metacontent to distributed cache.
5201 LockSemaphoreInfo(cache_info->file_semaphore);
5202 region=nexus_info->region;
5203 if ((cache_info->columns != nexus_info->region.width) ||
5204 (extent > MagickMaxBufferExtent))
5211 for (y=0; y < (ssize_t) rows; y++)
5213 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5214 cache_info->server_info,®ion,length,(const unsigned char *) p);
5215 if (count != (MagickOffsetType) length)
5217 p+=cache_info->metacontent_extent*nexus_info->region.width;
5220 UnlockSemaphoreInfo(cache_info->file_semaphore);
5226 if (y < (ssize_t) rows)
5228 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5229 cache_info->cache_filename);
5230 return(MagickFalse);
5232 if ((cache_info->debug != MagickFalse) &&
5233 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5234 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5235 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5236 nexus_info->region.width,(double) nexus_info->region.height,(double)
5237 nexus_info->region.x,(double) nexus_info->region.y);
5242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5246 + W r i t e C a c h e P i x e l s %
5250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5252 % WritePixelCachePixels() writes image pixels to the specified region of the
5255 % The format of the WritePixelCachePixels() method is:
5257 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5258 % NexusInfo *nexus_info,ExceptionInfo *exception)
5260 % A description of each parameter follows:
5262 % o cache_info: the pixel cache.
5264 % o nexus_info: the cache nexus to write the pixels.
5266 % o exception: return any errors or warnings in this structure.
5269 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5270 NexusInfo *nexus_info,ExceptionInfo *exception)
5280 register const Quantum
5289 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5291 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5292 nexus_info->region.x;
5293 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5295 extent=length*nexus_info->region.height;
5296 rows=nexus_info->region.height;
5298 p=nexus_info->pixels;
5299 switch (cache_info->type)
5308 Write pixels to memory.
5310 if ((cache_info->columns == nexus_info->region.width) &&
5311 (extent == (MagickSizeType) ((size_t) extent)))
5316 q=cache_info->pixels+offset*cache_info->number_channels;
5317 for (y=0; y < (ssize_t) rows; y++)
5319 (void) memcpy(q,p,(size_t) length);
5320 p+=cache_info->number_channels*nexus_info->region.width;
5321 q+=cache_info->columns*cache_info->number_channels;
5328 Write pixels to disk.
5330 LockSemaphoreInfo(cache_info->file_semaphore);
5331 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5333 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5334 cache_info->cache_filename);
5335 UnlockSemaphoreInfo(cache_info->file_semaphore);
5336 return(MagickFalse);
5338 if ((cache_info->columns == nexus_info->region.width) &&
5339 (extent <= MagickMaxBufferExtent))
5344 for (y=0; y < (ssize_t) rows; y++)
5346 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5347 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5349 if (count != (MagickOffsetType) length)
5351 p+=cache_info->number_channels*nexus_info->region.width;
5352 offset+=cache_info->columns;
5354 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5355 (void) ClosePixelCacheOnDisk(cache_info);
5356 UnlockSemaphoreInfo(cache_info->file_semaphore);
5359 case DistributedCache:
5365 Write pixels to distributed cache.
5367 LockSemaphoreInfo(cache_info->file_semaphore);
5368 region=nexus_info->region;
5369 if ((cache_info->columns != nexus_info->region.width) ||
5370 (extent > MagickMaxBufferExtent))
5377 for (y=0; y < (ssize_t) rows; y++)
5379 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5380 cache_info->server_info,®ion,length,(const unsigned char *) p);
5381 if (count != (MagickOffsetType) length)
5383 p+=cache_info->number_channels*nexus_info->region.width;
5386 UnlockSemaphoreInfo(cache_info->file_semaphore);
5392 if (y < (ssize_t) rows)
5394 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5395 cache_info->cache_filename);
5396 return(MagickFalse);
5398 if ((cache_info->debug != MagickFalse) &&
5399 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5400 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5401 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5402 nexus_info->region.width,(double) nexus_info->region.height,(double)
5403 nexus_info->region.x,(double) nexus_info->region.y);