2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
120 Forward declarations.
122 #if defined(__cplusplus) || defined(c_plusplus)
127 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
131 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
132 const ssize_t,const size_t,const size_t,ExceptionInfo *),
133 *GetVirtualPixelsCache(const Image *);
136 *GetVirtualMetacontentFromCache(const Image *);
138 static MagickBooleanType
139 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
141 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
142 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
143 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
144 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
146 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
147 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
148 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
151 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
152 const size_t,ExceptionInfo *),
153 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
154 const size_t,ExceptionInfo *),
155 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
156 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
158 #if defined(__cplusplus) || defined(c_plusplus)
165 static volatile MagickBooleanType
166 instantiate_cache = MagickFalse;
169 *cache_semaphore = (SemaphoreInfo *) NULL;
172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 + A c q u i r e P i x e l C a c h e %
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 % AcquirePixelCache() acquires a pixel cache.
184 % The format of the AcquirePixelCache() method is:
186 % Cache AcquirePixelCache(const size_t number_threads)
188 % A description of each parameter follows:
190 % o number_threads: the number of nexus threads.
193 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
201 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
202 if (cache_info == (CacheInfo *) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
205 cache_info->type=UndefinedCache;
206 cache_info->mode=IOMode;
207 cache_info->colorspace=sRGBColorspace;
208 cache_info->file=(-1);
209 cache_info->id=GetMagickThreadId();
210 cache_info->number_threads=number_threads;
211 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
212 cache_info->number_threads=GetOpenMPMaximumThreads();
213 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
214 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
215 if (cache_info->number_threads == 0)
216 cache_info->number_threads=1;
217 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
218 if (cache_info->nexus_info == (NexusInfo **) NULL)
219 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
220 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
221 if (synchronize != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(synchronize);
224 synchronize=DestroyString(synchronize);
226 cache_info->semaphore=AllocateSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AllocateSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickSignature;
231 return((Cache ) cache_info);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % A c q u i r e P i x e l C a c h e N e x u s %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
247 % The format of the AcquirePixelCacheNexus method is:
249 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 % A description of each parameter follows:
253 % o number_threads: the number of nexus threads.
256 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
264 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
265 number_threads,sizeof(*nexus_info)));
266 if (nexus_info == (NexusInfo **) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
269 sizeof(**nexus_info));
270 if (nexus_info[0] == (NexusInfo *) NULL)
271 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
272 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
273 for (i=0; i < (ssize_t) number_threads; i++)
275 nexus_info[i]=(&nexus_info[0][i]);
276 nexus_info[i]->signature=MagickSignature;
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 + A c q u i r e P i x e l C a c h e P i x e l s %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % AcquirePixelCachePixels() returns the pixels associated with the specified
295 % The format of the AcquirePixelCachePixels() method is:
297 % const void *AcquirePixelCachePixels(const Image *image,
298 % MagickSizeType *length,ExceptionInfo *exception)
300 % A description of each parameter follows:
302 % o image: the image.
304 % o length: the pixel cache length.
306 % o exception: return any errors or warnings in this structure.
309 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
310 MagickSizeType *length,ExceptionInfo *exception)
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickSignature);
323 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
324 return((const void *) NULL);
325 *length=cache_info->length;
326 return((const void *) cache_info->pixels);
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 + C a c h e C o m p o n e n t G e n e s i s %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % CacheComponentGenesis() instantiates the cache component.
342 % The format of the CacheComponentGenesis method is:
344 % MagickBooleanType CacheComponentGenesis(void)
347 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
349 AcquireSemaphoreInfo(&cache_semaphore);
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 + C a c h e C o m p o n e n t T e r m i n u s %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 % CacheComponentTerminus() destroys the cache component.
366 % The format of the CacheComponentTerminus() method is:
368 % CacheComponentTerminus(void)
371 MagickPrivate void CacheComponentTerminus(void)
373 if (cache_semaphore == (SemaphoreInfo *) NULL)
374 AcquireSemaphoreInfo(&cache_semaphore);
375 LockSemaphoreInfo(cache_semaphore);
376 instantiate_cache=MagickFalse;
377 UnlockSemaphoreInfo(cache_semaphore);
378 DestroySemaphoreInfo(&cache_semaphore);
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 + C l o n e P i x e l C a c h e %
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 % ClonePixelCache() clones a pixel cache.
394 % The format of the ClonePixelCache() method is:
396 % Cache ClonePixelCache(const Cache cache)
398 % A description of each parameter follows:
400 % o cache: the pixel cache.
403 MagickPrivate Cache ClonePixelCache(const Cache cache)
411 assert(cache != NULL);
412 cache_info=(const CacheInfo *) cache;
413 assert(cache_info->signature == MagickSignature);
414 if (cache_info->debug != MagickFalse)
415 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
416 cache_info->filename);
417 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
418 if (clone_info == (Cache) NULL)
419 return((Cache) NULL);
420 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
421 return((Cache ) clone_info);
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 + C l o n e P i x e l C a c h e M e t h o d s %
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
438 % The format of the ClonePixelCacheMethods() method is:
440 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
442 % A description of each parameter follows:
444 % o clone: Specifies a pointer to a Cache structure.
446 % o cache: the pixel cache.
449 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
455 assert(clone != (Cache) NULL);
456 source_info=(CacheInfo *) clone;
457 assert(source_info->signature == MagickSignature);
458 if (source_info->debug != MagickFalse)
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
460 source_info->filename);
461 assert(cache != (Cache) NULL);
462 cache_info=(CacheInfo *) cache;
463 assert(cache_info->signature == MagickSignature);
464 source_info->methods=cache_info->methods;
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 + C l o n e P i x e l C a c h e R e p o s i t o r y %
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
477 % ClonePixelCacheRepository() clones the source pixel cache to the destination
480 % The format of the ClonePixelCacheRepository() method is:
482 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
483 % CacheInfo *source_info,ExceptionInfo *exception)
485 % A description of each parameter follows:
487 % o cache_info: the pixel cache.
489 % o source_info: the source pixel cache.
491 % o exception: return any errors or warnings in this structure.
495 static inline MagickSizeType MagickMin(const MagickSizeType x,
496 const MagickSizeType y)
503 static MagickBooleanType ClonePixelCacheRepository(CacheInfo *clone_info,
504 CacheInfo *cache_info,ExceptionInfo *exception)
506 #define MaxCacheThreads 2
507 #define cache_threads(source,destination,chunk) \
508 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
509 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
510 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
526 assert(cache_info != (CacheInfo *) NULL);
527 assert(clone_info != (CacheInfo *) NULL);
528 assert(exception != (ExceptionInfo *) NULL);
529 if (cache_info->type == PingCache)
531 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
532 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
533 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
534 (cache_info->columns == clone_info->columns) &&
535 (cache_info->rows == clone_info->rows) &&
536 (cache_info->number_channels == clone_info->number_channels) &&
537 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
538 (cache_info->metacontent_extent == clone_info->metacontent_extent))
541 Identical pixel cache morphology.
543 (void) memcpy(clone_info->pixels,cache_info->pixels,cache_info->columns*
544 cache_info->number_channels*cache_info->rows*
545 sizeof(*cache_info->pixels));
546 if (cache_info->metacontent_extent != 0)
547 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
548 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
549 sizeof(cache_info->metacontent));
553 Mismatched pixel cache morphology.
555 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
556 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
557 if ((cache_nexus == (NexusInfo **) NULL) ||
558 (clone_nexus == (NexusInfo **) NULL))
559 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
560 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
561 optimize=(cache_info->number_channels == clone_info->number_channels) &&
562 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
563 MagickTrue : MagickFalse;
564 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
565 clone_info->columns*clone_info->number_channels);
567 #if defined(MAGICKCORE_OPENMP_SUPPORT)
568 #pragma omp parallel for schedule(static,4) shared(status) \
569 cache_threads(cache_info,clone_info,cache_info->rows)
571 for (y=0; y < (ssize_t) cache_info->rows; y++)
574 id = GetOpenMPThreadId();
585 if (status == MagickFalse)
587 if (y >= (ssize_t) clone_info->rows)
589 region.width=cache_info->columns;
593 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
595 if (pixels == (Quantum *) NULL)
597 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
598 if (status == MagickFalse)
600 region.width=clone_info->columns;
601 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
602 clone_nexus[id],exception);
603 if (pixels == (Quantum *) NULL)
605 if (optimize != MagickFalse)
606 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
610 register const Quantum
617 Mismatched pixel channel map.
619 p=cache_nexus[id]->pixels;
620 q=clone_nexus[id]->pixels;
621 for (x=0; x < (ssize_t) cache_info->columns; x++)
626 if (x == (ssize_t) clone_info->columns)
628 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
636 channel=clone_info->channel_map[i].channel;
637 traits=cache_info->channel_map[channel].traits;
638 if (traits != UndefinedPixelTrait)
639 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
643 p+=cache_info->number_channels;
646 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
648 if ((cache_info->metacontent_extent != 0) &&
649 (clone_info->metacontent_extent != 0))
654 length=(size_t) MagickMin(cache_info->metacontent_extent,
655 clone_info->metacontent_extent);
656 #if defined(MAGICKCORE_OPENMP_SUPPORT)
657 #pragma omp parallel for schedule(static,4) shared(status) \
658 cache_threads(cache_info,clone_info,cache_info->rows)
660 for (y=0; y < (ssize_t) cache_info->rows; y++)
663 id = GetOpenMPThreadId();
671 if (status == MagickFalse)
673 if (y >= (ssize_t) clone_info->rows)
675 region.width=cache_info->columns;
679 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
680 cache_nexus[id],exception);
681 if (pixels == (Quantum *) NULL)
683 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
684 if (status == MagickFalse)
686 region.width=clone_info->columns;
687 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
688 clone_nexus[id],exception);
689 if (pixels == (Quantum *) NULL)
691 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
692 length*sizeof(cache_nexus[id]->metacontent));
693 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
696 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
697 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
698 if (cache_info->debug != MagickFalse)
701 message[MaxTextExtent];
703 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
704 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
705 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 + D e s t r o y I m a g e P i x e l C a c h e %
720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
724 % The format of the DestroyImagePixelCache() method is:
726 % void DestroyImagePixelCache(Image *image)
728 % A description of each parameter follows:
730 % o image: the image.
733 static void DestroyImagePixelCache(Image *image)
735 assert(image != (Image *) NULL);
736 assert(image->signature == MagickSignature);
737 if (image->debug != MagickFalse)
738 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
739 if (image->cache == (void *) NULL)
741 image->cache=DestroyPixelCache(image->cache);
745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749 + D e s t r o y I m a g e P i x e l s %
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755 % DestroyImagePixels() deallocates memory associated with the pixel cache.
757 % The format of the DestroyImagePixels() method is:
759 % void DestroyImagePixels(Image *image)
761 % A description of each parameter follows:
763 % o image: the image.
766 MagickExport void DestroyImagePixels(Image *image)
771 assert(image != (const Image *) NULL);
772 assert(image->signature == MagickSignature);
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
775 assert(image->cache != (Cache) NULL);
776 cache_info=(CacheInfo *) image->cache;
777 assert(cache_info->signature == MagickSignature);
778 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
780 cache_info->methods.destroy_pixel_handler(image);
783 image->cache=DestroyPixelCache(image->cache);
787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
791 + D e s t r o y P i x e l C a c h e %
795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797 % DestroyPixelCache() deallocates memory associated with the pixel cache.
799 % The format of the DestroyPixelCache() method is:
801 % Cache DestroyPixelCache(Cache cache)
803 % A description of each parameter follows:
805 % o cache: the pixel cache.
809 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
815 if (cache_info->file != -1)
817 status=close(cache_info->file);
818 cache_info->file=(-1);
819 RelinquishMagickResource(FileResource,1);
821 return(status == -1 ? MagickFalse : MagickTrue);
824 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
826 switch (cache_info->type)
830 if (cache_info->mapped == MagickFalse)
831 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
834 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
835 (size_t) cache_info->length);
836 RelinquishMagickResource(MemoryResource,cache_info->length);
841 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
843 if (cache_info->mode != ReadMode)
844 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
845 *cache_info->cache_filename='\0';
846 RelinquishMagickResource(MapResource,cache_info->length);
850 if (cache_info->file != -1)
851 (void) ClosePixelCacheOnDisk(cache_info);
852 if (cache_info->mode != ReadMode)
853 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
854 *cache_info->cache_filename='\0';
855 RelinquishMagickResource(DiskResource,cache_info->length);
858 case DistributedCache:
860 *cache_info->cache_filename='\0';
861 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
862 cache_info->server_info);
868 cache_info->type=UndefinedCache;
869 cache_info->mapped=MagickFalse;
870 cache_info->metacontent=(void *) NULL;
873 MagickPrivate Cache DestroyPixelCache(Cache cache)
878 assert(cache != (Cache) NULL);
879 cache_info=(CacheInfo *) cache;
880 assert(cache_info->signature == MagickSignature);
881 if (cache_info->debug != MagickFalse)
882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
883 cache_info->filename);
884 LockSemaphoreInfo(cache_info->semaphore);
885 cache_info->reference_count--;
886 if (cache_info->reference_count != 0)
888 UnlockSemaphoreInfo(cache_info->semaphore);
889 return((Cache) NULL);
891 UnlockSemaphoreInfo(cache_info->semaphore);
892 if (cache_info->debug != MagickFalse)
895 message[MaxTextExtent];
897 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
898 cache_info->filename);
899 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
901 RelinquishPixelCachePixels(cache_info);
902 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
903 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
904 cache_info->server_info);
905 if (cache_info->nexus_info != (NexusInfo **) NULL)
906 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
907 cache_info->number_threads);
908 if (cache_info->random_info != (RandomInfo *) NULL)
909 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
910 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
911 DestroySemaphoreInfo(&cache_info->file_semaphore);
912 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
913 DestroySemaphoreInfo(&cache_info->semaphore);
914 cache_info->signature=(~MagickSignature);
915 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
925 + D e s t r o y P i x e l C a c h e N e x u s %
929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
933 % The format of the DestroyPixelCacheNexus() method is:
935 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
936 % const size_t number_threads)
938 % A description of each parameter follows:
940 % o nexus_info: the nexus to destroy.
942 % o number_threads: the number of nexus threads.
946 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
948 if (nexus_info->mapped == MagickFalse)
949 (void) RelinquishAlignedMemory(nexus_info->cache);
951 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
952 nexus_info->cache=(Quantum *) NULL;
953 nexus_info->pixels=(Quantum *) NULL;
954 nexus_info->metacontent=(void *) NULL;
955 nexus_info->length=0;
956 nexus_info->mapped=MagickFalse;
959 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
960 const size_t number_threads)
965 assert(nexus_info != (NexusInfo **) NULL);
966 for (i=0; i < (ssize_t) number_threads; i++)
968 if (nexus_info[i]->cache != (Quantum *) NULL)
969 RelinquishCacheNexusPixels(nexus_info[i]);
970 nexus_info[i]->signature=(~MagickSignature);
972 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
973 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 % G e t A u t h e n t i c M e t a c o n t e n t %
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
989 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
990 % returned if the associated pixels are not available.
992 % The format of the GetAuthenticMetacontent() method is:
994 % void *GetAuthenticMetacontent(const Image *image)
996 % A description of each parameter follows:
998 % o image: the image.
1001 MagickExport void *GetAuthenticMetacontent(const Image *image)
1007 id = GetOpenMPThreadId();
1012 assert(image != (const Image *) NULL);
1013 assert(image->signature == MagickSignature);
1014 assert(image->cache != (Cache) NULL);
1015 cache_info=(CacheInfo *) image->cache;
1016 assert(cache_info->signature == MagickSignature);
1017 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1018 (GetAuthenticMetacontentFromHandler) NULL)
1020 metacontent=cache_info->methods.
1021 get_authentic_metacontent_from_handler(image);
1022 return(metacontent);
1024 assert(id < (int) cache_info->number_threads);
1025 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1026 cache_info->nexus_info[id]);
1027 return(metacontent);
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 + G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
1039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1042 % with the last call to QueueAuthenticPixelsCache() or
1043 % GetAuthenticPixelsCache().
1045 % The format of the GetAuthenticMetacontentFromCache() method is:
1047 % void *GetAuthenticMetacontentFromCache(const Image *image)
1049 % A description of each parameter follows:
1051 % o image: the image.
1054 static void *GetAuthenticMetacontentFromCache(const Image *image)
1060 id = GetOpenMPThreadId();
1065 assert(image != (const Image *) NULL);
1066 assert(image->signature == MagickSignature);
1067 assert(image->cache != (Cache) NULL);
1068 cache_info=(CacheInfo *) image->cache;
1069 assert(cache_info->signature == MagickSignature);
1070 assert(id < (int) cache_info->number_threads);
1071 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1072 cache_info->nexus_info[id]);
1073 return(metacontent);
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 + G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1088 % disk pixel cache as defined by the geometry parameters. A pointer to the
1089 % pixels is returned if the pixels are transferred, otherwise a NULL is
1092 % The format of the GetAuthenticPixelCacheNexus() method is:
1094 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1095 % const ssize_t y,const size_t columns,const size_t rows,
1096 % NexusInfo *nexus_info,ExceptionInfo *exception)
1098 % A description of each parameter follows:
1100 % o image: the image.
1102 % o x,y,columns,rows: These values define the perimeter of a region of
1105 % o nexus_info: the cache nexus to return.
1107 % o exception: return any errors or warnings in this structure.
1111 static inline MagickBooleanType IsPixelAuthentic(
1112 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1120 if (cache_info->type == PingCache)
1122 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1123 nexus_info->region.x;
1124 status=nexus_info->pixels == (cache_info->pixels+offset*
1125 cache_info->number_channels) ? MagickTrue : MagickFalse;
1129 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1130 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1131 ExceptionInfo *exception)
1140 Transfer pixels from the cache.
1142 assert(image != (Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1145 nexus_info,exception);
1146 if (pixels == (Quantum *) NULL)
1147 return((Quantum *) NULL);
1148 cache_info=(CacheInfo *) image->cache;
1149 assert(cache_info->signature == MagickSignature);
1150 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1152 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1153 return((Quantum *) NULL);
1154 if (cache_info->metacontent_extent != 0)
1155 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1156 return((Quantum *) NULL);
1161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 + G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1171 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1172 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1174 % The format of the GetAuthenticPixelsFromCache() method is:
1176 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1178 % A description of each parameter follows:
1180 % o image: the image.
1183 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1189 id = GetOpenMPThreadId();
1191 assert(image != (const Image *) NULL);
1192 assert(image->signature == MagickSignature);
1193 assert(image->cache != (Cache) NULL);
1194 cache_info=(CacheInfo *) image->cache;
1195 assert(cache_info->signature == MagickSignature);
1196 assert(id < (int) cache_info->number_threads);
1197 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % G e t A u t h e n t i c P i x e l Q u e u e %
1209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 % GetAuthenticPixelQueue() returns the authentic pixels associated
1212 % corresponding with the last call to QueueAuthenticPixels() or
1213 % GetAuthenticPixels().
1215 % The format of the GetAuthenticPixelQueue() method is:
1217 % Quantum *GetAuthenticPixelQueue(const Image image)
1219 % A description of each parameter follows:
1221 % o image: the image.
1224 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1230 id = GetOpenMPThreadId();
1232 assert(image != (const Image *) NULL);
1233 assert(image->signature == MagickSignature);
1234 assert(image->cache != (Cache) NULL);
1235 cache_info=(CacheInfo *) image->cache;
1236 assert(cache_info->signature == MagickSignature);
1237 if (cache_info->methods.get_authentic_pixels_from_handler !=
1238 (GetAuthenticPixelsFromHandler) NULL)
1239 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1240 assert(id < (int) cache_info->number_threads);
1241 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249 % G e t A u t h e n t i c P i x e l s %
1252 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1254 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1255 % region is successfully accessed, a pointer to a Quantum array
1256 % representing the region is returned, otherwise NULL is returned.
1258 % The returned pointer may point to a temporary working copy of the pixels
1259 % or it may point to the original pixels in memory. Performance is maximized
1260 % if the selected region is part of one row, or one or more full rows, since
1261 % then there is opportunity to access the pixels in-place (without a copy)
1262 % if the image is in memory, or in a memory-mapped file. The returned pointer
1263 % must *never* be deallocated by the user.
1265 % Pixels accessed via the returned pointer represent a simple array of type
1266 % Quantum. If the image has corresponding metacontent,call
1267 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1268 % meta-content corresponding to the region. Once the Quantum array has
1269 % been updated, the changes must be saved back to the underlying image using
1270 % SyncAuthenticPixels() or they may be lost.
1272 % The format of the GetAuthenticPixels() method is:
1274 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1275 % const ssize_t y,const size_t columns,const size_t rows,
1276 % ExceptionInfo *exception)
1278 % A description of each parameter follows:
1280 % o image: the image.
1282 % o x,y,columns,rows: These values define the perimeter of a region of
1285 % o exception: return any errors or warnings in this structure.
1288 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1289 const ssize_t y,const size_t columns,const size_t rows,
1290 ExceptionInfo *exception)
1296 id = GetOpenMPThreadId();
1301 assert(image != (Image *) NULL);
1302 assert(image->signature == MagickSignature);
1303 assert(image->cache != (Cache) NULL);
1304 cache_info=(CacheInfo *) image->cache;
1305 assert(cache_info->signature == MagickSignature);
1306 if (cache_info->methods.get_authentic_pixels_handler !=
1307 (GetAuthenticPixelsHandler) NULL)
1309 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1313 assert(id < (int) cache_info->number_threads);
1314 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1315 cache_info->nexus_info[id],exception);
1320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324 + G e t A u t h e n t i c P i x e l s C a c h e %
1328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1331 % as defined by the geometry parameters. A pointer to the pixels is returned
1332 % if the pixels are transferred, otherwise a NULL is returned.
1334 % The format of the GetAuthenticPixelsCache() method is:
1336 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1337 % const ssize_t y,const size_t columns,const size_t rows,
1338 % ExceptionInfo *exception)
1340 % A description of each parameter follows:
1342 % o image: the image.
1344 % o x,y,columns,rows: These values define the perimeter of a region of
1347 % o exception: return any errors or warnings in this structure.
1350 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1351 const ssize_t y,const size_t columns,const size_t rows,
1352 ExceptionInfo *exception)
1358 id = GetOpenMPThreadId();
1363 assert(image != (const Image *) NULL);
1364 assert(image->signature == MagickSignature);
1365 assert(image->cache != (Cache) NULL);
1366 cache_info=(CacheInfo *) image->cache;
1367 if (cache_info == (Cache) NULL)
1368 return((Quantum *) NULL);
1369 assert(cache_info->signature == MagickSignature);
1370 assert(id < (int) cache_info->number_threads);
1371 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1372 cache_info->nexus_info[id],exception);
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 + G e t I m a g e E x t e n t %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % GetImageExtent() returns the extent of the pixels associated corresponding
1388 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1390 % The format of the GetImageExtent() method is:
1392 % MagickSizeType GetImageExtent(const Image *image)
1394 % A description of each parameter follows:
1396 % o image: the image.
1399 MagickExport MagickSizeType GetImageExtent(const Image *image)
1405 id = GetOpenMPThreadId();
1407 assert(image != (Image *) NULL);
1408 assert(image->signature == MagickSignature);
1409 if (image->debug != MagickFalse)
1410 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1411 assert(image->cache != (Cache) NULL);
1412 cache_info=(CacheInfo *) image->cache;
1413 assert(cache_info->signature == MagickSignature);
1414 assert(id < (int) cache_info->number_threads);
1415 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 + G e t I m a g e P i x e l C a c h e %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 % GetImagePixelCache() ensures that there is only a single reference to the
1430 % pixel cache to be modified, updating the provided cache pointer to point to
1431 % a clone of the original pixel cache if necessary.
1433 % The format of the GetImagePixelCache method is:
1435 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1436 % ExceptionInfo *exception)
1438 % A description of each parameter follows:
1440 % o image: the image.
1442 % o clone: any value other than MagickFalse clones the cache pixels.
1444 % o exception: return any errors or warnings in this structure.
1448 static inline MagickBooleanType ValidatePixelCacheMorphology(
1449 const Image *restrict image)
1452 *restrict cache_info;
1454 const PixelChannelMap
1459 Does the image match the pixel cache morphology?
1461 cache_info=(CacheInfo *) image->cache;
1462 p=image->channel_map;
1463 q=cache_info->channel_map;
1464 if ((image->storage_class != cache_info->storage_class) ||
1465 (image->colorspace != cache_info->colorspace) ||
1466 (image->alpha_trait != cache_info->alpha_trait) ||
1467 (image->mask != cache_info->mask) ||
1468 (image->columns != cache_info->columns) ||
1469 (image->rows != cache_info->rows) ||
1470 (image->number_channels != cache_info->number_channels) ||
1471 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1472 (image->metacontent_extent != cache_info->metacontent_extent) ||
1473 (cache_info->nexus_info == (NexusInfo **) NULL))
1474 return(MagickFalse);
1478 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1479 ExceptionInfo *exception)
1488 static MagickSizeType
1494 cache_timestamp = 0;
1497 LockSemaphoreInfo(image->semaphore);
1498 if (cpu_throttle == 0)
1499 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1500 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1501 MagickDelay(cpu_throttle);
1502 if (time_limit == 0)
1505 Set the expire time in seconds.
1507 time_limit=GetMagickResourceLimit(TimeResource);
1508 cache_timestamp=time((time_t *) NULL);
1510 if ((time_limit != MagickResourceInfinity) &&
1511 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1512 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1513 assert(image->cache != (Cache) NULL);
1514 cache_info=(CacheInfo *) image->cache;
1515 destroy=MagickFalse;
1516 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1518 LockSemaphoreInfo(cache_info->semaphore);
1519 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1530 clone_image=(*image);
1531 clone_image.semaphore=AllocateSemaphoreInfo();
1532 clone_image.reference_count=1;
1533 clone_image.cache=ClonePixelCache(cache_info);
1534 clone_info=(CacheInfo *) clone_image.cache;
1535 status=OpenPixelCache(&clone_image,IOMode,exception);
1536 if (status != MagickFalse)
1538 if (clone != MagickFalse)
1539 status=ClonePixelCacheRepository(clone_info,cache_info,
1541 if (status != MagickFalse)
1543 if (cache_info->reference_count == 1)
1544 cache_info->nexus_info=(NexusInfo **) NULL;
1546 image->cache=clone_image.cache;
1549 DestroySemaphoreInfo(&clone_image.semaphore);
1551 UnlockSemaphoreInfo(cache_info->semaphore);
1553 if (destroy != MagickFalse)
1554 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1555 if (status != MagickFalse)
1558 Ensure the image matches the pixel cache morphology.
1560 image->taint=MagickTrue;
1561 image->type=UndefinedType;
1562 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1564 status=OpenPixelCache(image,IOMode,exception);
1565 cache_info=(CacheInfo *) image->cache;
1566 if (cache_info->type == DiskCache)
1567 (void) ClosePixelCacheOnDisk(cache_info);
1570 UnlockSemaphoreInfo(image->semaphore);
1571 if (status == MagickFalse)
1572 return((Cache) NULL);
1573 return(image->cache);
1577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581 + G e t I m a g e P i x e l C a c h e T y p e %
1585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1588 % DiskCache, MemoryCache, MapCache, or PingCache.
1590 % The format of the GetImagePixelCacheType() method is:
1592 % CacheType GetImagePixelCacheType(const Image *image)
1594 % A description of each parameter follows:
1596 % o image: the image.
1599 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1604 assert(image != (Image *) NULL);
1605 assert(image->signature == MagickSignature);
1606 assert(image->cache != (Cache) NULL);
1607 cache_info=(CacheInfo *) image->cache;
1608 assert(cache_info->signature == MagickSignature);
1609 return(cache_info->type);
1613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 % G e t O n e A u t h e n t i c P i x e l %
1621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1624 % location. The image background color is returned if an error occurs.
1626 % The format of the GetOneAuthenticPixel() method is:
1628 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1629 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1631 % A description of each parameter follows:
1633 % o image: the image.
1635 % o x,y: These values define the location of the pixel to return.
1637 % o pixel: return a pixel at the specified (x,y) location.
1639 % o exception: return any errors or warnings in this structure.
1642 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1643 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1654 assert(image != (Image *) NULL);
1655 assert(image->signature == MagickSignature);
1656 assert(image->cache != (Cache) NULL);
1657 cache_info=(CacheInfo *) image->cache;
1658 assert(cache_info->signature == MagickSignature);
1659 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1660 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1661 (GetOneAuthenticPixelFromHandler) NULL)
1662 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1664 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1665 if (q == (Quantum *) NULL)
1667 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1668 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1669 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1670 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1671 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1672 return(MagickFalse);
1674 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1676 PixelChannel channel=GetPixelChannelChannel(image,i);
1677 pixel[channel]=q[i];
1683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1687 + 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 %
1691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1694 % location. The image background color is returned if an error occurs.
1696 % The format of the GetOneAuthenticPixelFromCache() method is:
1698 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1699 % const ssize_t x,const ssize_t y,Quantum *pixel,
1700 % ExceptionInfo *exception)
1702 % A description of each parameter follows:
1704 % o image: the image.
1706 % o x,y: These values define the location of the pixel to return.
1708 % o pixel: return a pixel at the specified (x,y) location.
1710 % o exception: return any errors or warnings in this structure.
1713 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1714 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1720 id = GetOpenMPThreadId();
1728 assert(image != (const Image *) NULL);
1729 assert(image->signature == MagickSignature);
1730 assert(image->cache != (Cache) NULL);
1731 cache_info=(CacheInfo *) image->cache;
1732 assert(cache_info->signature == MagickSignature);
1733 assert(id < (int) cache_info->number_threads);
1734 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1735 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1737 if (q == (Quantum *) NULL)
1739 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1740 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1741 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1742 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1743 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1744 return(MagickFalse);
1746 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1748 PixelChannel channel=GetPixelChannelChannel(image,i);
1749 pixel[channel]=q[i];
1755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759 % G e t O n e V i r t u a l P i x e l %
1763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1766 % (x,y) location. The image background color is returned if an error occurs.
1767 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1769 % The format of the GetOneVirtualPixel() method is:
1771 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1772 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1774 % A description of each parameter follows:
1776 % o image: the image.
1778 % o x,y: These values define the location of the pixel to return.
1780 % o pixel: return a pixel at the specified (x,y) location.
1782 % o exception: return any errors or warnings in this structure.
1785 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1786 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1792 id = GetOpenMPThreadId();
1800 assert(image != (const Image *) NULL);
1801 assert(image->signature == MagickSignature);
1802 assert(image->cache != (Cache) NULL);
1803 cache_info=(CacheInfo *) image->cache;
1804 assert(cache_info->signature == MagickSignature);
1805 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1806 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1807 (GetOneVirtualPixelFromHandler) NULL)
1808 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1809 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1810 assert(id < (int) cache_info->number_threads);
1811 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1812 1UL,1UL,cache_info->nexus_info[id],exception);
1813 if (p == (const Quantum *) NULL)
1815 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1816 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1817 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1818 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1819 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1820 return(MagickFalse);
1822 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1824 PixelChannel channel=GetPixelChannelChannel(image,i);
1825 pixel[channel]=p[i];
1831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835 + 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 %
1839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1841 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1842 % specified (x,y) location. The image background color is returned if an
1845 % The format of the GetOneVirtualPixelFromCache() method is:
1847 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1848 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1849 % Quantum *pixel,ExceptionInfo *exception)
1851 % A description of each parameter follows:
1853 % o image: the image.
1855 % o virtual_pixel_method: the virtual pixel method.
1857 % o x,y: These values define the location of the pixel to return.
1859 % o pixel: return a pixel at the specified (x,y) location.
1861 % o exception: return any errors or warnings in this structure.
1864 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1865 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1866 Quantum *pixel,ExceptionInfo *exception)
1872 id = GetOpenMPThreadId();
1880 assert(image != (const Image *) NULL);
1881 assert(image->signature == MagickSignature);
1882 assert(image->cache != (Cache) NULL);
1883 cache_info=(CacheInfo *) image->cache;
1884 assert(cache_info->signature == MagickSignature);
1885 assert(id < (int) cache_info->number_threads);
1886 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1887 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1888 cache_info->nexus_info[id],exception);
1889 if (p == (const Quantum *) NULL)
1891 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1892 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1893 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1894 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1895 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1896 return(MagickFalse);
1898 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1900 PixelChannel channel=GetPixelChannelChannel(image,i);
1901 pixel[channel]=p[i];
1907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1911 % G e t O n e V i r t u a l P i x e l I n f o %
1915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1917 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1918 % location. The image background color is returned if an error occurs. If
1919 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1921 % The format of the GetOneVirtualPixelInfo() method is:
1923 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1924 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1925 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1927 % A description of each parameter follows:
1929 % o image: the image.
1931 % o virtual_pixel_method: the virtual pixel method.
1933 % o x,y: these values define the location of the pixel to return.
1935 % o pixel: return a pixel at the specified (x,y) location.
1937 % o exception: return any errors or warnings in this structure.
1940 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1941 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1942 PixelInfo *pixel,ExceptionInfo *exception)
1948 id = GetOpenMPThreadId();
1950 register const Quantum
1953 assert(image != (const Image *) NULL);
1954 assert(image->signature == MagickSignature);
1955 assert(image->cache != (Cache) NULL);
1956 cache_info=(CacheInfo *) image->cache;
1957 assert(cache_info->signature == MagickSignature);
1958 assert(id < (int) cache_info->number_threads);
1959 GetPixelInfo(image,pixel);
1960 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1961 cache_info->nexus_info[id],exception);
1962 if (p == (const Quantum *) NULL)
1963 return(MagickFalse);
1964 GetPixelInfoPixel(image,p,pixel);
1969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1973 + G e t P i x e l C a c h e C o l o r s p a c e %
1977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1981 % The format of the GetPixelCacheColorspace() method is:
1983 % Colorspace GetPixelCacheColorspace(Cache cache)
1985 % A description of each parameter follows:
1987 % o cache: the pixel cache.
1990 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1995 assert(cache != (Cache) NULL);
1996 cache_info=(CacheInfo *) cache;
1997 assert(cache_info->signature == MagickSignature);
1998 if (cache_info->debug != MagickFalse)
1999 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2000 cache_info->filename);
2001 return(cache_info->colorspace);
2005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009 + G e t P i x e l C a c h e M e t h o d s %
2013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2015 % GetPixelCacheMethods() initializes the CacheMethods structure.
2017 % The format of the GetPixelCacheMethods() method is:
2019 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2021 % A description of each parameter follows:
2023 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2026 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2028 assert(cache_methods != (CacheMethods *) NULL);
2029 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2030 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2031 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2032 cache_methods->get_virtual_metacontent_from_handler=
2033 GetVirtualMetacontentFromCache;
2034 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2035 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2036 cache_methods->get_authentic_metacontent_from_handler=
2037 GetAuthenticMetacontentFromCache;
2038 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2039 cache_methods->get_one_authentic_pixel_from_handler=
2040 GetOneAuthenticPixelFromCache;
2041 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2042 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2043 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2051 + G e t P i x e l C a c h e N e x u s E x t e n t %
2055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2057 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2058 % corresponding with the last call to SetPixelCacheNexusPixels() or
2059 % GetPixelCacheNexusPixels().
2061 % The format of the GetPixelCacheNexusExtent() method is:
2063 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2064 % NexusInfo *nexus_info)
2066 % A description of each parameter follows:
2068 % o nexus_info: the nexus info.
2071 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2072 NexusInfo *nexus_info)
2080 assert(cache != NULL);
2081 cache_info=(CacheInfo *) cache;
2082 assert(cache_info->signature == MagickSignature);
2083 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2085 return((MagickSizeType) cache_info->columns*cache_info->rows);
2090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094 + 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 %
2098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2100 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2103 % The format of the GetPixelCacheNexusMetacontent() method is:
2105 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2106 % NexusInfo *nexus_info)
2108 % A description of each parameter follows:
2110 % o cache: the pixel cache.
2112 % o nexus_info: the cache nexus to return the meta-content.
2115 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2116 NexusInfo *nexus_info)
2121 assert(cache != NULL);
2122 cache_info=(CacheInfo *) cache;
2123 assert(cache_info->signature == MagickSignature);
2124 if (cache_info->storage_class == UndefinedClass)
2125 return((void *) NULL);
2126 return(nexus_info->metacontent);
2130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2134 + G e t P i x e l C a c h e N e x u s P i x e l s %
2138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2140 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2143 % The format of the GetPixelCacheNexusPixels() method is:
2145 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2146 % NexusInfo *nexus_info)
2148 % A description of each parameter follows:
2150 % o cache: the pixel cache.
2152 % o nexus_info: the cache nexus to return the pixels.
2155 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2156 NexusInfo *nexus_info)
2161 assert(cache != NULL);
2162 cache_info=(CacheInfo *) cache;
2163 assert(cache_info->signature == MagickSignature);
2164 if (cache_info->storage_class == UndefinedClass)
2165 return((Quantum *) NULL);
2166 return(nexus_info->pixels);
2170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2174 + G e t P i x e l C a c h e P i x e l s %
2178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2180 % GetPixelCachePixels() returns the pixels associated with the specified image.
2182 % The format of the GetPixelCachePixels() method is:
2184 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2185 % ExceptionInfo *exception)
2187 % A description of each parameter follows:
2189 % o image: the image.
2191 % o length: the pixel cache length.
2193 % o exception: return any errors or warnings in this structure.
2196 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2197 ExceptionInfo *exception)
2202 assert(image != (const Image *) NULL);
2203 assert(image->signature == MagickSignature);
2204 assert(image->cache != (Cache) NULL);
2205 assert(length != (MagickSizeType *) NULL);
2206 assert(exception != (ExceptionInfo *) NULL);
2207 assert(exception->signature == MagickSignature);
2208 cache_info=(CacheInfo *) image->cache;
2209 assert(cache_info->signature == MagickSignature);
2211 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2212 return((void *) NULL);
2213 *length=cache_info->length;
2214 return((void *) cache_info->pixels);
2218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2222 + 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 %
2226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2228 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2230 % The format of the GetPixelCacheStorageClass() method is:
2232 % ClassType GetPixelCacheStorageClass(Cache cache)
2234 % A description of each parameter follows:
2236 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2238 % o cache: the pixel cache.
2241 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2246 assert(cache != (Cache) NULL);
2247 cache_info=(CacheInfo *) cache;
2248 assert(cache_info->signature == MagickSignature);
2249 if (cache_info->debug != MagickFalse)
2250 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2251 cache_info->filename);
2252 return(cache_info->storage_class);
2256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2260 + G e t P i x e l C a c h e T i l e S i z e %
2264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2266 % GetPixelCacheTileSize() returns the pixel cache tile size.
2268 % The format of the GetPixelCacheTileSize() method is:
2270 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2273 % A description of each parameter follows:
2275 % o image: the image.
2277 % o width: the optimize cache tile width in pixels.
2279 % o height: the optimize cache tile height in pixels.
2282 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2288 assert(image != (Image *) NULL);
2289 assert(image->signature == MagickSignature);
2290 if (image->debug != MagickFalse)
2291 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2292 cache_info=(CacheInfo *) image->cache;
2293 assert(cache_info->signature == MagickSignature);
2294 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2295 if (GetImagePixelCacheType(image) == DiskCache)
2296 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2305 + 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 %
2309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2311 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2312 % pixel cache. A virtual pixel is any pixel access that is outside the
2313 % boundaries of the image cache.
2315 % The format of the GetPixelCacheVirtualMethod() method is:
2317 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2319 % A description of each parameter follows:
2321 % o image: the image.
2324 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2329 assert(image != (Image *) NULL);
2330 assert(image->signature == MagickSignature);
2331 assert(image->cache != (Cache) NULL);
2332 cache_info=(CacheInfo *) image->cache;
2333 assert(cache_info->signature == MagickSignature);
2334 return(cache_info->virtual_pixel_method);
2338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2342 + 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 %
2346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2348 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2349 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2351 % The format of the GetVirtualMetacontentFromCache() method is:
2353 % void *GetVirtualMetacontentFromCache(const Image *image)
2355 % A description of each parameter follows:
2357 % o image: the image.
2360 static const void *GetVirtualMetacontentFromCache(const Image *image)
2366 id = GetOpenMPThreadId();
2371 assert(image != (const Image *) NULL);
2372 assert(image->signature == MagickSignature);
2373 assert(image->cache != (Cache) NULL);
2374 cache_info=(CacheInfo *) image->cache;
2375 assert(cache_info->signature == MagickSignature);
2376 assert(id < (int) cache_info->number_threads);
2377 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2378 cache_info->nexus_info[id]);
2379 return(metacontent);
2383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2387 + 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 %
2391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2393 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2396 % The format of the GetVirtualMetacontentFromNexus() method is:
2398 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2399 % NexusInfo *nexus_info)
2401 % A description of each parameter follows:
2403 % o cache: the pixel cache.
2405 % o nexus_info: the cache nexus to return the meta-content.
2408 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2409 NexusInfo *nexus_info)
2414 assert(cache != (Cache) NULL);
2415 cache_info=(CacheInfo *) cache;
2416 assert(cache_info->signature == MagickSignature);
2417 if (cache_info->storage_class == UndefinedClass)
2418 return((void *) NULL);
2419 return(nexus_info->metacontent);
2423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2427 % G e t V i r t u a l M e t a c o n t e n t %
2431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2433 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2434 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2435 % returned if the meta-content are not available.
2437 % The format of the GetVirtualMetacontent() method is:
2439 % const void *GetVirtualMetacontent(const Image *image)
2441 % A description of each parameter follows:
2443 % o image: the image.
2446 MagickExport const void *GetVirtualMetacontent(const Image *image)
2452 id = GetOpenMPThreadId();
2457 assert(image != (const Image *) NULL);
2458 assert(image->signature == MagickSignature);
2459 assert(image->cache != (Cache) NULL);
2460 cache_info=(CacheInfo *) image->cache;
2461 assert(cache_info->signature == MagickSignature);
2462 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2463 if (metacontent != (void *) NULL)
2464 return(metacontent);
2465 assert(id < (int) cache_info->number_threads);
2466 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2467 cache_info->nexus_info[id]);
2468 return(metacontent);
2472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2476 + 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 %
2480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2482 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2483 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2484 % is returned if the pixels are transferred, otherwise a NULL is returned.
2486 % The format of the GetVirtualPixelsFromNexus() method is:
2488 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2489 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2490 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2491 % ExceptionInfo *exception)
2493 % A description of each parameter follows:
2495 % o image: the image.
2497 % o virtual_pixel_method: the virtual pixel method.
2499 % o x,y,columns,rows: These values define the perimeter of a region of
2502 % o nexus_info: the cache nexus to acquire.
2504 % o exception: return any errors or warnings in this structure.
2511 0, 48, 12, 60, 3, 51, 15, 63,
2512 32, 16, 44, 28, 35, 19, 47, 31,
2513 8, 56, 4, 52, 11, 59, 7, 55,
2514 40, 24, 36, 20, 43, 27, 39, 23,
2515 2, 50, 14, 62, 1, 49, 13, 61,
2516 34, 18, 46, 30, 33, 17, 45, 29,
2517 10, 58, 6, 54, 9, 57, 5, 53,
2518 42, 26, 38, 22, 41, 25, 37, 21
2521 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2526 index=x+DitherMatrix[x & 0x07]-32L;
2529 if (index >= (ssize_t) columns)
2530 return((ssize_t) columns-1L);
2534 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2539 index=y+DitherMatrix[y & 0x07]-32L;
2542 if (index >= (ssize_t) rows)
2543 return((ssize_t) rows-1L);
2547 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2551 if (x >= (ssize_t) columns)
2552 return((ssize_t) (columns-1));
2556 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2560 if (y >= (ssize_t) rows)
2561 return((ssize_t) (rows-1));
2565 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2567 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2570 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2572 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2575 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2576 const size_t extent)
2582 Compute the remainder of dividing offset by extent. It returns not only
2583 the quotient (tile the offset falls in) but also the positive remainer
2584 within that tile such that 0 <= remainder < extent. This method is
2585 essentially a ldiv() using a floored modulo division rather than the
2586 normal default truncated modulo division.
2588 modulo.quotient=offset/(ssize_t) extent;
2591 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2595 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2596 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2597 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2598 ExceptionInfo *exception)
2615 virtual_pixel[CompositePixelChannel];
2620 register const Quantum
2633 register unsigned char
2640 *virtual_metacontent;
2645 assert(image != (const Image *) NULL);
2646 assert(image->signature == MagickSignature);
2647 assert(image->cache != (Cache) NULL);
2648 cache_info=(CacheInfo *) image->cache;
2649 assert(cache_info->signature == MagickSignature);
2650 if (cache_info->type == UndefinedCache)
2651 return((const Quantum *) NULL);
2654 region.width=columns;
2656 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2658 if (pixels == (Quantum *) NULL)
2659 return((const Quantum *) NULL);
2661 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2662 nexus_info->region.x;
2663 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2664 nexus_info->region.width-1L;
2665 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2666 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2667 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2668 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2674 Pixel request is inside cache extents.
2676 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2678 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2679 if (status == MagickFalse)
2680 return((const Quantum *) NULL);
2681 if (cache_info->metacontent_extent != 0)
2683 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2684 if (status == MagickFalse)
2685 return((const Quantum *) NULL);
2690 Pixel request is outside cache extents.
2692 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2693 virtual_nexus=AcquirePixelCacheNexus(1);
2694 if (virtual_nexus == (NexusInfo **) NULL)
2696 if (virtual_nexus != (NexusInfo **) NULL)
2697 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2698 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2699 "UnableToGetCacheNexus","`%s'",image->filename);
2700 return((const Quantum *) NULL);
2702 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2703 sizeof(*virtual_pixel));
2704 virtual_metacontent=(void *) NULL;
2705 switch (virtual_pixel_method)
2707 case BackgroundVirtualPixelMethod:
2708 case BlackVirtualPixelMethod:
2709 case GrayVirtualPixelMethod:
2710 case TransparentVirtualPixelMethod:
2711 case MaskVirtualPixelMethod:
2712 case WhiteVirtualPixelMethod:
2713 case EdgeVirtualPixelMethod:
2714 case CheckerTileVirtualPixelMethod:
2715 case HorizontalTileVirtualPixelMethod:
2716 case VerticalTileVirtualPixelMethod:
2718 if (cache_info->metacontent_extent != 0)
2721 Acquire a metacontent buffer.
2723 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2724 cache_info->metacontent_extent);
2725 if (virtual_metacontent == (void *) NULL)
2727 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2728 (void) ThrowMagickException(exception,GetMagickModule(),
2729 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2730 return((const Quantum *) NULL);
2732 (void) ResetMagickMemory(virtual_metacontent,0,
2733 cache_info->metacontent_extent);
2735 switch (virtual_pixel_method)
2737 case BlackVirtualPixelMethod:
2739 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2740 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2741 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2744 case GrayVirtualPixelMethod:
2746 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2747 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2749 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2752 case TransparentVirtualPixelMethod:
2754 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2755 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2756 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2759 case MaskVirtualPixelMethod:
2760 case WhiteVirtualPixelMethod:
2762 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2763 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2764 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2769 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2771 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2773 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2775 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2777 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2787 for (v=0; v < (ssize_t) rows; v++)
2793 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2794 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2795 y_offset=EdgeY(y_offset,cache_info->rows);
2796 for (u=0; u < (ssize_t) columns; u+=length)
2802 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2803 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2804 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2812 Transfer a single pixel.
2814 length=(MagickSizeType) 1;
2815 switch (virtual_pixel_method)
2817 case EdgeVirtualPixelMethod:
2820 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2821 EdgeX(x_offset,cache_info->columns),
2822 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2824 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2827 case RandomVirtualPixelMethod:
2829 if (cache_info->random_info == (RandomInfo *) NULL)
2830 cache_info->random_info=AcquireRandomInfo();
2831 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2832 RandomX(cache_info->random_info,cache_info->columns),
2833 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2834 *virtual_nexus,exception);
2835 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2838 case DitherVirtualPixelMethod:
2840 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2841 DitherX(x_offset,cache_info->columns),
2842 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2844 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2847 case TileVirtualPixelMethod:
2849 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2850 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2851 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2852 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2854 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2857 case MirrorVirtualPixelMethod:
2859 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2860 if ((x_modulo.quotient & 0x01) == 1L)
2861 x_modulo.remainder=(ssize_t) cache_info->columns-
2862 x_modulo.remainder-1L;
2863 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2864 if ((y_modulo.quotient & 0x01) == 1L)
2865 y_modulo.remainder=(ssize_t) cache_info->rows-
2866 y_modulo.remainder-1L;
2867 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2868 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2870 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2873 case HorizontalTileEdgeVirtualPixelMethod:
2875 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2876 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2877 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2878 *virtual_nexus,exception);
2879 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2882 case VerticalTileEdgeVirtualPixelMethod:
2884 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2885 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2886 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2887 *virtual_nexus,exception);
2888 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2891 case BackgroundVirtualPixelMethod:
2892 case BlackVirtualPixelMethod:
2893 case GrayVirtualPixelMethod:
2894 case TransparentVirtualPixelMethod:
2895 case MaskVirtualPixelMethod:
2896 case WhiteVirtualPixelMethod:
2899 r=virtual_metacontent;
2902 case CheckerTileVirtualPixelMethod:
2904 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2905 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2906 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2909 r=virtual_metacontent;
2912 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2913 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2915 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2918 case HorizontalTileVirtualPixelMethod:
2920 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2923 r=virtual_metacontent;
2926 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2927 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2928 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2929 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2931 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2934 case VerticalTileVirtualPixelMethod:
2936 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2939 r=virtual_metacontent;
2942 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2943 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2944 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2945 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2947 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2951 if (p == (const Quantum *) NULL)
2953 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2955 q+=cache_info->number_channels;
2956 if ((s != (void *) NULL) && (r != (const void *) NULL))
2958 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2959 s+=cache_info->metacontent_extent;
2964 Transfer a run of pixels.
2966 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2967 (size_t) length,1UL,*virtual_nexus,exception);
2968 if (p == (const Quantum *) NULL)
2970 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2971 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2972 q+=length*cache_info->number_channels;
2973 if ((r != (void *) NULL) && (s != (const void *) NULL))
2975 (void) memcpy(s,r,(size_t) length);
2976 s+=length*cache_info->metacontent_extent;
2983 if (virtual_metacontent != (void *) NULL)
2984 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2985 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2994 + G e t V i r t u a l P i x e l C a c h e %
2998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3000 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3001 % cache as defined by the geometry parameters. A pointer to the pixels
3002 % is returned if the pixels are transferred, otherwise a NULL is returned.
3004 % The format of the GetVirtualPixelCache() method is:
3006 % const Quantum *GetVirtualPixelCache(const Image *image,
3007 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3008 % const ssize_t y,const size_t columns,const size_t rows,
3009 % ExceptionInfo *exception)
3011 % A description of each parameter follows:
3013 % o image: the image.
3015 % o virtual_pixel_method: the virtual pixel method.
3017 % o x,y,columns,rows: These values define the perimeter of a region of
3020 % o exception: return any errors or warnings in this structure.
3023 static const Quantum *GetVirtualPixelCache(const Image *image,
3024 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3025 const size_t columns,const size_t rows,ExceptionInfo *exception)
3031 id = GetOpenMPThreadId();
3036 assert(image != (const Image *) NULL);
3037 assert(image->signature == MagickSignature);
3038 assert(image->cache != (Cache) NULL);
3039 cache_info=(CacheInfo *) image->cache;
3040 assert(cache_info->signature == MagickSignature);
3041 assert(id < (int) cache_info->number_threads);
3042 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3043 cache_info->nexus_info[id],exception);
3048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3052 % G e t V i r t u a l P i x e l Q u e u e %
3056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3058 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3059 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3061 % The format of the GetVirtualPixelQueue() method is:
3063 % const Quantum *GetVirtualPixelQueue(const Image image)
3065 % A description of each parameter follows:
3067 % o image: the image.
3070 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3076 id = GetOpenMPThreadId();
3078 assert(image != (const Image *) NULL);
3079 assert(image->signature == MagickSignature);
3080 assert(image->cache != (Cache) NULL);
3081 cache_info=(CacheInfo *) image->cache;
3082 assert(cache_info->signature == MagickSignature);
3083 if (cache_info->methods.get_virtual_pixels_handler !=
3084 (GetVirtualPixelsHandler) NULL)
3085 return(cache_info->methods.get_virtual_pixels_handler(image));
3086 assert(id < (int) cache_info->number_threads);
3087 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3095 % G e t V i r t u a l P i x e l s %
3099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3101 % GetVirtualPixels() returns an immutable pixel region. If the
3102 % region is successfully accessed, a pointer to it is returned, otherwise
3103 % NULL is returned. The returned pointer may point to a temporary working
3104 % copy of the pixels or it may point to the original pixels in memory.
3105 % Performance is maximized if the selected region is part of one row, or one
3106 % or more full rows, since there is opportunity to access the pixels in-place
3107 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3108 % returned pointer must *never* be deallocated by the user.
3110 % Pixels accessed via the returned pointer represent a simple array of type
3111 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3112 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3113 % access the meta-content (of type void) corresponding to the the
3116 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3118 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3119 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3120 % GetCacheViewAuthenticPixels() instead.
3122 % The format of the GetVirtualPixels() method is:
3124 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3125 % const ssize_t y,const size_t columns,const size_t rows,
3126 % ExceptionInfo *exception)
3128 % A description of each parameter follows:
3130 % o image: the image.
3132 % o x,y,columns,rows: These values define the perimeter of a region of
3135 % o exception: return any errors or warnings in this structure.
3138 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3139 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3140 ExceptionInfo *exception)
3146 id = GetOpenMPThreadId();
3151 assert(image != (const Image *) NULL);
3152 assert(image->signature == MagickSignature);
3153 assert(image->cache != (Cache) NULL);
3154 cache_info=(CacheInfo *) image->cache;
3155 assert(cache_info->signature == MagickSignature);
3156 if (cache_info->methods.get_virtual_pixel_handler !=
3157 (GetVirtualPixelHandler) NULL)
3158 return(cache_info->methods.get_virtual_pixel_handler(image,
3159 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3160 assert(id < (int) cache_info->number_threads);
3161 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3162 columns,rows,cache_info->nexus_info[id],exception);
3167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3171 + 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 %
3175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3177 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3178 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3180 % The format of the GetVirtualPixelsCache() method is:
3182 % Quantum *GetVirtualPixelsCache(const Image *image)
3184 % A description of each parameter follows:
3186 % o image: the image.
3189 static const Quantum *GetVirtualPixelsCache(const Image *image)
3195 id = GetOpenMPThreadId();
3197 assert(image != (const Image *) NULL);
3198 assert(image->signature == MagickSignature);
3199 assert(image->cache != (Cache) NULL);
3200 cache_info=(CacheInfo *) image->cache;
3201 assert(cache_info->signature == MagickSignature);
3202 assert(id < (int) cache_info->number_threads);
3203 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3211 + G e t V i r t u a l P i x e l s N e x u s %
3215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3217 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3220 % The format of the GetVirtualPixelsNexus() method is:
3222 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3223 % NexusInfo *nexus_info)
3225 % A description of each parameter follows:
3227 % o cache: the pixel cache.
3229 % o nexus_info: the cache nexus to return the colormap pixels.
3232 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3233 NexusInfo *nexus_info)
3238 assert(cache != (Cache) NULL);
3239 cache_info=(CacheInfo *) cache;
3240 assert(cache_info->signature == MagickSignature);
3241 if (cache_info->storage_class == UndefinedClass)
3242 return((Quantum *) NULL);
3243 return((const Quantum *) nexus_info->pixels);
3247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3251 + O p e n P i x e l C a c h e %
3255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3257 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3258 % dimensions, allocating space for the image pixels and optionally the
3259 % metacontent, and memory mapping the cache if it is disk based. The cache
3260 % nexus array is initialized as well.
3262 % The format of the OpenPixelCache() method is:
3264 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3265 % ExceptionInfo *exception)
3267 % A description of each parameter follows:
3269 % o image: the image.
3271 % o mode: ReadMode, WriteMode, or IOMode.
3273 % o exception: return any errors or warnings in this structure.
3277 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3279 cache_info->mapped=MagickFalse;
3280 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3281 (size_t) cache_info->length));
3282 if (cache_info->pixels == (Quantum *) NULL)
3284 cache_info->mapped=MagickTrue;
3285 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3286 cache_info->length);
3290 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3297 Open pixel cache on disk.
3299 if (cache_info->file != -1)
3300 return(MagickTrue); /* cache already open */
3301 if (*cache_info->cache_filename == '\0')
3302 file=AcquireUniqueFileResource(cache_info->cache_filename);
3308 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3313 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3314 O_BINARY | O_EXCL,S_MODE);
3316 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3322 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3325 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3330 return(MagickFalse);
3331 (void) AcquireMagickResource(FileResource,1);
3332 cache_info->file=file;
3333 cache_info->mode=mode;
3337 static inline MagickOffsetType WritePixelCacheRegion(
3338 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3339 const MagickSizeType length,const unsigned char *restrict buffer)
3341 register MagickOffsetType
3347 #if !defined(MAGICKCORE_HAVE_PWRITE)
3348 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3349 return((MagickOffsetType) -1);
3352 for (i=0; i < (MagickOffsetType) length; i+=count)
3354 #if !defined(MAGICKCORE_HAVE_PWRITE)
3355 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3356 (MagickSizeType) SSIZE_MAX));
3358 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3359 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3371 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3381 cache_info=(CacheInfo *) image->cache;
3382 if (image->debug != MagickFalse)
3385 format[MaxTextExtent],
3386 message[MaxTextExtent];
3388 (void) FormatMagickSize(length,MagickFalse,format);
3389 (void) FormatLocaleString(message,MaxTextExtent,
3390 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3391 cache_info->cache_filename,cache_info->file,format);
3392 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3394 if (length != (MagickSizeType) ((MagickOffsetType) length))
3395 return(MagickFalse);
3396 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3398 return(MagickFalse);
3399 if ((MagickSizeType) offset >= length)
3401 extent=(MagickOffsetType) length-1;
3402 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3403 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3404 if (cache_info->synchronize != MagickFalse)
3409 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3411 return(MagickFalse);
3414 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3417 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3418 ExceptionInfo *exception)
3425 format[MaxTextExtent],
3426 message[MaxTextExtent];
3442 assert(image != (const Image *) NULL);
3443 assert(image->signature == MagickSignature);
3444 assert(image->cache != (Cache) NULL);
3445 if (image->debug != MagickFalse)
3446 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3447 if ((image->columns == 0) || (image->rows == 0))
3448 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3449 cache_info=(CacheInfo *) image->cache;
3450 assert(cache_info->signature == MagickSignature);
3451 source_info=(*cache_info);
3452 source_info.file=(-1);
3453 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3454 image->filename,(double) GetImageIndexInList(image));
3455 cache_info->storage_class=image->storage_class;
3456 cache_info->colorspace=image->colorspace;
3457 cache_info->alpha_trait=image->alpha_trait;
3458 cache_info->mask=image->mask;
3459 cache_info->rows=image->rows;
3460 cache_info->columns=image->columns;
3461 InitializePixelChannelMap(image);
3462 cache_info->number_channels=GetPixelChannels(image);
3463 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3464 sizeof(*image->channel_map));
3465 cache_info->metacontent_extent=image->metacontent_extent;
3466 cache_info->mode=mode;
3467 if (image->ping != MagickFalse)
3469 cache_info->type=PingCache;
3470 cache_info->pixels=(Quantum *) NULL;
3471 cache_info->metacontent=(void *) NULL;
3472 cache_info->length=0;
3475 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3476 packet_size=cache_info->number_channels*sizeof(Quantum);
3477 if (image->metacontent_extent != 0)
3478 packet_size+=cache_info->metacontent_extent;
3479 length=number_pixels*packet_size;
3480 columns=(size_t) (length/cache_info->rows/packet_size);
3481 if (cache_info->columns != columns)
3482 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3484 cache_info->length=length;
3485 status=AcquireMagickResource(AreaResource,cache_info->length);
3486 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3487 cache_info->metacontent_extent);
3488 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3490 status=AcquireMagickResource(MemoryResource,cache_info->length);
3491 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3492 (cache_info->type == MemoryCache))
3494 AllocatePixelCachePixels(cache_info);
3495 if (cache_info->pixels == (Quantum *) NULL)
3496 cache_info->pixels=source_info.pixels;
3500 Create memory pixel cache.
3503 cache_info->type=MemoryCache;
3504 cache_info->metacontent=(void *) NULL;
3505 if (cache_info->metacontent_extent != 0)
3506 cache_info->metacontent=(void *) (cache_info->pixels+
3507 number_pixels*cache_info->number_channels);
3508 if ((source_info.storage_class != UndefinedClass) &&
3511 status=ClonePixelCacheRepository(cache_info,&source_info,
3513 RelinquishPixelCachePixels(&source_info);
3515 if (image->debug != MagickFalse)
3517 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3518 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3520 (void) FormatLocaleString(message,MaxTextExtent,
3521 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3522 cache_info->filename,cache_info->mapped != MagickFalse ?
3523 "Anonymous" : "Heap",type,(double) cache_info->columns,
3524 (double) cache_info->rows,(double)
3525 cache_info->number_channels,format);
3526 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3532 RelinquishMagickResource(MemoryResource,cache_info->length);
3535 Create pixel cache on disk.
3537 status=AcquireMagickResource(DiskResource,cache_info->length);
3538 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3543 if (cache_info->type == DistributedCache)
3544 RelinquishMagickResource(DiskResource,cache_info->length);
3545 server_info=AcquireDistributeCacheInfo(exception);
3546 if (server_info != (DistributeCacheInfo *) NULL)
3548 status=OpenDistributePixelCache(server_info,image);
3549 if (status == MagickFalse)
3551 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3552 GetDistributeCacheHostname(server_info));
3553 server_info=DestroyDistributeCacheInfo(server_info);
3558 Create a distributed pixel cache.
3560 cache_info->type=DistributedCache;
3561 cache_info->server_info=server_info;
3562 (void) FormatLocaleString(cache_info->cache_filename,
3563 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3564 (DistributeCacheInfo *) cache_info->server_info),
3565 GetDistributeCachePort((DistributeCacheInfo *)
3566 cache_info->server_info));
3567 if ((source_info.storage_class != UndefinedClass) &&
3570 status=ClonePixelCacheRepository(cache_info,&source_info,
3572 RelinquishPixelCachePixels(&source_info);
3574 if (image->debug != MagickFalse)
3576 (void) FormatMagickSize(cache_info->length,MagickFalse,
3578 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3580 (void) FormatLocaleString(message,MaxTextExtent,
3581 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3582 cache_info->filename,cache_info->cache_filename,
3583 GetDistributeCacheFile((DistributeCacheInfo *)
3584 cache_info->server_info),type,(double) cache_info->columns,
3585 (double) cache_info->rows,(double)
3586 cache_info->number_channels,format);
3587 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3593 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3594 "CacheResourcesExhausted","`%s'",image->filename);
3595 return(MagickFalse);
3597 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3599 (void) ClosePixelCacheOnDisk(cache_info);
3600 *cache_info->cache_filename='\0';
3602 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3604 RelinquishMagickResource(DiskResource,cache_info->length);
3605 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3607 return(MagickFalse);
3609 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3610 cache_info->length);
3611 if (status == MagickFalse)
3613 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3615 return(MagickFalse);
3617 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3618 cache_info->metacontent_extent);
3619 if (length != (MagickSizeType) ((size_t) length))
3620 cache_info->type=DiskCache;
3623 status=AcquireMagickResource(MapResource,cache_info->length);
3624 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3625 (cache_info->type != MemoryCache))
3626 cache_info->type=DiskCache;
3629 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3630 cache_info->offset,(size_t) cache_info->length);
3631 if (cache_info->pixels == (Quantum *) NULL)
3633 cache_info->type=DiskCache;
3634 cache_info->pixels=source_info.pixels;
3639 Create file-backed memory-mapped pixel cache.
3642 (void) ClosePixelCacheOnDisk(cache_info);
3643 cache_info->type=MapCache;
3644 cache_info->mapped=MagickTrue;
3645 cache_info->metacontent=(void *) NULL;
3646 if (cache_info->metacontent_extent != 0)
3647 cache_info->metacontent=(void *) (cache_info->pixels+
3648 number_pixels*cache_info->number_channels);
3649 if ((source_info.storage_class != UndefinedClass) &&
3652 status=ClonePixelCacheRepository(cache_info,&source_info,
3654 RelinquishPixelCachePixels(&source_info);
3656 if (image->debug != MagickFalse)
3658 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3659 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3661 (void) FormatLocaleString(message,MaxTextExtent,
3662 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3663 cache_info->filename,cache_info->cache_filename,
3664 cache_info->file,type,(double) cache_info->columns,(double)
3665 cache_info->rows,(double) cache_info->number_channels,
3667 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3673 RelinquishMagickResource(MapResource,cache_info->length);
3676 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3678 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3679 RelinquishPixelCachePixels(&source_info);
3681 if (image->debug != MagickFalse)
3683 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3684 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3686 (void) FormatLocaleString(message,MaxTextExtent,
3687 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3688 cache_info->cache_filename,cache_info->file,type,(double)
3689 cache_info->columns,(double) cache_info->rows,(double)
3690 cache_info->number_channels,format);
3691 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3701 + P e r s i s t P i x e l C a c h e %
3705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3707 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3708 % persistent pixel cache is one that resides on disk and is not destroyed
3709 % when the program exits.
3711 % The format of the PersistPixelCache() method is:
3713 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3714 % const MagickBooleanType attach,MagickOffsetType *offset,
3715 % ExceptionInfo *exception)
3717 % A description of each parameter follows:
3719 % o image: the image.
3721 % o filename: the persistent pixel cache filename.
3723 % o attach: A value other than zero initializes the persistent pixel cache.
3725 % o initialize: A value other than zero initializes the persistent pixel
3728 % o offset: the offset in the persistent cache to store pixels.
3730 % o exception: return any errors or warnings in this structure.
3733 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3734 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3735 ExceptionInfo *exception)
3750 assert(image != (Image *) NULL);
3751 assert(image->signature == MagickSignature);
3752 if (image->debug != MagickFalse)
3753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3754 assert(image->cache != (void *) NULL);
3755 assert(filename != (const char *) NULL);
3756 assert(offset != (MagickOffsetType *) NULL);
3757 page_size=GetMagickPageSize();
3758 cache_info=(CacheInfo *) image->cache;
3759 assert(cache_info->signature == MagickSignature);
3760 if (attach != MagickFalse)
3763 Attach existing persistent pixel cache.
3765 if (image->debug != MagickFalse)
3766 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3767 "attach persistent cache");
3768 (void) CopyMagickString(cache_info->cache_filename,filename,
3770 cache_info->type=DiskCache;
3771 cache_info->offset=(*offset);
3772 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3773 return(MagickFalse);
3774 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3777 if ((cache_info->mode != ReadMode) &&
3778 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3779 (cache_info->reference_count == 1))
3781 LockSemaphoreInfo(cache_info->semaphore);
3782 if ((cache_info->mode != ReadMode) &&
3783 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3784 (cache_info->reference_count == 1))
3790 Usurp existing persistent pixel cache.
3792 status=rename_utf8(cache_info->cache_filename,filename);
3795 (void) CopyMagickString(cache_info->cache_filename,filename,
3797 *offset+=cache_info->length+page_size-(cache_info->length %
3799 UnlockSemaphoreInfo(cache_info->semaphore);
3800 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3801 if (image->debug != MagickFalse)
3802 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3803 "Usurp resident persistent cache");
3807 UnlockSemaphoreInfo(cache_info->semaphore);
3810 Clone persistent pixel cache.
3812 clone_image=(*image);
3813 clone_info=(CacheInfo *) clone_image.cache;
3814 image->cache=ClonePixelCache(cache_info);
3815 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3816 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3817 cache_info->type=DiskCache;
3818 cache_info->offset=(*offset);
3819 cache_info=(CacheInfo *) image->cache;
3820 status=OpenPixelCache(image,IOMode,exception);
3821 if (status != MagickFalse)
3822 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3823 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3824 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3833 + 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 %
3837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3839 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3840 % defined by the region rectangle and returns a pointer to the region. This
3841 % region is subsequently transferred from the pixel cache with
3842 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3843 % pixels are transferred, otherwise a NULL is returned.
3845 % The format of the QueueAuthenticPixelCacheNexus() method is:
3847 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3848 % const ssize_t y,const size_t columns,const size_t rows,
3849 % const MagickBooleanType clone,NexusInfo *nexus_info,
3850 % ExceptionInfo *exception)
3852 % A description of each parameter follows:
3854 % o image: the image.
3856 % o x,y,columns,rows: These values define the perimeter of a region of
3859 % o nexus_info: the cache nexus to set.
3861 % o clone: clone the pixel cache.
3863 % o exception: return any errors or warnings in this structure.
3866 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3867 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3868 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3886 Validate pixel cache geometry.
3888 assert(image != (const Image *) NULL);
3889 assert(image->signature == MagickSignature);
3890 assert(image->cache != (Cache) NULL);
3891 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3892 if (cache_info == (Cache) NULL)
3893 return((Quantum *) NULL);
3894 assert(cache_info->signature == MagickSignature);
3895 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3896 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3897 (y >= (ssize_t) cache_info->rows))
3899 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3900 "PixelsAreNotAuthentic","`%s'",image->filename);
3901 return((Quantum *) NULL);
3903 offset=(MagickOffsetType) y*cache_info->columns+x;
3905 return((Quantum *) NULL);
3906 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3907 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3908 if ((MagickSizeType) offset >= number_pixels)
3909 return((Quantum *) NULL);
3915 region.width=columns;
3917 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3927 + Q u e u e A u t h e n t i c P i x e l s C a c h e %
3931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3933 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3934 % defined by the region rectangle and returns a pointer to the region. This
3935 % region is subsequently transferred from the pixel cache with
3936 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3937 % pixels are transferred, otherwise a NULL is returned.
3939 % The format of the QueueAuthenticPixelsCache() method is:
3941 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3942 % const ssize_t y,const size_t columns,const size_t rows,
3943 % ExceptionInfo *exception)
3945 % A description of each parameter follows:
3947 % o image: the image.
3949 % o x,y,columns,rows: These values define the perimeter of a region of
3952 % o exception: return any errors or warnings in this structure.
3955 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3956 const ssize_t y,const size_t columns,const size_t rows,
3957 ExceptionInfo *exception)
3963 id = GetOpenMPThreadId();
3968 assert(image != (const Image *) NULL);
3969 assert(image->signature == MagickSignature);
3970 assert(image->cache != (Cache) NULL);
3971 cache_info=(CacheInfo *) image->cache;
3972 assert(cache_info->signature == MagickSignature);
3973 assert(id < (int) cache_info->number_threads);
3974 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3975 cache_info->nexus_info[id],exception);
3980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3984 % Q u e u e A u t h e n t i c P i x e l s %
3988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3990 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3991 % successfully initialized a pointer to a Quantum array representing the
3992 % region is returned, otherwise NULL is returned. The returned pointer may
3993 % point to a temporary working buffer for the pixels or it may point to the
3994 % final location of the pixels in memory.
3996 % Write-only access means that any existing pixel values corresponding to
3997 % the region are ignored. This is useful if the initial image is being
3998 % created from scratch, or if the existing pixel values are to be
3999 % completely replaced without need to refer to their pre-existing values.
4000 % The application is free to read and write the pixel buffer returned by
4001 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4002 % initialize the pixel array values. Initializing pixel array values is the
4003 % application's responsibility.
4005 % Performance is maximized if the selected region is part of one row, or
4006 % one or more full rows, since then there is opportunity to access the
4007 % pixels in-place (without a copy) if the image is in memory, or in a
4008 % memory-mapped file. The returned pointer must *never* be deallocated
4011 % Pixels accessed via the returned pointer represent a simple array of type
4012 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4013 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4014 % obtain the meta-content (of type void) corresponding to the region.
4015 % Once the Quantum (and/or Quantum) array has been updated, the
4016 % changes must be saved back to the underlying image using
4017 % SyncAuthenticPixels() or they may be lost.
4019 % The format of the QueueAuthenticPixels() method is:
4021 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4022 % const ssize_t y,const size_t columns,const size_t rows,
4023 % ExceptionInfo *exception)
4025 % A description of each parameter follows:
4027 % o image: the image.
4029 % o x,y,columns,rows: These values define the perimeter of a region of
4032 % o exception: return any errors or warnings in this structure.
4035 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4036 const ssize_t y,const size_t columns,const size_t rows,
4037 ExceptionInfo *exception)
4043 id = GetOpenMPThreadId();
4048 assert(image != (Image *) NULL);
4049 assert(image->signature == MagickSignature);
4050 assert(image->cache != (Cache) NULL);
4051 cache_info=(CacheInfo *) image->cache;
4052 assert(cache_info->signature == MagickSignature);
4053 if (cache_info->methods.queue_authentic_pixels_handler !=
4054 (QueueAuthenticPixelsHandler) NULL)
4056 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4057 columns,rows,exception);
4060 assert(id < (int) cache_info->number_threads);
4061 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4062 cache_info->nexus_info[id],exception);
4067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4071 + R e a d P i x e l C a c h e M e t a c o n t e n t %
4075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4077 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4080 % The format of the ReadPixelCacheMetacontent() method is:
4082 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4083 % NexusInfo *nexus_info,ExceptionInfo *exception)
4085 % A description of each parameter follows:
4087 % o cache_info: the pixel cache.
4089 % o nexus_info: the cache nexus to read the metacontent.
4091 % o exception: return any errors or warnings in this structure.
4095 static inline MagickOffsetType ReadPixelCacheRegion(
4096 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4097 const MagickSizeType length,unsigned char *restrict buffer)
4099 register MagickOffsetType
4105 #if !defined(MAGICKCORE_HAVE_PREAD)
4106 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4107 return((MagickOffsetType) -1);
4110 for (i=0; i < (MagickOffsetType) length; i+=count)
4112 #if !defined(MAGICKCORE_HAVE_PREAD)
4113 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4114 (MagickSizeType) SSIZE_MAX));
4116 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4117 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4129 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4130 NexusInfo *nexus_info,ExceptionInfo *exception)
4143 register unsigned char
4149 if (cache_info->metacontent_extent == 0)
4150 return(MagickFalse);
4151 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4153 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4154 nexus_info->region.x;
4155 length=(MagickSizeType) nexus_info->region.width*
4156 cache_info->metacontent_extent;
4157 extent=length*nexus_info->region.height;
4158 rows=nexus_info->region.height;
4160 q=(unsigned char *) nexus_info->metacontent;
4161 switch (cache_info->type)
4166 register unsigned char
4170 Read meta-content from memory.
4172 if ((cache_info->columns == nexus_info->region.width) &&
4173 (extent == (MagickSizeType) ((size_t) extent)))
4178 p=(unsigned char *) cache_info->metacontent+offset*
4179 cache_info->metacontent_extent;
4180 for (y=0; y < (ssize_t) rows; y++)
4182 (void) memcpy(q,p,(size_t) length);
4183 p+=cache_info->metacontent_extent*cache_info->columns;
4184 q+=cache_info->metacontent_extent*nexus_info->region.width;
4191 Read meta content from disk.
4193 LockSemaphoreInfo(cache_info->file_semaphore);
4194 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4196 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4197 cache_info->cache_filename);
4198 UnlockSemaphoreInfo(cache_info->file_semaphore);
4199 return(MagickFalse);
4201 if ((cache_info->columns == nexus_info->region.width) &&
4202 (extent <= MagickMaxBufferExtent))
4207 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4208 for (y=0; y < (ssize_t) rows; y++)
4210 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4211 cache_info->number_channels*sizeof(Quantum)+offset*
4212 cache_info->metacontent_extent,length,(unsigned char *) q);
4213 if (count != (MagickOffsetType) length)
4215 offset+=cache_info->columns;
4216 q+=cache_info->metacontent_extent*nexus_info->region.width;
4218 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4219 (void) ClosePixelCacheOnDisk(cache_info);
4220 UnlockSemaphoreInfo(cache_info->file_semaphore);
4223 case DistributedCache:
4229 Read metacontent from distributed cache.
4231 LockSemaphoreInfo(cache_info->file_semaphore);
4232 region=nexus_info->region;
4233 if ((cache_info->columns != nexus_info->region.width) ||
4234 (extent > MagickMaxBufferExtent))
4241 for (y=0; y < (ssize_t) rows; y++)
4243 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4244 cache_info->server_info,®ion,length,(unsigned char *) q);
4245 if (count != (MagickOffsetType) length)
4247 q+=cache_info->metacontent_extent*nexus_info->region.width;
4250 UnlockSemaphoreInfo(cache_info->file_semaphore);
4256 if (y < (ssize_t) rows)
4258 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4259 cache_info->cache_filename);
4260 return(MagickFalse);
4262 if ((cache_info->debug != MagickFalse) &&
4263 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4264 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4265 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4266 nexus_info->region.width,(double) nexus_info->region.height,(double)
4267 nexus_info->region.x,(double) nexus_info->region.y);
4272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4276 + R e a d P i x e l C a c h e P i x e l s %
4280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4282 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4285 % The format of the ReadPixelCachePixels() method is:
4287 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4288 % NexusInfo *nexus_info,ExceptionInfo *exception)
4290 % A description of each parameter follows:
4292 % o cache_info: the pixel cache.
4294 % o nexus_info: the cache nexus to read the pixels.
4296 % o exception: return any errors or warnings in this structure.
4299 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4300 NexusInfo *nexus_info,ExceptionInfo *exception)
4319 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4321 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4322 nexus_info->region.x;
4323 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4325 extent=length*nexus_info->region.height;
4326 rows=nexus_info->region.height;
4328 q=nexus_info->pixels;
4329 switch (cache_info->type)
4338 Read pixels from memory.
4340 if ((cache_info->columns == nexus_info->region.width) &&
4341 (extent == (MagickSizeType) ((size_t) extent)))
4346 p=cache_info->pixels+offset*cache_info->number_channels;
4347 for (y=0; y < (ssize_t) rows; y++)
4349 (void) memcpy(q,p,(size_t) length);
4350 p+=cache_info->number_channels*cache_info->columns;
4351 q+=cache_info->number_channels*nexus_info->region.width;
4358 Read pixels from disk.
4360 LockSemaphoreInfo(cache_info->file_semaphore);
4361 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4363 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4364 cache_info->cache_filename);
4365 UnlockSemaphoreInfo(cache_info->file_semaphore);
4366 return(MagickFalse);
4368 if ((cache_info->columns == nexus_info->region.width) &&
4369 (extent <= MagickMaxBufferExtent))
4374 for (y=0; y < (ssize_t) rows; y++)
4376 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4377 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4378 if (count != (MagickOffsetType) length)
4380 offset+=cache_info->columns;
4381 q+=cache_info->number_channels*nexus_info->region.width;
4383 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4384 (void) ClosePixelCacheOnDisk(cache_info);
4385 UnlockSemaphoreInfo(cache_info->file_semaphore);
4388 case DistributedCache:
4394 Read pixels from distributed cache.
4396 LockSemaphoreInfo(cache_info->file_semaphore);
4397 region=nexus_info->region;
4398 if ((cache_info->columns != nexus_info->region.width) ||
4399 (extent > MagickMaxBufferExtent))
4406 for (y=0; y < (ssize_t) rows; y++)
4408 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4409 cache_info->server_info,®ion,length,(unsigned char *) q);
4410 if (count != (MagickOffsetType) length)
4412 q+=cache_info->number_channels*nexus_info->region.width;
4415 UnlockSemaphoreInfo(cache_info->file_semaphore);
4421 if (y < (ssize_t) rows)
4423 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4424 cache_info->cache_filename);
4425 return(MagickFalse);
4427 if ((cache_info->debug != MagickFalse) &&
4428 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4429 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4430 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4431 nexus_info->region.width,(double) nexus_info->region.height,(double)
4432 nexus_info->region.x,(double) nexus_info->region.y);
4437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4441 + R e f e r e n c e P i x e l C a c h e %
4445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447 % ReferencePixelCache() increments the reference count associated with the
4448 % pixel cache returning a pointer to the cache.
4450 % The format of the ReferencePixelCache method is:
4452 % Cache ReferencePixelCache(Cache cache_info)
4454 % A description of each parameter follows:
4456 % o cache_info: the pixel cache.
4459 MagickPrivate Cache ReferencePixelCache(Cache cache)
4464 assert(cache != (Cache *) NULL);
4465 cache_info=(CacheInfo *) cache;
4466 assert(cache_info->signature == MagickSignature);
4467 LockSemaphoreInfo(cache_info->semaphore);
4468 cache_info->reference_count++;
4469 UnlockSemaphoreInfo(cache_info->semaphore);
4474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4478 + S e t P i x e l C a c h e M e t h o d s %
4482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4484 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4486 % The format of the SetPixelCacheMethods() method is:
4488 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4490 % A description of each parameter follows:
4492 % o cache: the pixel cache.
4494 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4497 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4502 GetOneAuthenticPixelFromHandler
4503 get_one_authentic_pixel_from_handler;
4505 GetOneVirtualPixelFromHandler
4506 get_one_virtual_pixel_from_handler;
4509 Set cache pixel methods.
4511 assert(cache != (Cache) NULL);
4512 assert(cache_methods != (CacheMethods *) NULL);
4513 cache_info=(CacheInfo *) cache;
4514 assert(cache_info->signature == MagickSignature);
4515 if (cache_info->debug != MagickFalse)
4516 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4517 cache_info->filename);
4518 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4519 cache_info->methods.get_virtual_pixel_handler=
4520 cache_methods->get_virtual_pixel_handler;
4521 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4522 cache_info->methods.destroy_pixel_handler=
4523 cache_methods->destroy_pixel_handler;
4524 if (cache_methods->get_virtual_metacontent_from_handler !=
4525 (GetVirtualMetacontentFromHandler) NULL)
4526 cache_info->methods.get_virtual_metacontent_from_handler=
4527 cache_methods->get_virtual_metacontent_from_handler;
4528 if (cache_methods->get_authentic_pixels_handler !=
4529 (GetAuthenticPixelsHandler) NULL)
4530 cache_info->methods.get_authentic_pixels_handler=
4531 cache_methods->get_authentic_pixels_handler;
4532 if (cache_methods->queue_authentic_pixels_handler !=
4533 (QueueAuthenticPixelsHandler) NULL)
4534 cache_info->methods.queue_authentic_pixels_handler=
4535 cache_methods->queue_authentic_pixels_handler;
4536 if (cache_methods->sync_authentic_pixels_handler !=
4537 (SyncAuthenticPixelsHandler) NULL)
4538 cache_info->methods.sync_authentic_pixels_handler=
4539 cache_methods->sync_authentic_pixels_handler;
4540 if (cache_methods->get_authentic_pixels_from_handler !=
4541 (GetAuthenticPixelsFromHandler) NULL)
4542 cache_info->methods.get_authentic_pixels_from_handler=
4543 cache_methods->get_authentic_pixels_from_handler;
4544 if (cache_methods->get_authentic_metacontent_from_handler !=
4545 (GetAuthenticMetacontentFromHandler) NULL)
4546 cache_info->methods.get_authentic_metacontent_from_handler=
4547 cache_methods->get_authentic_metacontent_from_handler;
4548 get_one_virtual_pixel_from_handler=
4549 cache_info->methods.get_one_virtual_pixel_from_handler;
4550 if (get_one_virtual_pixel_from_handler !=
4551 (GetOneVirtualPixelFromHandler) NULL)
4552 cache_info->methods.get_one_virtual_pixel_from_handler=
4553 cache_methods->get_one_virtual_pixel_from_handler;
4554 get_one_authentic_pixel_from_handler=
4555 cache_methods->get_one_authentic_pixel_from_handler;
4556 if (get_one_authentic_pixel_from_handler !=
4557 (GetOneAuthenticPixelFromHandler) NULL)
4558 cache_info->methods.get_one_authentic_pixel_from_handler=
4559 cache_methods->get_one_authentic_pixel_from_handler;
4563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4567 + S e t P i x e l C a c h e N e x u s P i x e l s %
4571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4573 % SetPixelCacheNexusPixels() defines the region of the cache for the
4574 % specified cache nexus.
4576 % The format of the SetPixelCacheNexusPixels() method is:
4578 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4579 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4580 % ExceptionInfo *exception)
4582 % A description of each parameter follows:
4584 % o cache_info: the pixel cache.
4586 % o mode: ReadMode, WriteMode, or IOMode.
4588 % o region: A pointer to the RectangleInfo structure that defines the
4589 % region of this particular cache nexus.
4591 % o nexus_info: the cache nexus to set.
4593 % o exception: return any errors or warnings in this structure.
4597 static inline MagickBooleanType AcquireCacheNexusPixels(
4598 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4599 ExceptionInfo *exception)
4601 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4602 return(MagickFalse);
4603 nexus_info->mapped=MagickFalse;
4604 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4605 (size_t) nexus_info->length));
4606 if (nexus_info->cache == (Quantum *) NULL)
4608 nexus_info->mapped=MagickTrue;
4609 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4610 nexus_info->length);
4612 if (nexus_info->cache == (Quantum *) NULL)
4614 (void) ThrowMagickException(exception,GetMagickModule(),
4615 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4616 cache_info->filename);
4617 return(MagickFalse);
4622 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4625 if (mode == ReadMode)
4627 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4630 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4633 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4634 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4635 ExceptionInfo *exception)
4644 assert(cache_info != (const CacheInfo *) NULL);
4645 assert(cache_info->signature == MagickSignature);
4646 if (cache_info->type == UndefinedCache)
4647 return((Quantum *) NULL);
4648 nexus_info->region=(*region);
4649 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4655 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4656 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4657 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4658 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4659 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4660 ((nexus_info->region.width == cache_info->columns) ||
4661 ((nexus_info->region.width % cache_info->columns) == 0)))))
4667 Pixels are accessed directly from memory.
4669 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4670 nexus_info->region.x;
4671 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4673 nexus_info->metacontent=(void *) NULL;
4674 if (cache_info->metacontent_extent != 0)
4675 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4676 offset*cache_info->metacontent_extent;
4677 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4678 return(nexus_info->pixels);
4682 Pixels are stored in a cache region until they are synced to the cache.
4684 number_pixels=(MagickSizeType) nexus_info->region.width*
4685 nexus_info->region.height;
4686 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4687 if (cache_info->metacontent_extent != 0)
4688 length+=number_pixels*cache_info->metacontent_extent;
4689 if (nexus_info->cache == (Quantum *) NULL)
4691 nexus_info->length=length;
4692 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4693 if (status == MagickFalse)
4695 nexus_info->length=0;
4696 return((Quantum *) NULL);
4700 if (nexus_info->length != length)
4702 RelinquishCacheNexusPixels(nexus_info);
4703 nexus_info->length=length;
4704 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4705 if (status == MagickFalse)
4707 nexus_info->length=0;
4708 return((Quantum *) NULL);
4711 nexus_info->pixels=nexus_info->cache;
4712 nexus_info->metacontent=(void *) NULL;
4713 if (cache_info->metacontent_extent != 0)
4714 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4715 cache_info->number_channels);
4716 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4717 return(nexus_info->pixels);
4721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4725 % S e t P i x e l C a c h e V i r t u a l M e t h o d %
4729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4731 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4732 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4733 % access that is outside the boundaries of the image cache.
4735 % The format of the SetPixelCacheVirtualMethod() method is:
4737 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4738 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4740 % A description of each parameter follows:
4742 % o image: the image.
4744 % o virtual_pixel_method: choose the type of virtual pixel.
4746 % o exception: return any errors or warnings in this structure.
4750 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4751 ExceptionInfo *exception)
4765 assert(image != (Image *) NULL);
4766 assert(image->signature == MagickSignature);
4767 if (image->debug != MagickFalse)
4768 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4769 assert(image->cache != (Cache) NULL);
4770 cache_info=(CacheInfo *) image->cache;
4771 assert(cache_info->signature == MagickSignature);
4772 image->alpha_trait=BlendPixelTrait;
4774 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4775 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4776 #pragma omp parallel for schedule(static,4) shared(status) \
4777 magick_threads(image,image,1,1)
4779 for (y=0; y < (ssize_t) image->rows; y++)
4787 if (status == MagickFalse)
4789 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4790 if (q == (Quantum *) NULL)
4795 for (x=0; x < (ssize_t) image->columns; x++)
4797 SetPixelAlpha(image,alpha,q);
4798 q+=GetPixelChannels(image);
4800 status=SyncCacheViewAuthenticPixels(image_view,exception);
4802 image_view=DestroyCacheView(image_view);
4806 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4807 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4815 assert(image != (Image *) NULL);
4816 assert(image->signature == MagickSignature);
4817 if (image->debug != MagickFalse)
4818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4819 assert(image->cache != (Cache) NULL);
4820 cache_info=(CacheInfo *) image->cache;
4821 assert(cache_info->signature == MagickSignature);
4822 method=cache_info->virtual_pixel_method;
4823 cache_info->virtual_pixel_method=virtual_pixel_method;
4824 if ((image->columns != 0) && (image->rows != 0))
4825 switch (virtual_pixel_method)
4827 case BackgroundVirtualPixelMethod:
4829 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4830 (image->alpha_trait != BlendPixelTrait))
4831 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4832 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4833 (IsGrayColorspace(image->colorspace) != MagickFalse))
4834 (void) TransformImageColorspace(image,sRGBColorspace,exception);
4837 case TransparentVirtualPixelMethod:
4839 if (image->alpha_trait != BlendPixelTrait)
4840 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4854 + S y n c A u t h e n t i c P i x e l C a c h e N e x u s %
4858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4860 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4861 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4862 % is synced, otherwise MagickFalse.
4864 % The format of the SyncAuthenticPixelCacheNexus() method is:
4866 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4867 % NexusInfo *nexus_info,ExceptionInfo *exception)
4869 % A description of each parameter follows:
4871 % o image: the image.
4873 % o nexus_info: the cache nexus to sync.
4875 % o exception: return any errors or warnings in this structure.
4878 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4879 NexusInfo *nexus_info,ExceptionInfo *exception)
4888 Transfer pixels to the cache.
4890 assert(image != (Image *) NULL);
4891 assert(image->signature == MagickSignature);
4892 if (image->cache == (Cache) NULL)
4893 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4894 cache_info=(CacheInfo *) image->cache;
4895 assert(cache_info->signature == MagickSignature);
4896 if (cache_info->type == UndefinedCache)
4897 return(MagickFalse);
4898 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4900 assert(cache_info->signature == MagickSignature);
4901 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4902 if ((cache_info->metacontent_extent != 0) &&
4903 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4904 return(MagickFalse);
4909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4913 + S y n c A u t h e n t i c P i x e l C a c h e %
4917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4919 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4920 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4921 % otherwise MagickFalse.
4923 % The format of the SyncAuthenticPixelsCache() method is:
4925 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4926 % ExceptionInfo *exception)
4928 % A description of each parameter follows:
4930 % o image: the image.
4932 % o exception: return any errors or warnings in this structure.
4935 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4936 ExceptionInfo *exception)
4942 id = GetOpenMPThreadId();
4947 assert(image != (Image *) NULL);
4948 assert(image->signature == MagickSignature);
4949 assert(image->cache != (Cache) NULL);
4950 cache_info=(CacheInfo *) image->cache;
4951 assert(cache_info->signature == MagickSignature);
4952 assert(id < (int) cache_info->number_threads);
4953 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4963 % S y n c A u t h e n t i c P i x e l s %
4967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4969 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4970 % The method returns MagickTrue if the pixel region is flushed, otherwise
4973 % The format of the SyncAuthenticPixels() method is:
4975 % MagickBooleanType SyncAuthenticPixels(Image *image,
4976 % ExceptionInfo *exception)
4978 % A description of each parameter follows:
4980 % o image: the image.
4982 % o exception: return any errors or warnings in this structure.
4985 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4986 ExceptionInfo *exception)
4992 id = GetOpenMPThreadId();
4997 assert(image != (Image *) NULL);
4998 assert(image->signature == MagickSignature);
4999 assert(image->cache != (Cache) NULL);
5000 cache_info=(CacheInfo *) image->cache;
5001 assert(cache_info->signature == MagickSignature);
5002 if (cache_info->methods.sync_authentic_pixels_handler !=
5003 (SyncAuthenticPixelsHandler) NULL)
5005 status=cache_info->methods.sync_authentic_pixels_handler(image,
5009 assert(id < (int) cache_info->number_threads);
5010 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5020 + S y n c I m a g e P i x e l C a c h e %
5024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5026 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5027 % The method returns MagickTrue if the pixel region is flushed, otherwise
5030 % The format of the SyncImagePixelCache() method is:
5032 % MagickBooleanType SyncImagePixelCache(Image *image,
5033 % ExceptionInfo *exception)
5035 % A description of each parameter follows:
5037 % o image: the image.
5039 % o exception: return any errors or warnings in this structure.
5042 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5043 ExceptionInfo *exception)
5048 assert(image != (Image *) NULL);
5049 assert(exception != (ExceptionInfo *) NULL);
5050 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5051 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5059 + W r i t e P i x e l C a c h e M e t a c o n t e n t %
5063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5065 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5066 % of the pixel cache.
5068 % The format of the WritePixelCacheMetacontent() method is:
5070 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5071 % NexusInfo *nexus_info,ExceptionInfo *exception)
5073 % A description of each parameter follows:
5075 % o cache_info: the pixel cache.
5077 % o nexus_info: the cache nexus to write the meta-content.
5079 % o exception: return any errors or warnings in this structure.
5082 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5083 NexusInfo *nexus_info,ExceptionInfo *exception)
5093 register const unsigned char
5102 if (cache_info->metacontent_extent == 0)
5103 return(MagickFalse);
5104 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5106 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5107 nexus_info->region.x;
5108 length=(MagickSizeType) nexus_info->region.width*
5109 cache_info->metacontent_extent;
5110 extent=(MagickSizeType) length*nexus_info->region.height;
5111 rows=nexus_info->region.height;
5113 p=(unsigned char *) nexus_info->metacontent;
5114 switch (cache_info->type)
5119 register unsigned char
5123 Write associated pixels to memory.
5125 if ((cache_info->columns == nexus_info->region.width) &&
5126 (extent == (MagickSizeType) ((size_t) extent)))
5131 q=(unsigned char *) cache_info->metacontent+offset*
5132 cache_info->metacontent_extent;
5133 for (y=0; y < (ssize_t) rows; y++)
5135 (void) memcpy(q,p,(size_t) length);
5136 p+=nexus_info->region.width*cache_info->metacontent_extent;
5137 q+=cache_info->columns*cache_info->metacontent_extent;
5144 Write associated pixels to disk.
5146 LockSemaphoreInfo(cache_info->file_semaphore);
5147 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5149 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5150 cache_info->cache_filename);
5151 UnlockSemaphoreInfo(cache_info->file_semaphore);
5152 return(MagickFalse);
5154 if ((cache_info->columns == nexus_info->region.width) &&
5155 (extent <= MagickMaxBufferExtent))
5160 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5161 for (y=0; y < (ssize_t) rows; y++)
5163 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5164 cache_info->number_channels*sizeof(Quantum)+offset*
5165 cache_info->metacontent_extent,length,(const unsigned char *) p);
5166 if (count != (MagickOffsetType) length)
5168 p+=cache_info->metacontent_extent*nexus_info->region.width;
5169 offset+=cache_info->columns;
5171 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5172 (void) ClosePixelCacheOnDisk(cache_info);
5173 UnlockSemaphoreInfo(cache_info->file_semaphore);
5176 case DistributedCache:
5182 Write metacontent to distributed cache.
5184 LockSemaphoreInfo(cache_info->file_semaphore);
5185 region=nexus_info->region;
5186 if ((cache_info->columns != nexus_info->region.width) ||
5187 (extent > MagickMaxBufferExtent))
5194 for (y=0; y < (ssize_t) rows; y++)
5196 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5197 cache_info->server_info,®ion,length,(const unsigned char *) p);
5198 if (count != (MagickOffsetType) length)
5200 p+=cache_info->metacontent_extent*nexus_info->region.width;
5203 UnlockSemaphoreInfo(cache_info->file_semaphore);
5209 if (y < (ssize_t) rows)
5211 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5212 cache_info->cache_filename);
5213 return(MagickFalse);
5215 if ((cache_info->debug != MagickFalse) &&
5216 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5218 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5219 nexus_info->region.width,(double) nexus_info->region.height,(double)
5220 nexus_info->region.x,(double) nexus_info->region.y);
5225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5229 + W r i t e C a c h e P i x e l s %
5233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5235 % WritePixelCachePixels() writes image pixels to the specified region of the
5238 % The format of the WritePixelCachePixels() method is:
5240 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5241 % NexusInfo *nexus_info,ExceptionInfo *exception)
5243 % A description of each parameter follows:
5245 % o cache_info: the pixel cache.
5247 % o nexus_info: the cache nexus to write the pixels.
5249 % o exception: return any errors or warnings in this structure.
5252 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5253 NexusInfo *nexus_info,ExceptionInfo *exception)
5263 register const Quantum
5272 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5274 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5275 nexus_info->region.x;
5276 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5278 extent=length*nexus_info->region.height;
5279 rows=nexus_info->region.height;
5281 p=nexus_info->pixels;
5282 switch (cache_info->type)
5291 Write pixels to memory.
5293 if ((cache_info->columns == nexus_info->region.width) &&
5294 (extent == (MagickSizeType) ((size_t) extent)))
5299 q=cache_info->pixels+offset*cache_info->number_channels;
5300 for (y=0; y < (ssize_t) rows; y++)
5302 (void) memcpy(q,p,(size_t) length);
5303 p+=cache_info->number_channels*nexus_info->region.width;
5304 q+=cache_info->columns*cache_info->number_channels;
5311 Write pixels to disk.
5313 LockSemaphoreInfo(cache_info->file_semaphore);
5314 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5316 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5317 cache_info->cache_filename);
5318 UnlockSemaphoreInfo(cache_info->file_semaphore);
5319 return(MagickFalse);
5321 if ((cache_info->columns == nexus_info->region.width) &&
5322 (extent <= MagickMaxBufferExtent))
5327 for (y=0; y < (ssize_t) rows; y++)
5329 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5330 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5332 if (count != (MagickOffsetType) length)
5334 p+=cache_info->number_channels*nexus_info->region.width;
5335 offset+=cache_info->columns;
5337 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5338 (void) ClosePixelCacheOnDisk(cache_info);
5339 UnlockSemaphoreInfo(cache_info->file_semaphore);
5342 case DistributedCache:
5348 Write pixels to distributed cache.
5350 LockSemaphoreInfo(cache_info->file_semaphore);
5351 region=nexus_info->region;
5352 if ((cache_info->columns != nexus_info->region.width) ||
5353 (extent > MagickMaxBufferExtent))
5360 for (y=0; y < (ssize_t) rows; y++)
5362 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5363 cache_info->server_info,®ion,length,(const unsigned char *) p);
5364 if (count != (MagickOffsetType) length)
5366 p+=cache_info->number_channels*nexus_info->region.width;
5369 UnlockSemaphoreInfo(cache_info->file_semaphore);
5375 if (y < (ssize_t) rows)
5377 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5378 cache_info->cache_filename);
5379 return(MagickFalse);
5381 if ((cache_info->debug != MagickFalse) &&
5382 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5383 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5384 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5385 nexus_info->region.width,(double) nexus_info->region.height,(double)
5386 nexus_info->region.x,(double) nexus_info->region.y);