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-2014 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
100 #if defined(__cplusplus) || defined(c_plusplus)
105 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
109 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
110 const ssize_t,const size_t,const size_t,ExceptionInfo *),
111 *GetVirtualPixelsCache(const Image *);
114 *GetVirtualMetacontentFromCache(const Image *);
116 static MagickBooleanType
117 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
120 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
122 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
123 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
124 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
125 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
129 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
130 const size_t,ExceptionInfo *),
131 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
132 const size_t,ExceptionInfo *),
133 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
134 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
136 #if defined(__cplusplus) || defined(c_plusplus)
143 static volatile MagickBooleanType
144 instantiate_cache = MagickFalse;
147 *cache_semaphore = (SemaphoreInfo *) NULL;
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 + A c q u i r e P i x e l C a c h e %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % AcquirePixelCache() acquires a pixel cache.
162 % The format of the AcquirePixelCache() method is:
164 % Cache AcquirePixelCache(const size_t number_threads)
166 % A description of each parameter follows:
168 % o number_threads: the number of nexus threads.
171 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
174 *restrict cache_info;
179 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
180 if (cache_info == (CacheInfo *) NULL)
181 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
182 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
183 cache_info->type=UndefinedCache;
184 cache_info->mode=IOMode;
185 cache_info->colorspace=sRGBColorspace;
186 cache_info->file=(-1);
187 cache_info->id=GetMagickThreadId();
188 cache_info->number_threads=number_threads;
189 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
190 cache_info->number_threads=GetOpenMPMaximumThreads();
191 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
192 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
193 if (cache_info->number_threads == 0)
194 cache_info->number_threads=1;
195 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
196 if (cache_info->nexus_info == (NexusInfo **) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
199 if (synchronize != (const char *) NULL)
201 cache_info->synchronize=IsStringTrue(synchronize);
202 synchronize=DestroyString(synchronize);
204 cache_info->semaphore=AllocateSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->file_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 return((Cache ) cache_info);
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % A c q u i r e P i x e l C a c h e N e x u s %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
225 % The format of the AcquirePixelCacheNexus method is:
227 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
229 % A description of each parameter follows:
231 % o number_threads: the number of nexus threads.
234 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
237 **restrict nexus_info;
242 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
243 number_threads,sizeof(*nexus_info)));
244 if (nexus_info == (NexusInfo **) NULL)
245 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
246 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
247 sizeof(**nexus_info));
248 if (nexus_info[0] == (NexusInfo *) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
251 for (i=0; i < (ssize_t) number_threads; i++)
253 nexus_info[i]=(&nexus_info[0][i]);
254 nexus_info[i]->signature=MagickSignature;
260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264 + A c q u i r e P i x e l C a c h e P i x e l s %
268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 % AcquirePixelCachePixels() returns the pixels associated with the specified
273 % The format of the AcquirePixelCachePixels() method is:
275 % const void *AcquirePixelCachePixels(const Image *image,
276 % MagickSizeType *length,ExceptionInfo *exception)
278 % A description of each parameter follows:
280 % o image: the image.
282 % o length: the pixel cache length.
284 % o exception: return any errors or warnings in this structure.
287 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
288 MagickSizeType *length,ExceptionInfo *exception)
291 *restrict cache_info;
293 assert(image != (const Image *) NULL);
294 assert(image->signature == MagickSignature);
295 assert(exception != (ExceptionInfo *) NULL);
296 assert(exception->signature == MagickSignature);
297 assert(image->cache != (Cache) NULL);
298 cache_info=(CacheInfo *) image->cache;
299 assert(cache_info->signature == MagickSignature);
301 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
302 return((const void *) NULL);
303 *length=cache_info->length;
304 return((const void *) cache_info->pixels);
308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 + C a c h e C o m p o n e n t G e n e s i s %
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 % CacheComponentGenesis() instantiates the cache component.
320 % The format of the CacheComponentGenesis method is:
322 % MagickBooleanType CacheComponentGenesis(void)
325 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
327 AcquireSemaphoreInfo(&cache_semaphore);
332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 + C a c h e C o m p o n e n t T e r m i n u s %
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 % CacheComponentTerminus() destroys the cache component.
344 % The format of the CacheComponentTerminus() method is:
346 % CacheComponentTerminus(void)
349 MagickPrivate void CacheComponentTerminus(void)
351 if (cache_semaphore == (SemaphoreInfo *) NULL)
352 AcquireSemaphoreInfo(&cache_semaphore);
353 LockSemaphoreInfo(cache_semaphore);
354 instantiate_cache=MagickFalse;
355 UnlockSemaphoreInfo(cache_semaphore);
356 DestroySemaphoreInfo(&cache_semaphore);
360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 + C l o n e P i x e l C a c h e %
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 % ClonePixelCache() clones a pixel cache.
372 % The format of the ClonePixelCache() method is:
374 % Cache ClonePixelCache(const Cache cache)
376 % A description of each parameter follows:
378 % o cache: the pixel cache.
381 MagickPrivate Cache ClonePixelCache(const Cache cache)
384 *restrict clone_info;
387 *restrict cache_info;
389 assert(cache != NULL);
390 cache_info=(const CacheInfo *) cache;
391 assert(cache_info->signature == MagickSignature);
392 if (cache_info->debug != MagickFalse)
393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
394 cache_info->filename);
395 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
396 if (clone_info == (Cache) NULL)
397 return((Cache) NULL);
398 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
399 return((Cache ) clone_info);
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 + C l o n e P i x e l C a c h e M e t h o d s %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
416 % The format of the ClonePixelCacheMethods() method is:
418 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
420 % A description of each parameter follows:
422 % o clone: Specifies a pointer to a Cache structure.
424 % o cache: the pixel cache.
427 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
430 *restrict cache_info,
431 *restrict source_info;
433 assert(clone != (Cache) NULL);
434 source_info=(CacheInfo *) clone;
435 assert(source_info->signature == MagickSignature);
436 if (source_info->debug != MagickFalse)
437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
438 source_info->filename);
439 assert(cache != (Cache) NULL);
440 cache_info=(CacheInfo *) cache;
441 assert(cache_info->signature == MagickSignature);
442 source_info->methods=cache_info->methods;
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450 + 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 %
454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
455 % ClonePixelCacheRepository() clones the source pixel cache to the destination
458 % The format of the ClonePixelCacheRepository() method is:
460 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
461 % CacheInfo *source_info,ExceptionInfo *exception)
463 % A description of each parameter follows:
465 % o cache_info: the pixel cache.
467 % o source_info: the source pixel cache.
469 % o exception: return any errors or warnings in this structure.
473 static inline void CopyPixels(Quantum *destination,const Quantum *source,
474 const MagickSizeType number_pixels)
476 #if !defined(MAGICKCORE_OPENMP_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH <= 8)
477 (void) memcpy(destination,source,(size_t) number_pixels*sizeof(*source));
480 register MagickOffsetType
483 if ((number_pixels*sizeof(*source)) < MagickMaxBufferExtent)
485 (void) memcpy(destination,source,(size_t) number_pixels*
489 #pragma omp parallel for
490 for (i=0; i < (MagickOffsetType) number_pixels; i++)
491 destination[i]=source[i];
496 static inline MagickSizeType MagickMin(const MagickSizeType x,
497 const MagickSizeType y)
504 static MagickBooleanType ClonePixelCacheRepository(
505 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
506 ExceptionInfo *exception)
508 #define MaxCacheThreads 2
509 #define cache_threads(source,destination,chunk) \
510 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
511 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
512 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
519 **restrict cache_nexus,
520 **restrict clone_nexus;
528 assert(cache_info != (CacheInfo *) NULL);
529 assert(clone_info != (CacheInfo *) NULL);
530 assert(exception != (ExceptionInfo *) NULL);
531 if (cache_info->type == PingCache)
533 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
534 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
535 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
536 (cache_info->columns == clone_info->columns) &&
537 (cache_info->rows == clone_info->rows) &&
538 (cache_info->number_channels == clone_info->number_channels) &&
539 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
540 (cache_info->metacontent_extent == clone_info->metacontent_extent))
542 CopyPixels(clone_info->pixels,cache_info->pixels,cache_info->columns*
543 cache_info->number_channels*cache_info->rows);
544 if (cache_info->metacontent_extent != 0)
545 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
546 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
547 sizeof(cache_info->metacontent));
551 Mismatched pixel cache morphology.
553 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
554 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
555 if ((cache_nexus == (NexusInfo **) NULL) ||
556 (clone_nexus == (NexusInfo **) NULL))
557 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
558 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
559 optimize=(cache_info->number_channels == clone_info->number_channels) &&
560 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
561 MagickTrue : MagickFalse;
562 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
563 clone_info->columns*clone_info->number_channels);
565 #if defined(MAGICKCORE_OPENMP_SUPPORT)
566 #pragma omp parallel for schedule(static,4) shared(status) \
567 cache_threads(cache_info,clone_info,cache_info->rows)
569 for (y=0; y < (ssize_t) cache_info->rows; y++)
572 id = GetOpenMPThreadId();
583 if (status == MagickFalse)
585 if (y >= (ssize_t) clone_info->rows)
587 region.width=cache_info->columns;
591 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
593 if (pixels == (Quantum *) NULL)
595 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
596 if (status == MagickFalse)
598 region.width=clone_info->columns;
599 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
600 clone_nexus[id],exception);
601 if (pixels == (Quantum *) NULL)
603 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,clone_nexus[id]->length);
604 if (optimize != MagickFalse)
605 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
609 register const Quantum
616 Mismatched pixel channel map.
618 p=cache_nexus[id]->pixels;
619 q=clone_nexus[id]->pixels;
620 for (x=0; x < (ssize_t) cache_info->columns; x++)
625 if (x == (ssize_t) clone_info->columns)
627 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
635 channel=clone_info->channel_map[i].channel;
636 traits=cache_info->channel_map[channel].traits;
637 if (traits != UndefinedPixelTrait)
638 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
642 p+=cache_info->number_channels;
645 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
647 if ((cache_info->metacontent_extent != 0) &&
648 (clone_info->metacontent_extent != 0))
653 length=(size_t) MagickMin(cache_info->metacontent_extent,
654 clone_info->metacontent_extent);
655 #if defined(MAGICKCORE_OPENMP_SUPPORT)
656 #pragma omp parallel for schedule(static,4) shared(status) \
657 cache_threads(cache_info,clone_info,cache_info->rows)
659 for (y=0; y < (ssize_t) cache_info->rows; y++)
662 id = GetOpenMPThreadId();
670 if (status == MagickFalse)
672 if (y >= (ssize_t) clone_info->rows)
674 region.width=cache_info->columns;
678 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
679 cache_nexus[id],exception);
680 if (pixels == (Quantum *) NULL)
682 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
683 if (status == MagickFalse)
685 region.width=clone_info->columns;
686 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
687 clone_nexus[id],exception);
688 if (pixels == (Quantum *) NULL)
690 if (clone_nexus[id]->metacontent != (void *) NULL)
691 (void) memcpy(clone_nexus[id]->metacontent,
692 cache_nexus[id]->metacontent,length*
693 sizeof(cache_nexus[id]->metacontent));
694 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
697 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
698 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
699 if (cache_info->debug != MagickFalse)
702 message[MaxTextExtent];
704 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
705 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
706 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 + D e s t r o y I m a g e P i x e l C a c h e %
721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
725 % The format of the DestroyImagePixelCache() method is:
727 % void DestroyImagePixelCache(Image *image)
729 % A description of each parameter follows:
731 % o image: the image.
734 static void DestroyImagePixelCache(Image *image)
736 assert(image != (Image *) NULL);
737 assert(image->signature == MagickSignature);
738 if (image->debug != MagickFalse)
739 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
740 if (image->cache == (void *) NULL)
742 image->cache=DestroyPixelCache(image->cache);
746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750 + D e s t r o y I m a g e P i x e l s %
754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 % DestroyImagePixels() deallocates memory associated with the pixel cache.
758 % The format of the DestroyImagePixels() method is:
760 % void DestroyImagePixels(Image *image)
762 % A description of each parameter follows:
764 % o image: the image.
767 MagickExport void DestroyImagePixels(Image *image)
770 *restrict cache_info;
772 assert(image != (const Image *) NULL);
773 assert(image->signature == MagickSignature);
774 if (image->debug != MagickFalse)
775 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
776 assert(image->cache != (Cache) NULL);
777 cache_info=(CacheInfo *) image->cache;
778 assert(cache_info->signature == MagickSignature);
779 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
781 cache_info->methods.destroy_pixel_handler(image);
784 image->cache=DestroyPixelCache(image->cache);
788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792 + D e s t r o y P i x e l C a c h e %
796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798 % DestroyPixelCache() deallocates memory associated with the pixel cache.
800 % The format of the DestroyPixelCache() method is:
802 % Cache DestroyPixelCache(Cache cache)
804 % A description of each parameter follows:
806 % o cache: the pixel cache.
810 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
816 if (cache_info->file != -1)
818 status=close(cache_info->file);
819 cache_info->file=(-1);
820 RelinquishMagickResource(FileResource,1);
822 return(status == -1 ? MagickFalse : MagickTrue);
825 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
827 switch (cache_info->type)
831 if (cache_info->mapped == MagickFalse)
832 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
836 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
837 cache_info->pixels=(Quantum *) NULL;
839 RelinquishMagickResource(MemoryResource,cache_info->length);
844 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
845 cache_info->pixels=(Quantum *) NULL;
846 if (cache_info->mode != ReadMode)
847 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
848 *cache_info->cache_filename='\0';
849 RelinquishMagickResource(MapResource,cache_info->length);
853 if (cache_info->file != -1)
854 (void) ClosePixelCacheOnDisk(cache_info);
855 if (cache_info->mode != ReadMode)
856 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
857 *cache_info->cache_filename='\0';
858 RelinquishMagickResource(DiskResource,cache_info->length);
861 case DistributedCache:
863 *cache_info->cache_filename='\0';
864 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
865 cache_info->server_info);
871 cache_info->type=UndefinedCache;
872 cache_info->mapped=MagickFalse;
873 cache_info->metacontent=(void *) NULL;
876 MagickPrivate Cache DestroyPixelCache(Cache cache)
879 *restrict cache_info;
881 assert(cache != (Cache) NULL);
882 cache_info=(CacheInfo *) cache;
883 assert(cache_info->signature == MagickSignature);
884 if (cache_info->debug != MagickFalse)
885 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
886 cache_info->filename);
887 LockSemaphoreInfo(cache_info->semaphore);
888 cache_info->reference_count--;
889 if (cache_info->reference_count != 0)
891 UnlockSemaphoreInfo(cache_info->semaphore);
892 return((Cache) NULL);
894 UnlockSemaphoreInfo(cache_info->semaphore);
895 if (cache_info->debug != MagickFalse)
898 message[MaxTextExtent];
900 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
901 cache_info->filename);
902 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
904 RelinquishPixelCachePixels(cache_info);
905 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
906 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
907 cache_info->server_info);
908 if (cache_info->nexus_info != (NexusInfo **) NULL)
909 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
910 cache_info->number_threads);
911 if (cache_info->random_info != (RandomInfo *) NULL)
912 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
913 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
914 DestroySemaphoreInfo(&cache_info->file_semaphore);
915 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
916 DestroySemaphoreInfo(&cache_info->semaphore);
917 cache_info->signature=(~MagickSignature);
918 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
924 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928 + D e s t r o y P i x e l C a c h e N e x u s %
932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
934 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
936 % The format of the DestroyPixelCacheNexus() method is:
938 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
939 % const size_t number_threads)
941 % A description of each parameter follows:
943 % o nexus_info: the nexus to destroy.
945 % o number_threads: the number of nexus threads.
949 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
951 if (nexus_info->mapped == MagickFalse)
952 (void) RelinquishAlignedMemory(nexus_info->cache);
954 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
955 nexus_info->cache=(Quantum *) NULL;
956 nexus_info->pixels=(Quantum *) NULL;
957 nexus_info->metacontent=(void *) NULL;
958 nexus_info->length=0;
959 nexus_info->mapped=MagickFalse;
962 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
963 const size_t number_threads)
968 assert(nexus_info != (NexusInfo **) NULL);
969 for (i=0; i < (ssize_t) number_threads; i++)
971 if (nexus_info[i]->cache != (Quantum *) NULL)
972 RelinquishCacheNexusPixels(nexus_info[i]);
973 nexus_info[i]->signature=(~MagickSignature);
975 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
976 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
985 % G e t A u t h e n t i c M e t a c o n t e n t %
989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
991 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
992 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
993 % returned if the associated pixels are not available.
995 % The format of the GetAuthenticMetacontent() method is:
997 % void *GetAuthenticMetacontent(const Image *image)
999 % A description of each parameter follows:
1001 % o image: the image.
1004 MagickExport void *GetAuthenticMetacontent(const Image *image)
1007 *restrict cache_info;
1010 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)
1023 metacontent=cache_info->methods.
1024 get_authentic_metacontent_from_handler(image);
1025 return(metacontent);
1027 assert(id < (int) cache_info->number_threads);
1028 return(cache_info->nexus_info[id]->metacontent);
1032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036 + 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 %
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1043 % with the last call to QueueAuthenticPixelsCache() or
1044 % GetAuthenticPixelsCache().
1046 % The format of the GetAuthenticMetacontentFromCache() method is:
1048 % void *GetAuthenticMetacontentFromCache(const Image *image)
1050 % A description of each parameter follows:
1052 % o image: the image.
1055 static void *GetAuthenticMetacontentFromCache(const Image *image)
1058 *restrict cache_info;
1061 id = GetOpenMPThreadId();
1063 assert(image != (const Image *) NULL);
1064 assert(image->signature == MagickSignature);
1065 assert(image->cache != (Cache) NULL);
1066 cache_info=(CacheInfo *) image->cache;
1067 assert(cache_info->signature == MagickSignature);
1068 assert(id < (int) cache_info->number_threads);
1069 return(cache_info->nexus_info[id]->metacontent);
1073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1077 + 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 %
1081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1084 % disk pixel cache as defined by the geometry parameters. A pointer to the
1085 % pixels is returned if the pixels are transferred, otherwise a NULL is
1088 % The format of the GetAuthenticPixelCacheNexus() method is:
1090 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1091 % const ssize_t y,const size_t columns,const size_t rows,
1092 % NexusInfo *nexus_info,ExceptionInfo *exception)
1094 % A description of each parameter follows:
1096 % o image: the image.
1098 % o x,y,columns,rows: These values define the perimeter of a region of
1101 % o nexus_info: the cache nexus to return.
1103 % o exception: return any errors or warnings in this structure.
1107 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1108 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1109 ExceptionInfo *exception)
1112 *restrict cache_info;
1118 Transfer pixels from the cache.
1120 assert(image != (Image *) NULL);
1121 assert(image->signature == MagickSignature);
1122 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1123 nexus_info,exception);
1124 if (pixels == (Quantum *) NULL)
1125 return((Quantum *) NULL);
1126 cache_info=(CacheInfo *) image->cache;
1127 assert(cache_info->signature == MagickSignature);
1128 if (nexus_info->authentic_pixel_cache != MagickFalse)
1130 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1131 return((Quantum *) NULL);
1132 if (cache_info->metacontent_extent != 0)
1133 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1134 return((Quantum *) NULL);
1139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1143 + 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 %
1147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1150 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1152 % The format of the GetAuthenticPixelsFromCache() method is:
1154 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1156 % A description of each parameter follows:
1158 % o image: the image.
1161 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1164 *restrict cache_info;
1167 id = GetOpenMPThreadId();
1169 assert(image != (const Image *) NULL);
1170 assert(image->signature == MagickSignature);
1171 assert(image->cache != (Cache) NULL);
1172 cache_info=(CacheInfo *) image->cache;
1173 assert(cache_info->signature == MagickSignature);
1174 assert(id < (int) cache_info->number_threads);
1175 return(cache_info->nexus_info[id]->pixels);
1179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1183 % G e t A u t h e n t i c P i x e l Q u e u e %
1187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189 % GetAuthenticPixelQueue() returns the authentic pixels associated
1190 % corresponding with the last call to QueueAuthenticPixels() or
1191 % GetAuthenticPixels().
1193 % The format of the GetAuthenticPixelQueue() method is:
1195 % Quantum *GetAuthenticPixelQueue(const Image image)
1197 % A description of each parameter follows:
1199 % o image: the image.
1202 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1205 *restrict cache_info;
1208 id = GetOpenMPThreadId();
1210 assert(image != (const Image *) NULL);
1211 assert(image->signature == MagickSignature);
1212 assert(image->cache != (Cache) NULL);
1213 cache_info=(CacheInfo *) image->cache;
1214 assert(cache_info->signature == MagickSignature);
1215 if (cache_info->methods.get_authentic_pixels_from_handler !=
1216 (GetAuthenticPixelsFromHandler) NULL)
1217 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1218 assert(id < (int) cache_info->number_threads);
1219 return(cache_info->nexus_info[id]->pixels);
1223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1227 % G e t A u t h e n t i c P i x e l s %
1230 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1232 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1233 % region is successfully accessed, a pointer to a Quantum array
1234 % representing the region is returned, otherwise NULL is returned.
1236 % The returned pointer may point to a temporary working copy of the pixels
1237 % or it may point to the original pixels in memory. Performance is maximized
1238 % if the selected region is part of one row, or one or more full rows, since
1239 % then there is opportunity to access the pixels in-place (without a copy)
1240 % if the image is in memory, or in a memory-mapped file. The returned pointer
1241 % must *never* be deallocated by the user.
1243 % Pixels accessed via the returned pointer represent a simple array of type
1244 % Quantum. If the image has corresponding metacontent,call
1245 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1246 % meta-content corresponding to the region. Once the Quantum array has
1247 % been updated, the changes must be saved back to the underlying image using
1248 % SyncAuthenticPixels() or they may be lost.
1250 % The format of the GetAuthenticPixels() method is:
1252 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1253 % const ssize_t y,const size_t columns,const size_t rows,
1254 % ExceptionInfo *exception)
1256 % A description of each parameter follows:
1258 % o image: the image.
1260 % o x,y,columns,rows: These values define the perimeter of a region of
1263 % o exception: return any errors or warnings in this structure.
1266 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1267 const ssize_t y,const size_t columns,const size_t rows,
1268 ExceptionInfo *exception)
1271 *restrict cache_info;
1274 id = GetOpenMPThreadId();
1279 assert(image != (Image *) NULL);
1280 assert(image->signature == MagickSignature);
1281 assert(image->cache != (Cache) NULL);
1282 cache_info=(CacheInfo *) image->cache;
1283 assert(cache_info->signature == MagickSignature);
1284 if (cache_info->methods.get_authentic_pixels_handler !=
1285 (GetAuthenticPixelsHandler) NULL)
1287 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1291 assert(id < (int) cache_info->number_threads);
1292 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1293 cache_info->nexus_info[id],exception);
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 + G e t A u t h e n t i c P i x e l s C a c h e %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1309 % as defined by the geometry parameters. A pointer to the pixels is returned
1310 % if the pixels are transferred, otherwise a NULL is returned.
1312 % The format of the GetAuthenticPixelsCache() method is:
1314 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1315 % const ssize_t y,const size_t columns,const size_t rows,
1316 % ExceptionInfo *exception)
1318 % A description of each parameter follows:
1320 % o image: the image.
1322 % o x,y,columns,rows: These values define the perimeter of a region of
1325 % o exception: return any errors or warnings in this structure.
1328 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1329 const ssize_t y,const size_t columns,const size_t rows,
1330 ExceptionInfo *exception)
1333 *restrict cache_info;
1336 id = GetOpenMPThreadId();
1341 assert(image != (const Image *) NULL);
1342 assert(image->signature == MagickSignature);
1343 assert(image->cache != (Cache) NULL);
1344 cache_info=(CacheInfo *) image->cache;
1345 if (cache_info == (Cache) NULL)
1346 return((Quantum *) NULL);
1347 assert(cache_info->signature == MagickSignature);
1348 assert(id < (int) cache_info->number_threads);
1349 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1350 cache_info->nexus_info[id],exception);
1355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 + G e t I m a g e E x t e n t %
1363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365 % GetImageExtent() returns the extent of the pixels associated corresponding
1366 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1368 % The format of the GetImageExtent() method is:
1370 % MagickSizeType GetImageExtent(const Image *image)
1372 % A description of each parameter follows:
1374 % o image: the image.
1377 MagickExport MagickSizeType GetImageExtent(const Image *image)
1380 *restrict cache_info;
1383 id = GetOpenMPThreadId();
1385 assert(image != (Image *) NULL);
1386 assert(image->signature == MagickSignature);
1387 if (image->debug != MagickFalse)
1388 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1389 assert(image->cache != (Cache) NULL);
1390 cache_info=(CacheInfo *) image->cache;
1391 assert(cache_info->signature == MagickSignature);
1392 assert(id < (int) cache_info->number_threads);
1393 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401 + G e t I m a g e P i x e l C a c h e %
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407 % GetImagePixelCache() ensures that there is only a single reference to the
1408 % pixel cache to be modified, updating the provided cache pointer to point to
1409 % a clone of the original pixel cache if necessary.
1411 % The format of the GetImagePixelCache method is:
1413 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1414 % ExceptionInfo *exception)
1416 % A description of each parameter follows:
1418 % o image: the image.
1420 % o clone: any value other than MagickFalse clones the cache pixels.
1422 % o exception: return any errors or warnings in this structure.
1426 static inline MagickBooleanType ValidatePixelCacheMorphology(
1427 const Image *restrict image)
1430 *restrict cache_info;
1432 const PixelChannelMap
1437 Does the image match the pixel cache morphology?
1439 cache_info=(CacheInfo *) image->cache;
1440 p=image->channel_map;
1441 q=cache_info->channel_map;
1442 if ((image->storage_class != cache_info->storage_class) ||
1443 (image->colorspace != cache_info->colorspace) ||
1444 (image->alpha_trait != cache_info->alpha_trait) ||
1445 (image->read_mask != cache_info->read_mask) ||
1446 (image->write_mask != cache_info->write_mask) ||
1447 (image->columns != cache_info->columns) ||
1448 (image->rows != cache_info->rows) ||
1449 (image->number_channels != cache_info->number_channels) ||
1450 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1451 (image->metacontent_extent != cache_info->metacontent_extent) ||
1452 (cache_info->nexus_info == (NexusInfo **) NULL))
1453 return(MagickFalse);
1457 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1458 ExceptionInfo *exception)
1461 *restrict cache_info;
1467 static MagickSizeType
1473 cache_timestamp = 0;
1476 LockSemaphoreInfo(image->semaphore);
1477 if (cpu_throttle == 0)
1478 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1479 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1480 MagickDelay(cpu_throttle);
1481 if (time_limit == 0)
1484 Set the expire time in seconds.
1486 time_limit=GetMagickResourceLimit(TimeResource);
1487 cache_timestamp=time((time_t *) NULL);
1489 if ((time_limit != MagickResourceInfinity) &&
1490 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1491 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1492 assert(image->cache != (Cache) NULL);
1493 cache_info=(CacheInfo *) image->cache;
1494 destroy=MagickFalse;
1495 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1497 LockSemaphoreInfo(cache_info->semaphore);
1498 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1509 clone_image=(*image);
1510 clone_image.semaphore=AllocateSemaphoreInfo();
1511 clone_image.reference_count=1;
1512 clone_image.cache=ClonePixelCache(cache_info);
1513 clone_info=(CacheInfo *) clone_image.cache;
1514 status=OpenPixelCache(&clone_image,IOMode,exception);
1515 if (status != MagickFalse)
1517 if (clone != MagickFalse)
1518 status=ClonePixelCacheRepository(clone_info,cache_info,
1520 if (status != MagickFalse)
1522 if (cache_info->reference_count == 1)
1523 cache_info->nexus_info=(NexusInfo **) NULL;
1525 image->cache=clone_image.cache;
1528 DestroySemaphoreInfo(&clone_image.semaphore);
1530 UnlockSemaphoreInfo(cache_info->semaphore);
1532 if (destroy != MagickFalse)
1533 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1534 if (status != MagickFalse)
1537 Ensure the image matches the pixel cache morphology.
1539 image->taint=MagickTrue;
1540 image->type=UndefinedType;
1541 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1543 status=OpenPixelCache(image,IOMode,exception);
1544 cache_info=(CacheInfo *) image->cache;
1545 if (cache_info->type == DiskCache)
1546 (void) ClosePixelCacheOnDisk(cache_info);
1549 UnlockSemaphoreInfo(image->semaphore);
1550 if (status == MagickFalse)
1551 return((Cache) NULL);
1552 return(image->cache);
1556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560 + G e t I m a g e P i x e l C a c h e T y p e %
1564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1567 % DiskCache, MemoryCache, MapCache, or PingCache.
1569 % The format of the GetImagePixelCacheType() method is:
1571 % CacheType GetImagePixelCacheType(const Image *image)
1573 % A description of each parameter follows:
1575 % o image: the image.
1578 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1581 *restrict cache_info;
1583 assert(image != (Image *) NULL);
1584 assert(image->signature == MagickSignature);
1585 assert(image->cache != (Cache) NULL);
1586 cache_info=(CacheInfo *) image->cache;
1587 assert(cache_info->signature == MagickSignature);
1588 return(cache_info->type);
1592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 % G e t O n e A u t h e n t i c P i x e l %
1600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1603 % location. The image background color is returned if an error occurs.
1605 % The format of the GetOneAuthenticPixel() method is:
1607 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1608 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1610 % A description of each parameter follows:
1612 % o image: the image.
1614 % o x,y: These values define the location of the pixel to return.
1616 % o pixel: return a pixel at the specified (x,y) location.
1618 % o exception: return any errors or warnings in this structure.
1621 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1622 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1625 *restrict cache_info;
1633 assert(image != (Image *) NULL);
1634 assert(image->signature == MagickSignature);
1635 assert(image->cache != (Cache) NULL);
1636 cache_info=(CacheInfo *) image->cache;
1637 assert(cache_info->signature == MagickSignature);
1638 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1639 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1640 (GetOneAuthenticPixelFromHandler) NULL)
1641 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1643 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1644 if (q == (Quantum *) NULL)
1646 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1647 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1648 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1649 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1650 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1651 return(MagickFalse);
1653 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1655 PixelChannel channel=GetPixelChannelChannel(image,i);
1656 pixel[channel]=q[i];
1662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1666 + 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 %
1670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1673 % location. The image background color is returned if an error occurs.
1675 % The format of the GetOneAuthenticPixelFromCache() method is:
1677 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1678 % const ssize_t x,const ssize_t y,Quantum *pixel,
1679 % ExceptionInfo *exception)
1681 % A description of each parameter follows:
1683 % o image: the image.
1685 % o x,y: These values define the location of the pixel to return.
1687 % o pixel: return a pixel at the specified (x,y) location.
1689 % o exception: return any errors or warnings in this structure.
1692 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1693 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1696 *restrict cache_info;
1699 id = GetOpenMPThreadId();
1707 assert(image != (const Image *) NULL);
1708 assert(image->signature == MagickSignature);
1709 assert(image->cache != (Cache) NULL);
1710 cache_info=(CacheInfo *) image->cache;
1711 assert(cache_info->signature == MagickSignature);
1712 assert(id < (int) cache_info->number_threads);
1713 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1714 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1716 if (q == (Quantum *) NULL)
1718 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1719 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1720 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1721 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1722 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1723 return(MagickFalse);
1725 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1727 PixelChannel channel=GetPixelChannelChannel(image,i);
1728 pixel[channel]=q[i];
1734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1738 % G e t O n e V i r t u a l P i x e l %
1742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1745 % (x,y) location. The image background color is returned if an error occurs.
1746 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1748 % The format of the GetOneVirtualPixel() method is:
1750 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1751 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1753 % A description of each parameter follows:
1755 % o image: the image.
1757 % o x,y: These values define the location of the pixel to return.
1759 % o pixel: return a pixel at the specified (x,y) location.
1761 % o exception: return any errors or warnings in this structure.
1764 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1765 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1768 *restrict cache_info;
1771 id = GetOpenMPThreadId();
1779 assert(image != (const Image *) NULL);
1780 assert(image->signature == MagickSignature);
1781 assert(image->cache != (Cache) NULL);
1782 cache_info=(CacheInfo *) image->cache;
1783 assert(cache_info->signature == MagickSignature);
1784 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1785 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1786 (GetOneVirtualPixelFromHandler) NULL)
1787 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1788 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1789 assert(id < (int) cache_info->number_threads);
1790 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1791 1UL,1UL,cache_info->nexus_info[id],exception);
1792 if (p == (const Quantum *) NULL)
1794 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1795 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1796 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1797 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1798 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1799 return(MagickFalse);
1801 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1803 PixelChannel channel=GetPixelChannelChannel(image,i);
1804 pixel[channel]=p[i];
1810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1814 + 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 %
1818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1820 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1821 % specified (x,y) location. The image background color is returned if an
1824 % The format of the GetOneVirtualPixelFromCache() method is:
1826 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1827 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1828 % Quantum *pixel,ExceptionInfo *exception)
1830 % A description of each parameter follows:
1832 % o image: the image.
1834 % o virtual_pixel_method: the virtual pixel method.
1836 % o x,y: These values define the location of the pixel to return.
1838 % o pixel: return a pixel at the specified (x,y) location.
1840 % o exception: return any errors or warnings in this structure.
1843 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1844 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1845 Quantum *pixel,ExceptionInfo *exception)
1848 *restrict cache_info;
1851 id = GetOpenMPThreadId();
1859 assert(image != (const Image *) NULL);
1860 assert(image->signature == MagickSignature);
1861 assert(image->cache != (Cache) NULL);
1862 cache_info=(CacheInfo *) image->cache;
1863 assert(cache_info->signature == MagickSignature);
1864 assert(id < (int) cache_info->number_threads);
1865 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1866 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1867 cache_info->nexus_info[id],exception);
1868 if (p == (const Quantum *) NULL)
1870 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1871 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1872 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1873 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1874 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1875 return(MagickFalse);
1877 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1879 PixelChannel channel=GetPixelChannelChannel(image,i);
1880 pixel[channel]=p[i];
1886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1890 % G e t O n e V i r t u a l P i x e l I n f o %
1894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1896 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1897 % location. The image background color is returned if an error occurs. If
1898 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1900 % The format of the GetOneVirtualPixelInfo() method is:
1902 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1903 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1904 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1906 % A description of each parameter follows:
1908 % o image: the image.
1910 % o virtual_pixel_method: the virtual pixel method.
1912 % o x,y: these values define the location of the pixel to return.
1914 % o pixel: return a pixel at the specified (x,y) location.
1916 % o exception: return any errors or warnings in this structure.
1919 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1920 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1921 PixelInfo *pixel,ExceptionInfo *exception)
1924 *restrict cache_info;
1927 id = GetOpenMPThreadId();
1929 register const Quantum
1932 assert(image != (const Image *) NULL);
1933 assert(image->signature == MagickSignature);
1934 assert(image->cache != (Cache) NULL);
1935 cache_info=(CacheInfo *) image->cache;
1936 assert(cache_info->signature == MagickSignature);
1937 assert(id < (int) cache_info->number_threads);
1938 GetPixelInfo(image,pixel);
1939 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1940 cache_info->nexus_info[id],exception);
1941 if (p == (const Quantum *) NULL)
1942 return(MagickFalse);
1943 GetPixelInfoPixel(image,p,pixel);
1948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1952 + G e t P i x e l C a c h e C o l o r s p a c e %
1956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1960 % The format of the GetPixelCacheColorspace() method is:
1962 % Colorspace GetPixelCacheColorspace(Cache cache)
1964 % A description of each parameter follows:
1966 % o cache: the pixel cache.
1969 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1972 *restrict cache_info;
1974 assert(cache != (Cache) NULL);
1975 cache_info=(CacheInfo *) cache;
1976 assert(cache_info->signature == MagickSignature);
1977 if (cache_info->debug != MagickFalse)
1978 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1979 cache_info->filename);
1980 return(cache_info->colorspace);
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988 + G e t P i x e l C a c h e M e t h o d s %
1992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1994 % GetPixelCacheMethods() initializes the CacheMethods structure.
1996 % The format of the GetPixelCacheMethods() method is:
1998 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2000 % A description of each parameter follows:
2002 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2005 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2007 assert(cache_methods != (CacheMethods *) NULL);
2008 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2009 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2010 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2011 cache_methods->get_virtual_metacontent_from_handler=
2012 GetVirtualMetacontentFromCache;
2013 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2014 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2015 cache_methods->get_authentic_metacontent_from_handler=
2016 GetAuthenticMetacontentFromCache;
2017 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2018 cache_methods->get_one_authentic_pixel_from_handler=
2019 GetOneAuthenticPixelFromCache;
2020 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2021 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2022 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2030 + G e t P i x e l C a c h e N e x u s E x t e n t %
2034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2036 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2037 % corresponding with the last call to SetPixelCacheNexusPixels() or
2038 % GetPixelCacheNexusPixels().
2040 % The format of the GetPixelCacheNexusExtent() method is:
2042 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2043 % NexusInfo *nexus_info)
2045 % A description of each parameter follows:
2047 % o nexus_info: the nexus info.
2050 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2051 NexusInfo *restrict nexus_info)
2054 *restrict cache_info;
2059 assert(cache != NULL);
2060 cache_info=(CacheInfo *) cache;
2061 assert(cache_info->signature == MagickSignature);
2062 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2064 return((MagickSizeType) cache_info->columns*cache_info->rows);
2069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2073 + G e t P i x e l C a c h e P i x e l s %
2077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2079 % GetPixelCachePixels() returns the pixels associated with the specified image.
2081 % The format of the GetPixelCachePixels() method is:
2083 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2084 % ExceptionInfo *exception)
2086 % A description of each parameter follows:
2088 % o image: the image.
2090 % o length: the pixel cache length.
2092 % o exception: return any errors or warnings in this structure.
2095 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2096 ExceptionInfo *exception)
2099 *restrict cache_info;
2101 assert(image != (const Image *) NULL);
2102 assert(image->signature == MagickSignature);
2103 assert(image->cache != (Cache) NULL);
2104 assert(length != (MagickSizeType *) NULL);
2105 assert(exception != (ExceptionInfo *) NULL);
2106 assert(exception->signature == MagickSignature);
2107 cache_info=(CacheInfo *) image->cache;
2108 assert(cache_info->signature == MagickSignature);
2110 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2111 return((void *) NULL);
2112 *length=cache_info->length;
2113 return((void *) cache_info->pixels);
2117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2121 + 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 %
2125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2127 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2129 % The format of the GetPixelCacheStorageClass() method is:
2131 % ClassType GetPixelCacheStorageClass(Cache cache)
2133 % A description of each parameter follows:
2135 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2137 % o cache: the pixel cache.
2140 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2143 *restrict cache_info;
2145 assert(cache != (Cache) NULL);
2146 cache_info=(CacheInfo *) cache;
2147 assert(cache_info->signature == MagickSignature);
2148 if (cache_info->debug != MagickFalse)
2149 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2150 cache_info->filename);
2151 return(cache_info->storage_class);
2155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2159 + G e t P i x e l C a c h e T i l e S i z e %
2163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2165 % GetPixelCacheTileSize() returns the pixel cache tile size.
2167 % The format of the GetPixelCacheTileSize() method is:
2169 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2172 % A description of each parameter follows:
2174 % o image: the image.
2176 % o width: the optimize cache tile width in pixels.
2178 % o height: the optimize cache tile height in pixels.
2181 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2185 *restrict cache_info;
2187 assert(image != (Image *) NULL);
2188 assert(image->signature == MagickSignature);
2189 if (image->debug != MagickFalse)
2190 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2191 cache_info=(CacheInfo *) image->cache;
2192 assert(cache_info->signature == MagickSignature);
2193 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2194 if (GetImagePixelCacheType(image) == DiskCache)
2195 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204 + 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 %
2208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2210 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2211 % pixel cache. A virtual pixel is any pixel access that is outside the
2212 % boundaries of the image cache.
2214 % The format of the GetPixelCacheVirtualMethod() method is:
2216 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2218 % A description of each parameter follows:
2220 % o image: the image.
2223 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2226 *restrict cache_info;
2228 assert(image != (Image *) NULL);
2229 assert(image->signature == MagickSignature);
2230 assert(image->cache != (Cache) NULL);
2231 cache_info=(CacheInfo *) image->cache;
2232 assert(cache_info->signature == MagickSignature);
2233 return(cache_info->virtual_pixel_method);
2237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2241 + 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 %
2245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2248 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2250 % The format of the GetVirtualMetacontentFromCache() method is:
2252 % void *GetVirtualMetacontentFromCache(const Image *image)
2254 % A description of each parameter follows:
2256 % o image: the image.
2259 static const void *GetVirtualMetacontentFromCache(const Image *image)
2262 *restrict cache_info;
2265 id = GetOpenMPThreadId();
2268 *restrict metacontent;
2270 assert(image != (const Image *) NULL);
2271 assert(image->signature == MagickSignature);
2272 assert(image->cache != (Cache) NULL);
2273 cache_info=(CacheInfo *) image->cache;
2274 assert(cache_info->signature == MagickSignature);
2275 assert(id < (int) cache_info->number_threads);
2276 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2277 cache_info->nexus_info[id]);
2278 return(metacontent);
2282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2286 + 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 %
2290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2292 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2295 % The format of the GetVirtualMetacontentFromNexus() method is:
2297 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2298 % NexusInfo *nexus_info)
2300 % A description of each parameter follows:
2302 % o cache: the pixel cache.
2304 % o nexus_info: the cache nexus to return the meta-content.
2307 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2308 NexusInfo *restrict nexus_info)
2311 *restrict cache_info;
2313 assert(cache != (Cache) NULL);
2314 cache_info=(CacheInfo *) cache;
2315 assert(cache_info->signature == MagickSignature);
2316 if (cache_info->storage_class == UndefinedClass)
2317 return((void *) NULL);
2318 return(nexus_info->metacontent);
2322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326 % G e t V i r t u a l M e t a c o n t e n t %
2330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2332 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2333 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2334 % returned if the meta-content are not available.
2336 % The format of the GetVirtualMetacontent() method is:
2338 % const void *GetVirtualMetacontent(const Image *image)
2340 % A description of each parameter follows:
2342 % o image: the image.
2345 MagickExport const void *GetVirtualMetacontent(const Image *image)
2348 *restrict cache_info;
2351 id = GetOpenMPThreadId();
2354 *restrict metacontent;
2356 assert(image != (const Image *) NULL);
2357 assert(image->signature == MagickSignature);
2358 assert(image->cache != (Cache) NULL);
2359 cache_info=(CacheInfo *) image->cache;
2360 assert(cache_info->signature == MagickSignature);
2361 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2362 if (metacontent != (void *) NULL)
2363 return(metacontent);
2364 assert(id < (int) cache_info->number_threads);
2365 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2366 cache_info->nexus_info[id]);
2367 return(metacontent);
2371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375 + 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 %
2379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2382 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2383 % is returned if the pixels are transferred, otherwise a NULL is returned.
2385 % The format of the GetVirtualPixelsFromNexus() method is:
2387 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2388 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2389 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2390 % ExceptionInfo *exception)
2392 % A description of each parameter follows:
2394 % o image: the image.
2396 % o virtual_pixel_method: the virtual pixel method.
2398 % o x,y,columns,rows: These values define the perimeter of a region of
2401 % o nexus_info: the cache nexus to acquire.
2403 % o exception: return any errors or warnings in this structure.
2410 0, 48, 12, 60, 3, 51, 15, 63,
2411 32, 16, 44, 28, 35, 19, 47, 31,
2412 8, 56, 4, 52, 11, 59, 7, 55,
2413 40, 24, 36, 20, 43, 27, 39, 23,
2414 2, 50, 14, 62, 1, 49, 13, 61,
2415 34, 18, 46, 30, 33, 17, 45, 29,
2416 10, 58, 6, 54, 9, 57, 5, 53,
2417 42, 26, 38, 22, 41, 25, 37, 21
2420 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2425 index=x+DitherMatrix[x & 0x07]-32L;
2428 if (index >= (ssize_t) columns)
2429 return((ssize_t) columns-1L);
2433 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2438 index=y+DitherMatrix[y & 0x07]-32L;
2441 if (index >= (ssize_t) rows)
2442 return((ssize_t) rows-1L);
2446 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2450 if (x >= (ssize_t) columns)
2451 return((ssize_t) (columns-1));
2455 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2459 if (y >= (ssize_t) rows)
2460 return((ssize_t) (rows-1));
2464 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2466 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2469 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2471 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2474 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2475 const size_t extent)
2481 Compute the remainder of dividing offset by extent. It returns not only
2482 the quotient (tile the offset falls in) but also the positive remainer
2483 within that tile such that 0 <= remainder < extent. This method is
2484 essentially a ldiv() using a floored modulo division rather than the
2485 normal default truncated modulo division.
2487 modulo.quotient=offset/(ssize_t) extent;
2490 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2494 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2495 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2496 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2497 ExceptionInfo *exception)
2500 *restrict cache_info;
2510 **restrict virtual_nexus;
2514 virtual_pixel[MaxPixelChannels];
2519 register const Quantum
2532 register unsigned char
2539 *restrict virtual_metacontent;
2544 assert(image != (const Image *) NULL);
2545 assert(image->signature == MagickSignature);
2546 assert(image->cache != (Cache) NULL);
2547 cache_info=(CacheInfo *) image->cache;
2548 assert(cache_info->signature == MagickSignature);
2549 if (cache_info->type == UndefinedCache)
2550 return((const Quantum *) NULL);
2553 region.width=columns;
2555 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2557 if (pixels == (Quantum *) NULL)
2558 return((const Quantum *) NULL);
2560 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2561 nexus_info->region.x;
2562 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2563 nexus_info->region.width-1L;
2564 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2565 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2566 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2567 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2573 Pixel request is inside cache extents.
2575 if (nexus_info->authentic_pixel_cache != MagickFalse)
2577 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2578 if (status == MagickFalse)
2579 return((const Quantum *) NULL);
2580 if (cache_info->metacontent_extent != 0)
2582 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2583 if (status == MagickFalse)
2584 return((const Quantum *) NULL);
2589 Pixel request is outside cache extents.
2591 s=(unsigned char *) nexus_info->metacontent;
2592 virtual_nexus=AcquirePixelCacheNexus(1);
2593 if (virtual_nexus == (NexusInfo **) NULL)
2595 if (virtual_nexus != (NexusInfo **) NULL)
2596 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2597 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2598 "UnableToGetCacheNexus","`%s'",image->filename);
2599 return((const Quantum *) NULL);
2601 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2602 sizeof(*virtual_pixel));
2603 virtual_metacontent=(void *) NULL;
2604 switch (virtual_pixel_method)
2606 case BackgroundVirtualPixelMethod:
2607 case BlackVirtualPixelMethod:
2608 case GrayVirtualPixelMethod:
2609 case TransparentVirtualPixelMethod:
2610 case MaskVirtualPixelMethod:
2611 case WhiteVirtualPixelMethod:
2612 case EdgeVirtualPixelMethod:
2613 case CheckerTileVirtualPixelMethod:
2614 case HorizontalTileVirtualPixelMethod:
2615 case VerticalTileVirtualPixelMethod:
2617 if (cache_info->metacontent_extent != 0)
2620 Acquire a metacontent buffer.
2622 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2623 cache_info->metacontent_extent);
2624 if (virtual_metacontent == (void *) NULL)
2626 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2627 (void) ThrowMagickException(exception,GetMagickModule(),
2628 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2629 return((const Quantum *) NULL);
2631 (void) ResetMagickMemory(virtual_metacontent,0,
2632 cache_info->metacontent_extent);
2634 switch (virtual_pixel_method)
2636 case BlackVirtualPixelMethod:
2638 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2639 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2640 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2643 case GrayVirtualPixelMethod:
2645 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2646 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2648 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2651 case TransparentVirtualPixelMethod:
2653 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2654 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2655 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2658 case MaskVirtualPixelMethod:
2659 case WhiteVirtualPixelMethod:
2661 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2662 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2663 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2668 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2670 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2672 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2674 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2676 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2686 for (v=0; v < (ssize_t) rows; v++)
2692 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2693 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2694 y_offset=EdgeY(y_offset,cache_info->rows);
2695 for (u=0; u < (ssize_t) columns; u+=length)
2701 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2702 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2703 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2711 Transfer a single pixel.
2713 length=(MagickSizeType) 1;
2714 switch (virtual_pixel_method)
2716 case EdgeVirtualPixelMethod:
2719 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2720 EdgeX(x_offset,cache_info->columns),
2721 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2723 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2726 case RandomVirtualPixelMethod:
2728 if (cache_info->random_info == (RandomInfo *) NULL)
2729 cache_info->random_info=AcquireRandomInfo();
2730 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2731 RandomX(cache_info->random_info,cache_info->columns),
2732 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2733 *virtual_nexus,exception);
2734 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2737 case DitherVirtualPixelMethod:
2739 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2740 DitherX(x_offset,cache_info->columns),
2741 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2743 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2746 case TileVirtualPixelMethod:
2748 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2749 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2750 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2751 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2753 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2756 case MirrorVirtualPixelMethod:
2758 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2759 if ((x_modulo.quotient & 0x01) == 1L)
2760 x_modulo.remainder=(ssize_t) cache_info->columns-
2761 x_modulo.remainder-1L;
2762 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2763 if ((y_modulo.quotient & 0x01) == 1L)
2764 y_modulo.remainder=(ssize_t) cache_info->rows-
2765 y_modulo.remainder-1L;
2766 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2767 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2769 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2772 case HorizontalTileEdgeVirtualPixelMethod:
2774 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2775 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2776 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2777 *virtual_nexus,exception);
2778 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2781 case VerticalTileEdgeVirtualPixelMethod:
2783 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2784 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2785 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2786 *virtual_nexus,exception);
2787 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2790 case BackgroundVirtualPixelMethod:
2791 case BlackVirtualPixelMethod:
2792 case GrayVirtualPixelMethod:
2793 case TransparentVirtualPixelMethod:
2794 case MaskVirtualPixelMethod:
2795 case WhiteVirtualPixelMethod:
2798 r=virtual_metacontent;
2801 case CheckerTileVirtualPixelMethod:
2803 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2804 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2805 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2808 r=virtual_metacontent;
2811 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2812 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2814 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2817 case HorizontalTileVirtualPixelMethod:
2819 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2822 r=virtual_metacontent;
2825 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2826 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2827 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2828 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2830 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2833 case VerticalTileVirtualPixelMethod:
2835 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2838 r=virtual_metacontent;
2841 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2842 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2843 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2844 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2846 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2850 if (p == (const Quantum *) NULL)
2852 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2854 q+=cache_info->number_channels;
2855 if ((s != (void *) NULL) && (r != (const void *) NULL))
2857 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2858 s+=cache_info->metacontent_extent;
2863 Transfer a run of pixels.
2865 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2866 (size_t) length,1UL,*virtual_nexus,exception);
2867 if (p == (const Quantum *) NULL)
2869 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2870 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2871 q+=length*cache_info->number_channels;
2872 if ((r != (void *) NULL) && (s != (const void *) NULL))
2874 (void) memcpy(s,r,(size_t) length);
2875 s+=length*cache_info->metacontent_extent;
2882 if (virtual_metacontent != (void *) NULL)
2883 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2884 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2893 + G e t V i r t u a l P i x e l C a c h e %
2897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2899 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2900 % cache as defined by the geometry parameters. A pointer to the pixels
2901 % is returned if the pixels are transferred, otherwise a NULL is returned.
2903 % The format of the GetVirtualPixelCache() method is:
2905 % const Quantum *GetVirtualPixelCache(const Image *image,
2906 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2907 % const ssize_t y,const size_t columns,const size_t rows,
2908 % ExceptionInfo *exception)
2910 % A description of each parameter follows:
2912 % o image: the image.
2914 % o virtual_pixel_method: the virtual pixel method.
2916 % o x,y,columns,rows: These values define the perimeter of a region of
2919 % o exception: return any errors or warnings in this structure.
2922 static const Quantum *GetVirtualPixelCache(const Image *image,
2923 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2924 const size_t columns,const size_t rows,ExceptionInfo *exception)
2927 *restrict cache_info;
2930 id = GetOpenMPThreadId();
2935 assert(image != (const Image *) NULL);
2936 assert(image->signature == MagickSignature);
2937 assert(image->cache != (Cache) NULL);
2938 cache_info=(CacheInfo *) image->cache;
2939 assert(cache_info->signature == MagickSignature);
2940 assert(id < (int) cache_info->number_threads);
2941 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2942 cache_info->nexus_info[id],exception);
2947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2951 % G e t V i r t u a l P i x e l Q u e u e %
2955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2957 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2958 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2960 % The format of the GetVirtualPixelQueue() method is:
2962 % const Quantum *GetVirtualPixelQueue(const Image image)
2964 % A description of each parameter follows:
2966 % o image: the image.
2969 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2972 *restrict cache_info;
2975 id = GetOpenMPThreadId();
2977 assert(image != (const Image *) NULL);
2978 assert(image->signature == MagickSignature);
2979 assert(image->cache != (Cache) NULL);
2980 cache_info=(CacheInfo *) image->cache;
2981 assert(cache_info->signature == MagickSignature);
2982 if (cache_info->methods.get_virtual_pixels_handler !=
2983 (GetVirtualPixelsHandler) NULL)
2984 return(cache_info->methods.get_virtual_pixels_handler(image));
2985 assert(id < (int) cache_info->number_threads);
2986 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2994 % G e t V i r t u a l P i x e l s %
2998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3000 % GetVirtualPixels() returns an immutable pixel region. If the
3001 % region is successfully accessed, a pointer to it is returned, otherwise
3002 % NULL is returned. The returned pointer may point to a temporary working
3003 % copy of the pixels or it may point to the original pixels in memory.
3004 % Performance is maximized if the selected region is part of one row, or one
3005 % or more full rows, since there is opportunity to access the pixels in-place
3006 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3007 % returned pointer must *never* be deallocated by the user.
3009 % Pixels accessed via the returned pointer represent a simple array of type
3010 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3011 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3012 % access the meta-content (of type void) corresponding to the the
3015 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3017 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3018 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3019 % GetCacheViewAuthenticPixels() instead.
3021 % The format of the GetVirtualPixels() method is:
3023 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3024 % const ssize_t y,const size_t columns,const size_t rows,
3025 % ExceptionInfo *exception)
3027 % A description of each parameter follows:
3029 % o image: the image.
3031 % o x,y,columns,rows: These values define the perimeter of a region of
3034 % o exception: return any errors or warnings in this structure.
3037 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3038 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3039 ExceptionInfo *exception)
3042 *restrict cache_info;
3045 id = GetOpenMPThreadId();
3050 assert(image != (const Image *) NULL);
3051 assert(image->signature == MagickSignature);
3052 assert(image->cache != (Cache) NULL);
3053 cache_info=(CacheInfo *) image->cache;
3054 assert(cache_info->signature == MagickSignature);
3055 if (cache_info->methods.get_virtual_pixel_handler !=
3056 (GetVirtualPixelHandler) NULL)
3057 return(cache_info->methods.get_virtual_pixel_handler(image,
3058 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3059 assert(id < (int) cache_info->number_threads);
3060 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3061 columns,rows,cache_info->nexus_info[id],exception);
3066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3070 + 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 %
3074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3076 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3077 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3079 % The format of the GetVirtualPixelsCache() method is:
3081 % Quantum *GetVirtualPixelsCache(const Image *image)
3083 % A description of each parameter follows:
3085 % o image: the image.
3088 static const Quantum *GetVirtualPixelsCache(const Image *image)
3091 *restrict cache_info;
3094 id = GetOpenMPThreadId();
3096 assert(image != (const Image *) NULL);
3097 assert(image->signature == MagickSignature);
3098 assert(image->cache != (Cache) NULL);
3099 cache_info=(CacheInfo *) image->cache;
3100 assert(cache_info->signature == MagickSignature);
3101 assert(id < (int) cache_info->number_threads);
3102 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3110 + G e t V i r t u a l P i x e l s N e x u s %
3114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3116 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3119 % The format of the GetVirtualPixelsNexus() method is:
3121 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3122 % NexusInfo *nexus_info)
3124 % A description of each parameter follows:
3126 % o cache: the pixel cache.
3128 % o nexus_info: the cache nexus to return the colormap pixels.
3131 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3132 NexusInfo *restrict nexus_info)
3135 *restrict cache_info;
3137 assert(cache != (Cache) NULL);
3138 cache_info=(CacheInfo *) cache;
3139 assert(cache_info->signature == MagickSignature);
3140 if (cache_info->storage_class == UndefinedClass)
3141 return((Quantum *) NULL);
3142 return((const Quantum *) nexus_info->pixels);
3146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3150 + O p e n P i x e l C a c h e %
3154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3156 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3157 % dimensions, allocating space for the image pixels and optionally the
3158 % metacontent, and memory mapping the cache if it is disk based. The cache
3159 % nexus array is initialized as well.
3161 % The format of the OpenPixelCache() method is:
3163 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3164 % ExceptionInfo *exception)
3166 % A description of each parameter follows:
3168 % o image: the image.
3170 % o mode: ReadMode, WriteMode, or IOMode.
3172 % o exception: return any errors or warnings in this structure.
3176 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3178 cache_info->mapped=MagickFalse;
3179 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3180 (size_t) cache_info->length));
3181 if (cache_info->pixels == (Quantum *) NULL)
3183 cache_info->mapped=MagickTrue;
3184 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3185 cache_info->length);
3189 #if defined(__cplusplus) || defined(c_plusplus)
3194 static void CacheSignalHandler(int status)
3196 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3200 #if defined(__cplusplus) || defined(c_plusplus)
3204 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3211 Open pixel cache on disk.
3213 if (cache_info->file != -1)
3214 return(MagickTrue); /* cache already open */
3215 if (*cache_info->cache_filename == '\0')
3216 file=AcquireUniqueFileResource(cache_info->cache_filename);
3222 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3227 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3228 O_BINARY | O_EXCL,S_MODE);
3230 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3236 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3239 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3244 return(MagickFalse);
3245 (void) AcquireMagickResource(FileResource,1);
3246 cache_info->file=file;
3247 cache_info->mode=mode;
3251 static inline MagickOffsetType WritePixelCacheRegion(
3252 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3253 const MagickSizeType length,const unsigned char *restrict buffer)
3255 register MagickOffsetType
3261 #if !defined(MAGICKCORE_HAVE_PWRITE)
3262 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3263 return((MagickOffsetType) -1);
3266 for (i=0; i < (MagickOffsetType) length; i+=count)
3268 #if !defined(MAGICKCORE_HAVE_PWRITE)
3269 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3270 (MagickSizeType) SSIZE_MAX));
3272 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3273 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3285 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3288 *restrict cache_info;
3295 cache_info=(CacheInfo *) image->cache;
3296 if (image->debug != MagickFalse)
3299 format[MaxTextExtent],
3300 message[MaxTextExtent];
3302 (void) FormatMagickSize(length,MagickFalse,format);
3303 (void) FormatLocaleString(message,MaxTextExtent,
3304 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3305 cache_info->cache_filename,cache_info->file,format);
3306 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3308 if (length != (MagickSizeType) ((MagickOffsetType) length))
3309 return(MagickFalse);
3310 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3312 return(MagickFalse);
3313 if ((MagickSizeType) offset >= length)
3315 extent=(MagickOffsetType) length-1;
3316 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3317 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3318 if (cache_info->synchronize != MagickFalse)
3323 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3325 return(MagickFalse);
3329 (void) signal(SIGBUS,CacheSignalHandler);
3331 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3334 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3335 ExceptionInfo *exception)
3338 *restrict cache_info,
3342 format[MaxTextExtent],
3343 message[MaxTextExtent];
3359 assert(image != (const Image *) NULL);
3360 assert(image->signature == MagickSignature);
3361 assert(image->cache != (Cache) NULL);
3362 if (image->debug != MagickFalse)
3363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3364 if ((image->columns == 0) || (image->rows == 0))
3365 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3366 cache_info=(CacheInfo *) image->cache;
3367 assert(cache_info->signature == MagickSignature);
3368 source_info=(*cache_info);
3369 source_info.file=(-1);
3370 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3371 image->filename,(double) GetImageIndexInList(image));
3372 cache_info->storage_class=image->storage_class;
3373 cache_info->colorspace=image->colorspace;
3374 cache_info->alpha_trait=image->alpha_trait;
3375 cache_info->read_mask=image->read_mask;
3376 cache_info->write_mask=image->write_mask;
3377 cache_info->rows=image->rows;
3378 cache_info->columns=image->columns;
3379 InitializePixelChannelMap(image);
3380 cache_info->number_channels=GetPixelChannels(image);
3381 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3382 sizeof(*image->channel_map));
3383 cache_info->metacontent_extent=image->metacontent_extent;
3384 cache_info->mode=mode;
3385 if (image->ping != MagickFalse)
3387 cache_info->type=PingCache;
3388 cache_info->pixels=(Quantum *) NULL;
3389 cache_info->metacontent=(void *) NULL;
3390 cache_info->length=0;
3393 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3394 packet_size=cache_info->number_channels*sizeof(Quantum);
3395 if (image->metacontent_extent != 0)
3396 packet_size+=cache_info->metacontent_extent;
3397 length=number_pixels*packet_size;
3398 columns=(size_t) (length/cache_info->rows/packet_size);
3399 if (cache_info->columns != columns)
3400 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3402 cache_info->length=length;
3403 status=AcquireMagickResource(AreaResource,cache_info->length);
3404 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3405 cache_info->metacontent_extent);
3406 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3408 status=AcquireMagickResource(MemoryResource,cache_info->length);
3409 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3410 (cache_info->type == MemoryCache))
3412 AllocatePixelCachePixels(cache_info);
3413 if (cache_info->pixels == (Quantum *) NULL)
3414 cache_info->pixels=source_info.pixels;
3418 Create memory pixel cache.
3421 cache_info->type=MemoryCache;
3422 cache_info->metacontent=(void *) NULL;
3423 if (cache_info->metacontent_extent != 0)
3424 cache_info->metacontent=(void *) (cache_info->pixels+
3425 number_pixels*cache_info->number_channels);
3426 if ((source_info.storage_class != UndefinedClass) &&
3429 status=ClonePixelCacheRepository(cache_info,&source_info,
3431 RelinquishPixelCachePixels(&source_info);
3433 if (image->debug != MagickFalse)
3435 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3436 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3438 (void) FormatLocaleString(message,MaxTextExtent,
3439 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3440 cache_info->filename,cache_info->mapped != MagickFalse ?
3441 "Anonymous" : "Heap",type,(double) cache_info->columns,
3442 (double) cache_info->rows,(double)
3443 cache_info->number_channels,format);
3444 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3450 RelinquishMagickResource(MemoryResource,cache_info->length);
3453 Create pixel cache on disk.
3455 status=AcquireMagickResource(DiskResource,cache_info->length);
3456 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3461 if (cache_info->type == DistributedCache)
3462 RelinquishMagickResource(DiskResource,cache_info->length);
3463 server_info=AcquireDistributeCacheInfo(exception);
3464 if (server_info != (DistributeCacheInfo *) NULL)
3466 status=OpenDistributePixelCache(server_info,image);
3467 if (status == MagickFalse)
3469 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3470 GetDistributeCacheHostname(server_info));
3471 server_info=DestroyDistributeCacheInfo(server_info);
3476 Create a distributed pixel cache.
3478 cache_info->type=DistributedCache;
3479 cache_info->server_info=server_info;
3480 (void) FormatLocaleString(cache_info->cache_filename,
3481 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3482 (DistributeCacheInfo *) cache_info->server_info),
3483 GetDistributeCachePort((DistributeCacheInfo *)
3484 cache_info->server_info));
3485 if ((source_info.storage_class != UndefinedClass) &&
3488 status=ClonePixelCacheRepository(cache_info,&source_info,
3490 RelinquishPixelCachePixels(&source_info);
3492 if (image->debug != MagickFalse)
3494 (void) FormatMagickSize(cache_info->length,MagickFalse,
3496 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3498 (void) FormatLocaleString(message,MaxTextExtent,
3499 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3500 cache_info->filename,cache_info->cache_filename,
3501 GetDistributeCacheFile((DistributeCacheInfo *)
3502 cache_info->server_info),type,(double) cache_info->columns,
3503 (double) cache_info->rows,(double)
3504 cache_info->number_channels,format);
3505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3511 RelinquishMagickResource(DiskResource,cache_info->length);
3512 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3513 "CacheResourcesExhausted","`%s'",image->filename);
3514 return(MagickFalse);
3516 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3518 (void) ClosePixelCacheOnDisk(cache_info);
3519 *cache_info->cache_filename='\0';
3521 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3523 RelinquishMagickResource(DiskResource,cache_info->length);
3524 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3526 return(MagickFalse);
3528 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3529 cache_info->length);
3530 if (status == MagickFalse)
3532 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3534 return(MagickFalse);
3536 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3537 cache_info->metacontent_extent);
3538 if (length != (MagickSizeType) ((size_t) length))
3539 cache_info->type=DiskCache;
3542 status=AcquireMagickResource(MapResource,cache_info->length);
3543 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3544 (cache_info->type != MemoryCache))
3545 cache_info->type=DiskCache;
3548 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3549 cache_info->offset,(size_t) cache_info->length);
3550 if (cache_info->pixels == (Quantum *) NULL)
3552 cache_info->type=DiskCache;
3553 cache_info->pixels=source_info.pixels;
3558 Create file-backed memory-mapped pixel cache.
3561 (void) ClosePixelCacheOnDisk(cache_info);
3562 cache_info->type=MapCache;
3563 cache_info->mapped=MagickTrue;
3564 cache_info->metacontent=(void *) NULL;
3565 if (cache_info->metacontent_extent != 0)
3566 cache_info->metacontent=(void *) (cache_info->pixels+
3567 number_pixels*cache_info->number_channels);
3568 if ((source_info.storage_class != UndefinedClass) &&
3571 status=ClonePixelCacheRepository(cache_info,&source_info,
3573 RelinquishPixelCachePixels(&source_info);
3575 if (image->debug != MagickFalse)
3577 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
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 cache_info->file,type,(double) cache_info->columns,(double)
3584 cache_info->rows,(double) cache_info->number_channels,
3586 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3592 RelinquishMagickResource(MapResource,cache_info->length);
3595 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3597 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3598 RelinquishPixelCachePixels(&source_info);
3600 if (image->debug != MagickFalse)
3602 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3603 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3605 (void) FormatLocaleString(message,MaxTextExtent,
3606 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3607 cache_info->cache_filename,cache_info->file,type,(double)
3608 cache_info->columns,(double) cache_info->rows,(double)
3609 cache_info->number_channels,format);
3610 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3620 + P e r s i s t P i x e l C a c h e %
3624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3626 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3627 % persistent pixel cache is one that resides on disk and is not destroyed
3628 % when the program exits.
3630 % The format of the PersistPixelCache() method is:
3632 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3633 % const MagickBooleanType attach,MagickOffsetType *offset,
3634 % ExceptionInfo *exception)
3636 % A description of each parameter follows:
3638 % o image: the image.
3640 % o filename: the persistent pixel cache filename.
3642 % o attach: A value other than zero initializes the persistent pixel cache.
3644 % o initialize: A value other than zero initializes the persistent pixel
3647 % o offset: the offset in the persistent cache to store pixels.
3649 % o exception: return any errors or warnings in this structure.
3652 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3653 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3654 ExceptionInfo *exception)
3657 *restrict cache_info,
3658 *restrict clone_info;
3669 assert(image != (Image *) NULL);
3670 assert(image->signature == MagickSignature);
3671 if (image->debug != MagickFalse)
3672 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3673 assert(image->cache != (void *) NULL);
3674 assert(filename != (const char *) NULL);
3675 assert(offset != (MagickOffsetType *) NULL);
3676 page_size=GetMagickPageSize();
3677 cache_info=(CacheInfo *) image->cache;
3678 assert(cache_info->signature == MagickSignature);
3679 if (attach != MagickFalse)
3682 Attach existing persistent pixel cache.
3684 if (image->debug != MagickFalse)
3685 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3686 "attach persistent cache");
3687 (void) CopyMagickString(cache_info->cache_filename,filename,
3689 cache_info->type=DiskCache;
3690 cache_info->offset=(*offset);
3691 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3692 return(MagickFalse);
3693 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3696 if ((cache_info->mode != ReadMode) &&
3697 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3698 (cache_info->reference_count == 1))
3700 LockSemaphoreInfo(cache_info->semaphore);
3701 if ((cache_info->mode != ReadMode) &&
3702 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3703 (cache_info->reference_count == 1))
3709 Usurp existing persistent pixel cache.
3711 status=rename_utf8(cache_info->cache_filename,filename);
3714 (void) CopyMagickString(cache_info->cache_filename,filename,
3716 *offset+=cache_info->length+page_size-(cache_info->length %
3718 UnlockSemaphoreInfo(cache_info->semaphore);
3719 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3720 if (image->debug != MagickFalse)
3721 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3722 "Usurp resident persistent cache");
3726 UnlockSemaphoreInfo(cache_info->semaphore);
3729 Clone persistent pixel cache.
3731 clone_image=(*image);
3732 clone_info=(CacheInfo *) clone_image.cache;
3733 image->cache=ClonePixelCache(cache_info);
3734 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3735 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3736 cache_info->type=DiskCache;
3737 cache_info->offset=(*offset);
3738 cache_info=(CacheInfo *) image->cache;
3739 status=OpenPixelCache(image,IOMode,exception);
3740 if (status != MagickFalse)
3741 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3742 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3743 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3752 + 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 %
3756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3758 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3759 % defined by the region rectangle and returns a pointer to the region. This
3760 % region is subsequently transferred from the pixel cache with
3761 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3762 % pixels are transferred, otherwise a NULL is returned.
3764 % The format of the QueueAuthenticPixelCacheNexus() method is:
3766 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3767 % const ssize_t y,const size_t columns,const size_t rows,
3768 % const MagickBooleanType clone,NexusInfo *nexus_info,
3769 % ExceptionInfo *exception)
3771 % A description of each parameter follows:
3773 % o image: the image.
3775 % o x,y,columns,rows: These values define the perimeter of a region of
3778 % o nexus_info: the cache nexus to set.
3780 % o clone: clone the pixel cache.
3782 % o exception: return any errors or warnings in this structure.
3785 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3786 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3787 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3790 *restrict cache_info;
3805 Validate pixel cache geometry.
3807 assert(image != (const Image *) NULL);
3808 assert(image->signature == MagickSignature);
3809 assert(image->cache != (Cache) NULL);
3810 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3811 if (cache_info == (Cache) NULL)
3812 return((Quantum *) NULL);
3813 assert(cache_info->signature == MagickSignature);
3814 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3815 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3816 (y >= (ssize_t) cache_info->rows))
3818 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3819 "PixelsAreNotAuthentic","`%s'",image->filename);
3820 return((Quantum *) NULL);
3822 offset=(MagickOffsetType) y*cache_info->columns+x;
3824 return((Quantum *) NULL);
3825 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3826 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3827 if ((MagickSizeType) offset >= number_pixels)
3828 return((Quantum *) NULL);
3834 region.width=columns;
3836 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3846 + 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 %
3850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3852 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3853 % defined by the region rectangle and returns a pointer to the region. This
3854 % region is subsequently transferred from the pixel cache with
3855 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3856 % pixels are transferred, otherwise a NULL is returned.
3858 % The format of the QueueAuthenticPixelsCache() method is:
3860 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3861 % const ssize_t y,const size_t columns,const size_t rows,
3862 % ExceptionInfo *exception)
3864 % A description of each parameter follows:
3866 % o image: the image.
3868 % o x,y,columns,rows: These values define the perimeter of a region of
3871 % o exception: return any errors or warnings in this structure.
3874 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3875 const ssize_t y,const size_t columns,const size_t rows,
3876 ExceptionInfo *exception)
3879 *restrict cache_info;
3882 id = GetOpenMPThreadId();
3887 assert(image != (const Image *) NULL);
3888 assert(image->signature == MagickSignature);
3889 assert(image->cache != (Cache) NULL);
3890 cache_info=(CacheInfo *) image->cache;
3891 assert(cache_info->signature == MagickSignature);
3892 assert(id < (int) cache_info->number_threads);
3893 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3894 cache_info->nexus_info[id],exception);
3899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3903 % Q u e u e A u t h e n t i c P i x e l s %
3907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3909 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3910 % successfully initialized a pointer to a Quantum array representing the
3911 % region is returned, otherwise NULL is returned. The returned pointer may
3912 % point to a temporary working buffer for the pixels or it may point to the
3913 % final location of the pixels in memory.
3915 % Write-only access means that any existing pixel values corresponding to
3916 % the region are ignored. This is useful if the initial image is being
3917 % created from scratch, or if the existing pixel values are to be
3918 % completely replaced without need to refer to their pre-existing values.
3919 % The application is free to read and write the pixel buffer returned by
3920 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3921 % initialize the pixel array values. Initializing pixel array values is the
3922 % application's responsibility.
3924 % Performance is maximized if the selected region is part of one row, or
3925 % one or more full rows, since then there is opportunity to access the
3926 % pixels in-place (without a copy) if the image is in memory, or in a
3927 % memory-mapped file. The returned pointer must *never* be deallocated
3930 % Pixels accessed via the returned pointer represent a simple array of type
3931 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3932 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3933 % obtain the meta-content (of type void) corresponding to the region.
3934 % Once the Quantum (and/or Quantum) array has been updated, the
3935 % changes must be saved back to the underlying image using
3936 % SyncAuthenticPixels() or they may be lost.
3938 % The format of the QueueAuthenticPixels() method is:
3940 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3941 % const ssize_t y,const size_t columns,const size_t rows,
3942 % ExceptionInfo *exception)
3944 % A description of each parameter follows:
3946 % o image: the image.
3948 % o x,y,columns,rows: These values define the perimeter of a region of
3951 % o exception: return any errors or warnings in this structure.
3954 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3955 const ssize_t y,const size_t columns,const size_t rows,
3956 ExceptionInfo *exception)
3959 *restrict cache_info;
3962 id = GetOpenMPThreadId();
3967 assert(image != (Image *) NULL);
3968 assert(image->signature == MagickSignature);
3969 assert(image->cache != (Cache) NULL);
3970 cache_info=(CacheInfo *) image->cache;
3971 assert(cache_info->signature == MagickSignature);
3972 if (cache_info->methods.queue_authentic_pixels_handler !=
3973 (QueueAuthenticPixelsHandler) NULL)
3975 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3976 columns,rows,exception);
3979 assert(id < (int) cache_info->number_threads);
3980 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3981 cache_info->nexus_info[id],exception);
3986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3990 + 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 %
3994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3996 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3999 % The format of the ReadPixelCacheMetacontent() method is:
4001 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4002 % NexusInfo *nexus_info,ExceptionInfo *exception)
4004 % A description of each parameter follows:
4006 % o cache_info: the pixel cache.
4008 % o nexus_info: the cache nexus to read the metacontent.
4010 % o exception: return any errors or warnings in this structure.
4014 static inline MagickOffsetType ReadPixelCacheRegion(
4015 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4016 const MagickSizeType length,unsigned char *restrict buffer)
4018 register MagickOffsetType
4024 #if !defined(MAGICKCORE_HAVE_PREAD)
4025 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4026 return((MagickOffsetType) -1);
4029 for (i=0; i < (MagickOffsetType) length; i+=count)
4031 #if !defined(MAGICKCORE_HAVE_PREAD)
4032 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4033 (MagickSizeType) SSIZE_MAX));
4035 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4036 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4048 static MagickBooleanType ReadPixelCacheMetacontent(
4049 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4050 ExceptionInfo *exception)
4063 register unsigned char
4069 if (cache_info->metacontent_extent == 0)
4070 return(MagickFalse);
4071 if (nexus_info->authentic_pixel_cache != MagickFalse)
4073 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4074 nexus_info->region.x;
4075 length=(MagickSizeType) nexus_info->region.width*
4076 cache_info->metacontent_extent;
4077 extent=length*nexus_info->region.height;
4078 rows=nexus_info->region.height;
4080 q=(unsigned char *) nexus_info->metacontent;
4081 switch (cache_info->type)
4086 register unsigned char
4090 Read meta-content from memory.
4092 if ((cache_info->columns == nexus_info->region.width) &&
4093 (extent == (MagickSizeType) ((size_t) extent)))
4098 p=(unsigned char *) cache_info->metacontent+offset*
4099 cache_info->metacontent_extent;
4100 for (y=0; y < (ssize_t) rows; y++)
4102 (void) memcpy(q,p,(size_t) length);
4103 p+=cache_info->metacontent_extent*cache_info->columns;
4104 q+=cache_info->metacontent_extent*nexus_info->region.width;
4111 Read meta content from disk.
4113 LockSemaphoreInfo(cache_info->file_semaphore);
4114 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4116 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4117 cache_info->cache_filename);
4118 UnlockSemaphoreInfo(cache_info->file_semaphore);
4119 return(MagickFalse);
4121 if ((cache_info->columns == nexus_info->region.width) &&
4122 (extent <= MagickMaxBufferExtent))
4127 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4128 for (y=0; y < (ssize_t) rows; y++)
4130 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4131 cache_info->number_channels*sizeof(Quantum)+offset*
4132 cache_info->metacontent_extent,length,(unsigned char *) q);
4133 if (count != (MagickOffsetType) length)
4135 offset+=cache_info->columns;
4136 q+=cache_info->metacontent_extent*nexus_info->region.width;
4138 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4139 (void) ClosePixelCacheOnDisk(cache_info);
4140 UnlockSemaphoreInfo(cache_info->file_semaphore);
4143 case DistributedCache:
4149 Read metacontent from distributed cache.
4151 LockSemaphoreInfo(cache_info->file_semaphore);
4152 region=nexus_info->region;
4153 if ((cache_info->columns != nexus_info->region.width) ||
4154 (extent > MagickMaxBufferExtent))
4161 for (y=0; y < (ssize_t) rows; y++)
4163 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4164 cache_info->server_info,®ion,length,(unsigned char *) q);
4165 if (count != (MagickOffsetType) length)
4167 q+=cache_info->metacontent_extent*nexus_info->region.width;
4170 UnlockSemaphoreInfo(cache_info->file_semaphore);
4176 if (y < (ssize_t) rows)
4178 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4179 cache_info->cache_filename);
4180 return(MagickFalse);
4182 if ((cache_info->debug != MagickFalse) &&
4183 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4184 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4185 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4186 nexus_info->region.width,(double) nexus_info->region.height,(double)
4187 nexus_info->region.x,(double) nexus_info->region.y);
4192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4196 + R e a d P i x e l C a c h e P i x e l s %
4200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4202 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4205 % The format of the ReadPixelCachePixels() method is:
4207 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4208 % NexusInfo *nexus_info,ExceptionInfo *exception)
4210 % A description of each parameter follows:
4212 % o cache_info: the pixel cache.
4214 % o nexus_info: the cache nexus to read the pixels.
4216 % o exception: return any errors or warnings in this structure.
4219 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4220 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4239 if (nexus_info->authentic_pixel_cache != MagickFalse)
4241 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4242 nexus_info->region.x;
4243 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4245 extent=length*nexus_info->region.height;
4246 rows=nexus_info->region.height;
4248 q=nexus_info->pixels;
4249 switch (cache_info->type)
4258 Read pixels from memory.
4260 if ((cache_info->columns == nexus_info->region.width) &&
4261 (extent == (MagickSizeType) ((size_t) extent)))
4266 p=cache_info->pixels+offset*cache_info->number_channels;
4267 for (y=0; y < (ssize_t) rows; y++)
4269 (void) memcpy(q,p,(size_t) length);
4270 p+=cache_info->number_channels*cache_info->columns;
4271 q+=cache_info->number_channels*nexus_info->region.width;
4278 Read pixels from disk.
4280 LockSemaphoreInfo(cache_info->file_semaphore);
4281 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4283 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4284 cache_info->cache_filename);
4285 UnlockSemaphoreInfo(cache_info->file_semaphore);
4286 return(MagickFalse);
4288 if ((cache_info->columns == nexus_info->region.width) &&
4289 (extent <= MagickMaxBufferExtent))
4294 for (y=0; y < (ssize_t) rows; y++)
4296 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4297 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4298 if (count != (MagickOffsetType) length)
4300 offset+=cache_info->columns;
4301 q+=cache_info->number_channels*nexus_info->region.width;
4303 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4304 (void) ClosePixelCacheOnDisk(cache_info);
4305 UnlockSemaphoreInfo(cache_info->file_semaphore);
4308 case DistributedCache:
4314 Read pixels from distributed cache.
4316 LockSemaphoreInfo(cache_info->file_semaphore);
4317 region=nexus_info->region;
4318 if ((cache_info->columns != nexus_info->region.width) ||
4319 (extent > MagickMaxBufferExtent))
4326 for (y=0; y < (ssize_t) rows; y++)
4328 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4329 cache_info->server_info,®ion,length,(unsigned char *) q);
4330 if (count != (MagickOffsetType) length)
4332 q+=cache_info->number_channels*nexus_info->region.width;
4335 UnlockSemaphoreInfo(cache_info->file_semaphore);
4341 if (y < (ssize_t) rows)
4343 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4344 cache_info->cache_filename);
4345 return(MagickFalse);
4347 if ((cache_info->debug != MagickFalse) &&
4348 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4349 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4350 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4351 nexus_info->region.width,(double) nexus_info->region.height,(double)
4352 nexus_info->region.x,(double) nexus_info->region.y);
4357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4361 + R e f e r e n c e P i x e l C a c h e %
4365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4367 % ReferencePixelCache() increments the reference count associated with the
4368 % pixel cache returning a pointer to the cache.
4370 % The format of the ReferencePixelCache method is:
4372 % Cache ReferencePixelCache(Cache cache_info)
4374 % A description of each parameter follows:
4376 % o cache_info: the pixel cache.
4379 MagickPrivate Cache ReferencePixelCache(Cache cache)
4382 *restrict cache_info;
4384 assert(cache != (Cache *) NULL);
4385 cache_info=(CacheInfo *) cache;
4386 assert(cache_info->signature == MagickSignature);
4387 LockSemaphoreInfo(cache_info->semaphore);
4388 cache_info->reference_count++;
4389 UnlockSemaphoreInfo(cache_info->semaphore);
4394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4398 + S e t P i x e l C a c h e M e t h o d s %
4402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4404 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4406 % The format of the SetPixelCacheMethods() method is:
4408 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4410 % A description of each parameter follows:
4412 % o cache: the pixel cache.
4414 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4417 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4420 *restrict cache_info;
4422 GetOneAuthenticPixelFromHandler
4423 get_one_authentic_pixel_from_handler;
4425 GetOneVirtualPixelFromHandler
4426 get_one_virtual_pixel_from_handler;
4429 Set cache pixel methods.
4431 assert(cache != (Cache) NULL);
4432 assert(cache_methods != (CacheMethods *) NULL);
4433 cache_info=(CacheInfo *) cache;
4434 assert(cache_info->signature == MagickSignature);
4435 if (cache_info->debug != MagickFalse)
4436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4437 cache_info->filename);
4438 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4439 cache_info->methods.get_virtual_pixel_handler=
4440 cache_methods->get_virtual_pixel_handler;
4441 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4442 cache_info->methods.destroy_pixel_handler=
4443 cache_methods->destroy_pixel_handler;
4444 if (cache_methods->get_virtual_metacontent_from_handler !=
4445 (GetVirtualMetacontentFromHandler) NULL)
4446 cache_info->methods.get_virtual_metacontent_from_handler=
4447 cache_methods->get_virtual_metacontent_from_handler;
4448 if (cache_methods->get_authentic_pixels_handler !=
4449 (GetAuthenticPixelsHandler) NULL)
4450 cache_info->methods.get_authentic_pixels_handler=
4451 cache_methods->get_authentic_pixels_handler;
4452 if (cache_methods->queue_authentic_pixels_handler !=
4453 (QueueAuthenticPixelsHandler) NULL)
4454 cache_info->methods.queue_authentic_pixels_handler=
4455 cache_methods->queue_authentic_pixels_handler;
4456 if (cache_methods->sync_authentic_pixels_handler !=
4457 (SyncAuthenticPixelsHandler) NULL)
4458 cache_info->methods.sync_authentic_pixels_handler=
4459 cache_methods->sync_authentic_pixels_handler;
4460 if (cache_methods->get_authentic_pixels_from_handler !=
4461 (GetAuthenticPixelsFromHandler) NULL)
4462 cache_info->methods.get_authentic_pixels_from_handler=
4463 cache_methods->get_authentic_pixels_from_handler;
4464 if (cache_methods->get_authentic_metacontent_from_handler !=
4465 (GetAuthenticMetacontentFromHandler) NULL)
4466 cache_info->methods.get_authentic_metacontent_from_handler=
4467 cache_methods->get_authentic_metacontent_from_handler;
4468 get_one_virtual_pixel_from_handler=
4469 cache_info->methods.get_one_virtual_pixel_from_handler;
4470 if (get_one_virtual_pixel_from_handler !=
4471 (GetOneVirtualPixelFromHandler) NULL)
4472 cache_info->methods.get_one_virtual_pixel_from_handler=
4473 cache_methods->get_one_virtual_pixel_from_handler;
4474 get_one_authentic_pixel_from_handler=
4475 cache_methods->get_one_authentic_pixel_from_handler;
4476 if (get_one_authentic_pixel_from_handler !=
4477 (GetOneAuthenticPixelFromHandler) NULL)
4478 cache_info->methods.get_one_authentic_pixel_from_handler=
4479 cache_methods->get_one_authentic_pixel_from_handler;
4483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4487 + S e t P i x e l C a c h e N e x u s P i x e l s %
4491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493 % SetPixelCacheNexusPixels() defines the region of the cache for the
4494 % specified cache nexus.
4496 % The format of the SetPixelCacheNexusPixels() method is:
4498 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4499 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4500 % ExceptionInfo *exception)
4502 % A description of each parameter follows:
4504 % o cache_info: the pixel cache.
4506 % o mode: ReadMode, WriteMode, or IOMode.
4508 % o region: A pointer to the RectangleInfo structure that defines the
4509 % region of this particular cache nexus.
4511 % o nexus_info: the cache nexus to set.
4513 % o exception: return any errors or warnings in this structure.
4517 static inline MagickBooleanType AcquireCacheNexusPixels(
4518 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4519 ExceptionInfo *exception)
4521 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4522 return(MagickFalse);
4523 nexus_info->mapped=MagickFalse;
4524 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4525 (size_t) nexus_info->length));
4526 if (nexus_info->cache == (Quantum *) NULL)
4528 nexus_info->mapped=MagickTrue;
4529 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4530 nexus_info->length);
4532 if (nexus_info->cache == (Quantum *) NULL)
4534 (void) ThrowMagickException(exception,GetMagickModule(),
4535 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4536 cache_info->filename);
4537 return(MagickFalse);
4542 static inline MagickBooleanType IsPixelCacheAuthentic(
4543 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4552 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4554 if (cache_info->type == PingCache)
4556 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4557 nexus_info->region.x;
4558 status=nexus_info->pixels == (cache_info->pixels+offset*
4559 cache_info->number_channels) ? MagickTrue : MagickFalse;
4563 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4566 if (mode == ReadMode)
4568 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4571 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4574 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4575 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4576 ExceptionInfo *exception)
4585 assert(cache_info != (const CacheInfo *) NULL);
4586 assert(cache_info->signature == MagickSignature);
4587 if (cache_info->type == UndefinedCache)
4588 return((Quantum *) NULL);
4589 nexus_info->region=(*region);
4590 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4596 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4597 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4598 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4599 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4600 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4601 ((nexus_info->region.width == cache_info->columns) ||
4602 ((nexus_info->region.width % cache_info->columns) == 0)))))
4608 Pixels are accessed directly from memory.
4610 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4611 nexus_info->region.x;
4612 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4614 nexus_info->metacontent=(void *) NULL;
4615 if (cache_info->metacontent_extent != 0)
4616 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4617 offset*cache_info->metacontent_extent;
4618 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4619 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4621 return(nexus_info->pixels);
4625 Pixels are stored in a staging region until they are synced to the cache.
4627 number_pixels=(MagickSizeType) nexus_info->region.width*
4628 nexus_info->region.height;
4629 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4630 if (cache_info->metacontent_extent != 0)
4631 length+=number_pixels*cache_info->metacontent_extent;
4632 if (nexus_info->cache == (Quantum *) NULL)
4634 nexus_info->length=length;
4635 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4636 if (status == MagickFalse)
4638 nexus_info->length=0;
4639 return((Quantum *) NULL);
4643 if (nexus_info->length < length)
4645 RelinquishCacheNexusPixels(nexus_info);
4646 nexus_info->length=length;
4647 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4648 if (status == MagickFalse)
4650 nexus_info->length=0;
4651 return((Quantum *) NULL);
4654 nexus_info->pixels=nexus_info->cache;
4655 nexus_info->metacontent=(void *) NULL;
4656 if (cache_info->metacontent_extent != 0)
4657 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4658 cache_info->number_channels);
4659 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4660 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4662 return(nexus_info->pixels);
4666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4670 % 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 %
4674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4676 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4677 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4678 % access that is outside the boundaries of the image cache.
4680 % The format of the SetPixelCacheVirtualMethod() method is:
4682 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4683 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4685 % A description of each parameter follows:
4687 % o image: the image.
4689 % o virtual_pixel_method: choose the type of virtual pixel.
4691 % o exception: return any errors or warnings in this structure.
4695 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4696 ExceptionInfo *exception)
4699 *restrict cache_info;
4702 *restrict image_view;
4710 assert(image != (Image *) NULL);
4711 assert(image->signature == MagickSignature);
4712 if (image->debug != MagickFalse)
4713 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4714 assert(image->cache != (Cache) NULL);
4715 cache_info=(CacheInfo *) image->cache;
4716 assert(cache_info->signature == MagickSignature);
4717 image->alpha_trait=BlendPixelTrait;
4719 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4720 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4721 #pragma omp parallel for schedule(static,4) shared(status) \
4722 magick_threads(image,image,1,1)
4724 for (y=0; y < (ssize_t) image->rows; y++)
4732 if (status == MagickFalse)
4734 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4735 if (q == (Quantum *) NULL)
4740 for (x=0; x < (ssize_t) image->columns; x++)
4742 SetPixelAlpha(image,alpha,q);
4743 q+=GetPixelChannels(image);
4745 status=SyncCacheViewAuthenticPixels(image_view,exception);
4747 image_view=DestroyCacheView(image_view);
4751 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4752 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4755 *restrict cache_info;
4760 assert(image != (Image *) NULL);
4761 assert(image->signature == MagickSignature);
4762 if (image->debug != MagickFalse)
4763 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4764 assert(image->cache != (Cache) NULL);
4765 cache_info=(CacheInfo *) image->cache;
4766 assert(cache_info->signature == MagickSignature);
4767 method=cache_info->virtual_pixel_method;
4768 cache_info->virtual_pixel_method=virtual_pixel_method;
4769 if ((image->columns != 0) && (image->rows != 0))
4770 switch (virtual_pixel_method)
4772 case BackgroundVirtualPixelMethod:
4774 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4775 (image->alpha_trait != BlendPixelTrait))
4776 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4777 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4778 (IsGrayColorspace(image->colorspace) != MagickFalse))
4779 (void) SetImageColorspace(image,sRGBColorspace,exception);
4782 case TransparentVirtualPixelMethod:
4784 if (image->alpha_trait != BlendPixelTrait)
4785 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4799 + 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 %
4803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4805 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4806 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4807 % is synced, otherwise MagickFalse.
4809 % The format of the SyncAuthenticPixelCacheNexus() method is:
4811 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4812 % NexusInfo *nexus_info,ExceptionInfo *exception)
4814 % A description of each parameter follows:
4816 % o image: the image.
4818 % o nexus_info: the cache nexus to sync.
4820 % o exception: return any errors or warnings in this structure.
4823 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4824 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4827 *restrict cache_info;
4833 Transfer pixels to the cache.
4835 assert(image != (Image *) NULL);
4836 assert(image->signature == MagickSignature);
4837 if (image->cache == (Cache) NULL)
4838 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4839 cache_info=(CacheInfo *) image->cache;
4840 assert(cache_info->signature == MagickSignature);
4841 if (cache_info->type == UndefinedCache)
4842 return(MagickFalse);
4843 if (nexus_info->authentic_pixel_cache != MagickFalse)
4845 assert(cache_info->signature == MagickSignature);
4846 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4847 if ((cache_info->metacontent_extent != 0) &&
4848 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4849 return(MagickFalse);
4854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4858 + S y n c A u t h e n t i c P i x e l C a c h e %
4862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4864 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4865 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4866 % otherwise MagickFalse.
4868 % The format of the SyncAuthenticPixelsCache() method is:
4870 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4871 % ExceptionInfo *exception)
4873 % A description of each parameter follows:
4875 % o image: the image.
4877 % o exception: return any errors or warnings in this structure.
4880 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4881 ExceptionInfo *exception)
4884 *restrict cache_info;
4887 id = GetOpenMPThreadId();
4892 assert(image != (Image *) NULL);
4893 assert(image->signature == MagickSignature);
4894 assert(image->cache != (Cache) NULL);
4895 cache_info=(CacheInfo *) image->cache;
4896 assert(cache_info->signature == MagickSignature);
4897 assert(id < (int) cache_info->number_threads);
4898 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4908 % S y n c A u t h e n t i c P i x e l s %
4912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4914 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4915 % The method returns MagickTrue if the pixel region is flushed, otherwise
4918 % The format of the SyncAuthenticPixels() method is:
4920 % MagickBooleanType SyncAuthenticPixels(Image *image,
4921 % ExceptionInfo *exception)
4923 % A description of each parameter follows:
4925 % o image: the image.
4927 % o exception: return any errors or warnings in this structure.
4930 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4931 ExceptionInfo *exception)
4934 *restrict cache_info;
4937 id = GetOpenMPThreadId();
4942 assert(image != (Image *) NULL);
4943 assert(image->signature == MagickSignature);
4944 assert(image->cache != (Cache) NULL);
4945 cache_info=(CacheInfo *) image->cache;
4946 assert(cache_info->signature == MagickSignature);
4947 if (cache_info->methods.sync_authentic_pixels_handler !=
4948 (SyncAuthenticPixelsHandler) NULL)
4950 status=cache_info->methods.sync_authentic_pixels_handler(image,
4954 assert(id < (int) cache_info->number_threads);
4955 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4965 + S y n c I m a g e P i x e l C a c h e %
4969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4971 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4972 % The method returns MagickTrue if the pixel region is flushed, otherwise
4975 % The format of the SyncImagePixelCache() method is:
4977 % MagickBooleanType SyncImagePixelCache(Image *image,
4978 % ExceptionInfo *exception)
4980 % A description of each parameter follows:
4982 % o image: the image.
4984 % o exception: return any errors or warnings in this structure.
4987 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4988 ExceptionInfo *exception)
4991 *restrict cache_info;
4993 assert(image != (Image *) NULL);
4994 assert(exception != (ExceptionInfo *) NULL);
4995 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4996 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5004 + 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 %
5008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5010 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5011 % of the pixel cache.
5013 % The format of the WritePixelCacheMetacontent() method is:
5015 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5016 % NexusInfo *nexus_info,ExceptionInfo *exception)
5018 % A description of each parameter follows:
5020 % o cache_info: the pixel cache.
5022 % o nexus_info: the cache nexus to write the meta-content.
5024 % o exception: return any errors or warnings in this structure.
5027 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5028 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5038 register const unsigned char
5047 if (cache_info->metacontent_extent == 0)
5048 return(MagickFalse);
5049 if (nexus_info->authentic_pixel_cache != MagickFalse)
5051 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5052 nexus_info->region.x;
5053 length=(MagickSizeType) nexus_info->region.width*
5054 cache_info->metacontent_extent;
5055 extent=(MagickSizeType) length*nexus_info->region.height;
5056 rows=nexus_info->region.height;
5058 p=(unsigned char *) nexus_info->metacontent;
5059 switch (cache_info->type)
5064 register unsigned char
5068 Write associated pixels to memory.
5070 if ((cache_info->columns == nexus_info->region.width) &&
5071 (extent == (MagickSizeType) ((size_t) extent)))
5076 q=(unsigned char *) cache_info->metacontent+offset*
5077 cache_info->metacontent_extent;
5078 for (y=0; y < (ssize_t) rows; y++)
5080 (void) memcpy(q,p,(size_t) length);
5081 p+=nexus_info->region.width*cache_info->metacontent_extent;
5082 q+=cache_info->columns*cache_info->metacontent_extent;
5089 Write associated pixels to disk.
5091 LockSemaphoreInfo(cache_info->file_semaphore);
5092 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5094 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5095 cache_info->cache_filename);
5096 UnlockSemaphoreInfo(cache_info->file_semaphore);
5097 return(MagickFalse);
5099 if ((cache_info->columns == nexus_info->region.width) &&
5100 (extent <= MagickMaxBufferExtent))
5105 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5106 for (y=0; y < (ssize_t) rows; y++)
5108 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5109 cache_info->number_channels*sizeof(Quantum)+offset*
5110 cache_info->metacontent_extent,length,(const unsigned char *) p);
5111 if (count != (MagickOffsetType) length)
5113 p+=cache_info->metacontent_extent*nexus_info->region.width;
5114 offset+=cache_info->columns;
5116 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5117 (void) ClosePixelCacheOnDisk(cache_info);
5118 UnlockSemaphoreInfo(cache_info->file_semaphore);
5121 case DistributedCache:
5127 Write metacontent to distributed cache.
5129 LockSemaphoreInfo(cache_info->file_semaphore);
5130 region=nexus_info->region;
5131 if ((cache_info->columns != nexus_info->region.width) ||
5132 (extent > MagickMaxBufferExtent))
5139 for (y=0; y < (ssize_t) rows; y++)
5141 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5142 cache_info->server_info,®ion,length,(const unsigned char *) p);
5143 if (count != (MagickOffsetType) length)
5145 p+=cache_info->metacontent_extent*nexus_info->region.width;
5148 UnlockSemaphoreInfo(cache_info->file_semaphore);
5154 if (y < (ssize_t) rows)
5156 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5157 cache_info->cache_filename);
5158 return(MagickFalse);
5160 if ((cache_info->debug != MagickFalse) &&
5161 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5162 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5163 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5164 nexus_info->region.width,(double) nexus_info->region.height,(double)
5165 nexus_info->region.x,(double) nexus_info->region.y);
5170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5174 + W r i t e C a c h e P i x e l s %
5178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5180 % WritePixelCachePixels() writes image pixels to the specified region of the
5183 % The format of the WritePixelCachePixels() method is:
5185 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5186 % NexusInfo *nexus_info,ExceptionInfo *exception)
5188 % A description of each parameter follows:
5190 % o cache_info: the pixel cache.
5192 % o nexus_info: the cache nexus to write the pixels.
5194 % o exception: return any errors or warnings in this structure.
5197 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5198 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5208 register const Quantum
5217 if (nexus_info->authentic_pixel_cache != MagickFalse)
5219 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5220 nexus_info->region.x;
5221 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5223 extent=length*nexus_info->region.height;
5224 rows=nexus_info->region.height;
5226 p=nexus_info->pixels;
5227 switch (cache_info->type)
5236 Write pixels to memory.
5238 if ((cache_info->columns == nexus_info->region.width) &&
5239 (extent == (MagickSizeType) ((size_t) extent)))
5244 q=cache_info->pixels+offset*cache_info->number_channels;
5245 for (y=0; y < (ssize_t) rows; y++)
5247 (void) memcpy(q,p,(size_t) length);
5248 p+=cache_info->number_channels*nexus_info->region.width;
5249 q+=cache_info->columns*cache_info->number_channels;
5256 Write pixels to disk.
5258 LockSemaphoreInfo(cache_info->file_semaphore);
5259 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5261 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5262 cache_info->cache_filename);
5263 UnlockSemaphoreInfo(cache_info->file_semaphore);
5264 return(MagickFalse);
5266 if ((cache_info->columns == nexus_info->region.width) &&
5267 (extent <= MagickMaxBufferExtent))
5272 for (y=0; y < (ssize_t) rows; y++)
5274 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5275 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5277 if (count != (MagickOffsetType) length)
5279 p+=cache_info->number_channels*nexus_info->region.width;
5280 offset+=cache_info->columns;
5282 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5283 (void) ClosePixelCacheOnDisk(cache_info);
5284 UnlockSemaphoreInfo(cache_info->file_semaphore);
5287 case DistributedCache:
5293 Write pixels to distributed cache.
5295 LockSemaphoreInfo(cache_info->file_semaphore);
5296 region=nexus_info->region;
5297 if ((cache_info->columns != nexus_info->region.width) ||
5298 (extent > MagickMaxBufferExtent))
5305 for (y=0; y < (ssize_t) rows; y++)
5307 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5308 cache_info->server_info,®ion,length,(const unsigned char *) p);
5309 if (count != (MagickOffsetType) length)
5311 p+=cache_info->number_channels*nexus_info->region.width;
5314 UnlockSemaphoreInfo(cache_info->file_semaphore);
5320 if (y < (ssize_t) rows)
5322 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5323 cache_info->cache_filename);
5324 return(MagickFalse);
5326 if ((cache_info->debug != MagickFalse) &&
5327 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5328 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5329 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5330 nexus_info->region.width,(double) nexus_info->region.height,(double)
5331 nexus_info->region.x,(double) nexus_info->region.y);