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))
1492 #if !defined(ECANCELED)
1497 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1499 assert(image->cache != (Cache) NULL);
1500 cache_info=(CacheInfo *) image->cache;
1501 destroy=MagickFalse;
1502 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1504 LockSemaphoreInfo(cache_info->semaphore);
1505 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1516 clone_image=(*image);
1517 clone_image.semaphore=AllocateSemaphoreInfo();
1518 clone_image.reference_count=1;
1519 clone_image.cache=ClonePixelCache(cache_info);
1520 clone_info=(CacheInfo *) clone_image.cache;
1521 status=OpenPixelCache(&clone_image,IOMode,exception);
1522 if (status != MagickFalse)
1524 if (clone != MagickFalse)
1525 status=ClonePixelCacheRepository(clone_info,cache_info,
1527 if (status != MagickFalse)
1529 if (cache_info->reference_count == 1)
1530 cache_info->nexus_info=(NexusInfo **) NULL;
1532 image->cache=clone_image.cache;
1535 DestroySemaphoreInfo(&clone_image.semaphore);
1537 UnlockSemaphoreInfo(cache_info->semaphore);
1539 if (destroy != MagickFalse)
1540 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1541 if (status != MagickFalse)
1544 Ensure the image matches the pixel cache morphology.
1546 image->taint=MagickTrue;
1547 image->type=UndefinedType;
1548 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1550 status=OpenPixelCache(image,IOMode,exception);
1551 cache_info=(CacheInfo *) image->cache;
1552 if (cache_info->type == DiskCache)
1553 (void) ClosePixelCacheOnDisk(cache_info);
1556 UnlockSemaphoreInfo(image->semaphore);
1557 if (status == MagickFalse)
1558 return((Cache) NULL);
1559 return(image->cache);
1563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567 + G e t I m a g e P i x e l C a c h e T y p e %
1571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1574 % DiskCache, MemoryCache, MapCache, or PingCache.
1576 % The format of the GetImagePixelCacheType() method is:
1578 % CacheType GetImagePixelCacheType(const Image *image)
1580 % A description of each parameter follows:
1582 % o image: the image.
1585 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1588 *restrict cache_info;
1590 assert(image != (Image *) NULL);
1591 assert(image->signature == MagickSignature);
1592 assert(image->cache != (Cache) NULL);
1593 cache_info=(CacheInfo *) image->cache;
1594 assert(cache_info->signature == MagickSignature);
1595 return(cache_info->type);
1599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1603 % G e t O n e A u t h e n t i c P i x e l %
1607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1609 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1610 % location. The image background color is returned if an error occurs.
1612 % The format of the GetOneAuthenticPixel() method is:
1614 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1615 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1617 % A description of each parameter follows:
1619 % o image: the image.
1621 % o x,y: These values define the location of the pixel to return.
1623 % o pixel: return a pixel at the specified (x,y) location.
1625 % o exception: return any errors or warnings in this structure.
1628 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1629 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1632 *restrict cache_info;
1640 assert(image != (Image *) NULL);
1641 assert(image->signature == MagickSignature);
1642 assert(image->cache != (Cache) NULL);
1643 cache_info=(CacheInfo *) image->cache;
1644 assert(cache_info->signature == MagickSignature);
1645 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1646 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1647 (GetOneAuthenticPixelFromHandler) NULL)
1648 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1650 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1651 if (q == (Quantum *) NULL)
1653 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1654 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1655 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1656 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1657 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1658 return(MagickFalse);
1660 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1662 PixelChannel channel=GetPixelChannelChannel(image,i);
1663 pixel[channel]=q[i];
1669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1673 + 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 %
1677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1680 % location. The image background color is returned if an error occurs.
1682 % The format of the GetOneAuthenticPixelFromCache() method is:
1684 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1685 % const ssize_t x,const ssize_t y,Quantum *pixel,
1686 % ExceptionInfo *exception)
1688 % A description of each parameter follows:
1690 % o image: the image.
1692 % o x,y: These values define the location of the pixel to return.
1694 % o pixel: return a pixel at the specified (x,y) location.
1696 % o exception: return any errors or warnings in this structure.
1699 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1700 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1703 *restrict cache_info;
1706 id = GetOpenMPThreadId();
1714 assert(image != (const Image *) NULL);
1715 assert(image->signature == MagickSignature);
1716 assert(image->cache != (Cache) NULL);
1717 cache_info=(CacheInfo *) image->cache;
1718 assert(cache_info->signature == MagickSignature);
1719 assert(id < (int) cache_info->number_threads);
1720 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1721 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1723 if (q == (Quantum *) NULL)
1725 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1726 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1727 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1728 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1729 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1730 return(MagickFalse);
1732 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1734 PixelChannel channel=GetPixelChannelChannel(image,i);
1735 pixel[channel]=q[i];
1741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745 % G e t O n e V i r t u a l P i x e l %
1749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1751 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1752 % (x,y) location. The image background color is returned if an error occurs.
1753 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1755 % The format of the GetOneVirtualPixel() method is:
1757 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1758 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1760 % A description of each parameter follows:
1762 % o image: the image.
1764 % o x,y: These values define the location of the pixel to return.
1766 % o pixel: return a pixel at the specified (x,y) location.
1768 % o exception: return any errors or warnings in this structure.
1771 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1772 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1775 *restrict cache_info;
1778 id = GetOpenMPThreadId();
1786 assert(image != (const Image *) NULL);
1787 assert(image->signature == MagickSignature);
1788 assert(image->cache != (Cache) NULL);
1789 cache_info=(CacheInfo *) image->cache;
1790 assert(cache_info->signature == MagickSignature);
1791 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1792 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1793 (GetOneVirtualPixelFromHandler) NULL)
1794 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1795 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1796 assert(id < (int) cache_info->number_threads);
1797 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1798 1UL,1UL,cache_info->nexus_info[id],exception);
1799 if (p == (const Quantum *) NULL)
1801 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1802 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1803 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1804 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1805 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1806 return(MagickFalse);
1808 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1810 PixelChannel channel=GetPixelChannelChannel(image,i);
1811 pixel[channel]=p[i];
1817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1821 + 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 %
1825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1827 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1828 % specified (x,y) location. The image background color is returned if an
1831 % The format of the GetOneVirtualPixelFromCache() method is:
1833 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1834 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1835 % Quantum *pixel,ExceptionInfo *exception)
1837 % A description of each parameter follows:
1839 % o image: the image.
1841 % o virtual_pixel_method: the virtual pixel method.
1843 % o x,y: These values define the location of the pixel to return.
1845 % o pixel: return a pixel at the specified (x,y) location.
1847 % o exception: return any errors or warnings in this structure.
1850 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1851 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1852 Quantum *pixel,ExceptionInfo *exception)
1855 *restrict cache_info;
1858 id = GetOpenMPThreadId();
1866 assert(image != (const Image *) NULL);
1867 assert(image->signature == MagickSignature);
1868 assert(image->cache != (Cache) NULL);
1869 cache_info=(CacheInfo *) image->cache;
1870 assert(cache_info->signature == MagickSignature);
1871 assert(id < (int) cache_info->number_threads);
1872 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1873 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1874 cache_info->nexus_info[id],exception);
1875 if (p == (const Quantum *) NULL)
1877 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1878 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1879 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1880 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1881 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1882 return(MagickFalse);
1884 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1886 PixelChannel channel=GetPixelChannelChannel(image,i);
1887 pixel[channel]=p[i];
1893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1897 % G e t O n e V i r t u a l P i x e l I n f o %
1901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1903 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1904 % location. The image background color is returned if an error occurs. If
1905 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1907 % The format of the GetOneVirtualPixelInfo() method is:
1909 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1910 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1911 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1913 % A description of each parameter follows:
1915 % o image: the image.
1917 % o virtual_pixel_method: the virtual pixel method.
1919 % o x,y: these values define the location of the pixel to return.
1921 % o pixel: return a pixel at the specified (x,y) location.
1923 % o exception: return any errors or warnings in this structure.
1926 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1927 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1928 PixelInfo *pixel,ExceptionInfo *exception)
1931 *restrict cache_info;
1934 id = GetOpenMPThreadId();
1936 register const Quantum
1939 assert(image != (const Image *) NULL);
1940 assert(image->signature == MagickSignature);
1941 assert(image->cache != (Cache) NULL);
1942 cache_info=(CacheInfo *) image->cache;
1943 assert(cache_info->signature == MagickSignature);
1944 assert(id < (int) cache_info->number_threads);
1945 GetPixelInfo(image,pixel);
1946 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1947 cache_info->nexus_info[id],exception);
1948 if (p == (const Quantum *) NULL)
1949 return(MagickFalse);
1950 GetPixelInfoPixel(image,p,pixel);
1955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1959 + G e t P i x e l C a c h e C o l o r s p a c e %
1963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1967 % The format of the GetPixelCacheColorspace() method is:
1969 % Colorspace GetPixelCacheColorspace(Cache cache)
1971 % A description of each parameter follows:
1973 % o cache: the pixel cache.
1976 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1979 *restrict cache_info;
1981 assert(cache != (Cache) NULL);
1982 cache_info=(CacheInfo *) cache;
1983 assert(cache_info->signature == MagickSignature);
1984 if (cache_info->debug != MagickFalse)
1985 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1986 cache_info->filename);
1987 return(cache_info->colorspace);
1991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1995 + G e t P i x e l C a c h e M e t h o d s %
1999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2001 % GetPixelCacheMethods() initializes the CacheMethods structure.
2003 % The format of the GetPixelCacheMethods() method is:
2005 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2007 % A description of each parameter follows:
2009 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2012 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2014 assert(cache_methods != (CacheMethods *) NULL);
2015 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2016 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2017 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2018 cache_methods->get_virtual_metacontent_from_handler=
2019 GetVirtualMetacontentFromCache;
2020 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2021 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2022 cache_methods->get_authentic_metacontent_from_handler=
2023 GetAuthenticMetacontentFromCache;
2024 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2025 cache_methods->get_one_authentic_pixel_from_handler=
2026 GetOneAuthenticPixelFromCache;
2027 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2028 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2029 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2037 + G e t P i x e l C a c h e N e x u s E x t e n t %
2041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2044 % corresponding with the last call to SetPixelCacheNexusPixels() or
2045 % GetPixelCacheNexusPixels().
2047 % The format of the GetPixelCacheNexusExtent() method is:
2049 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2050 % NexusInfo *nexus_info)
2052 % A description of each parameter follows:
2054 % o nexus_info: the nexus info.
2057 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2058 NexusInfo *restrict nexus_info)
2061 *restrict cache_info;
2066 assert(cache != NULL);
2067 cache_info=(CacheInfo *) cache;
2068 assert(cache_info->signature == MagickSignature);
2069 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2071 return((MagickSizeType) cache_info->columns*cache_info->rows);
2076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2080 + G e t P i x e l C a c h e P i x e l s %
2084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2086 % GetPixelCachePixels() returns the pixels associated with the specified image.
2088 % The format of the GetPixelCachePixels() method is:
2090 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2091 % ExceptionInfo *exception)
2093 % A description of each parameter follows:
2095 % o image: the image.
2097 % o length: the pixel cache length.
2099 % o exception: return any errors or warnings in this structure.
2102 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2103 ExceptionInfo *exception)
2106 *restrict cache_info;
2108 assert(image != (const Image *) NULL);
2109 assert(image->signature == MagickSignature);
2110 assert(image->cache != (Cache) NULL);
2111 assert(length != (MagickSizeType *) NULL);
2112 assert(exception != (ExceptionInfo *) NULL);
2113 assert(exception->signature == MagickSignature);
2114 cache_info=(CacheInfo *) image->cache;
2115 assert(cache_info->signature == MagickSignature);
2117 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2118 return((void *) NULL);
2119 *length=cache_info->length;
2120 return((void *) cache_info->pixels);
2124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2128 + 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 %
2132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2134 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2136 % The format of the GetPixelCacheStorageClass() method is:
2138 % ClassType GetPixelCacheStorageClass(Cache cache)
2140 % A description of each parameter follows:
2142 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2144 % o cache: the pixel cache.
2147 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2150 *restrict cache_info;
2152 assert(cache != (Cache) NULL);
2153 cache_info=(CacheInfo *) cache;
2154 assert(cache_info->signature == MagickSignature);
2155 if (cache_info->debug != MagickFalse)
2156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2157 cache_info->filename);
2158 return(cache_info->storage_class);
2162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166 + G e t P i x e l C a c h e T i l e S i z e %
2170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2172 % GetPixelCacheTileSize() returns the pixel cache tile size.
2174 % The format of the GetPixelCacheTileSize() method is:
2176 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2179 % A description of each parameter follows:
2181 % o image: the image.
2183 % o width: the optimize cache tile width in pixels.
2185 % o height: the optimize cache tile height in pixels.
2188 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2192 *restrict cache_info;
2194 assert(image != (Image *) NULL);
2195 assert(image->signature == MagickSignature);
2196 if (image->debug != MagickFalse)
2197 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2198 cache_info=(CacheInfo *) image->cache;
2199 assert(cache_info->signature == MagickSignature);
2200 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2201 if (GetImagePixelCacheType(image) == DiskCache)
2202 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2211 + 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 %
2215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2217 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2218 % pixel cache. A virtual pixel is any pixel access that is outside the
2219 % boundaries of the image cache.
2221 % The format of the GetPixelCacheVirtualMethod() method is:
2223 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2225 % A description of each parameter follows:
2227 % o image: the image.
2230 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2233 *restrict cache_info;
2235 assert(image != (Image *) NULL);
2236 assert(image->signature == MagickSignature);
2237 assert(image->cache != (Cache) NULL);
2238 cache_info=(CacheInfo *) image->cache;
2239 assert(cache_info->signature == MagickSignature);
2240 return(cache_info->virtual_pixel_method);
2244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2248 + 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 %
2252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2254 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2255 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2257 % The format of the GetVirtualMetacontentFromCache() method is:
2259 % void *GetVirtualMetacontentFromCache(const Image *image)
2261 % A description of each parameter follows:
2263 % o image: the image.
2266 static const void *GetVirtualMetacontentFromCache(const Image *image)
2269 *restrict cache_info;
2272 id = GetOpenMPThreadId();
2275 *restrict metacontent;
2277 assert(image != (const Image *) NULL);
2278 assert(image->signature == MagickSignature);
2279 assert(image->cache != (Cache) NULL);
2280 cache_info=(CacheInfo *) image->cache;
2281 assert(cache_info->signature == MagickSignature);
2282 assert(id < (int) cache_info->number_threads);
2283 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2284 cache_info->nexus_info[id]);
2285 return(metacontent);
2289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2293 + 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 %
2297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2299 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2302 % The format of the GetVirtualMetacontentFromNexus() method is:
2304 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2305 % NexusInfo *nexus_info)
2307 % A description of each parameter follows:
2309 % o cache: the pixel cache.
2311 % o nexus_info: the cache nexus to return the meta-content.
2314 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2315 NexusInfo *restrict nexus_info)
2318 *restrict cache_info;
2320 assert(cache != (Cache) NULL);
2321 cache_info=(CacheInfo *) cache;
2322 assert(cache_info->signature == MagickSignature);
2323 if (cache_info->storage_class == UndefinedClass)
2324 return((void *) NULL);
2325 return(nexus_info->metacontent);
2329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2333 % G e t V i r t u a l M e t a c o n t e n t %
2337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2339 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2340 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2341 % returned if the meta-content are not available.
2343 % The format of the GetVirtualMetacontent() method is:
2345 % const void *GetVirtualMetacontent(const Image *image)
2347 % A description of each parameter follows:
2349 % o image: the image.
2352 MagickExport const void *GetVirtualMetacontent(const Image *image)
2355 *restrict cache_info;
2358 id = GetOpenMPThreadId();
2361 *restrict metacontent;
2363 assert(image != (const Image *) NULL);
2364 assert(image->signature == MagickSignature);
2365 assert(image->cache != (Cache) NULL);
2366 cache_info=(CacheInfo *) image->cache;
2367 assert(cache_info->signature == MagickSignature);
2368 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2369 if (metacontent != (void *) NULL)
2370 return(metacontent);
2371 assert(id < (int) cache_info->number_threads);
2372 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2373 cache_info->nexus_info[id]);
2374 return(metacontent);
2378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2382 + 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 %
2386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2389 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2390 % is returned if the pixels are transferred, otherwise a NULL is returned.
2392 % The format of the GetVirtualPixelsFromNexus() method is:
2394 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2395 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2396 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2397 % ExceptionInfo *exception)
2399 % A description of each parameter follows:
2401 % o image: the image.
2403 % o virtual_pixel_method: the virtual pixel method.
2405 % o x,y,columns,rows: These values define the perimeter of a region of
2408 % o nexus_info: the cache nexus to acquire.
2410 % o exception: return any errors or warnings in this structure.
2417 0, 48, 12, 60, 3, 51, 15, 63,
2418 32, 16, 44, 28, 35, 19, 47, 31,
2419 8, 56, 4, 52, 11, 59, 7, 55,
2420 40, 24, 36, 20, 43, 27, 39, 23,
2421 2, 50, 14, 62, 1, 49, 13, 61,
2422 34, 18, 46, 30, 33, 17, 45, 29,
2423 10, 58, 6, 54, 9, 57, 5, 53,
2424 42, 26, 38, 22, 41, 25, 37, 21
2427 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2432 index=x+DitherMatrix[x & 0x07]-32L;
2435 if (index >= (ssize_t) columns)
2436 return((ssize_t) columns-1L);
2440 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2445 index=y+DitherMatrix[y & 0x07]-32L;
2448 if (index >= (ssize_t) rows)
2449 return((ssize_t) rows-1L);
2453 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2457 if (x >= (ssize_t) columns)
2458 return((ssize_t) (columns-1));
2462 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2466 if (y >= (ssize_t) rows)
2467 return((ssize_t) (rows-1));
2471 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2473 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2476 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2478 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2481 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2482 const size_t extent)
2488 Compute the remainder of dividing offset by extent. It returns not only
2489 the quotient (tile the offset falls in) but also the positive remainer
2490 within that tile such that 0 <= remainder < extent. This method is
2491 essentially a ldiv() using a floored modulo division rather than the
2492 normal default truncated modulo division.
2494 modulo.quotient=offset/(ssize_t) extent;
2497 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2501 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2502 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2503 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2504 ExceptionInfo *exception)
2507 *restrict cache_info;
2517 **restrict virtual_nexus;
2521 virtual_pixel[MaxPixelChannels];
2526 register const Quantum
2539 register unsigned char
2546 *restrict virtual_metacontent;
2551 assert(image != (const Image *) NULL);
2552 assert(image->signature == MagickSignature);
2553 assert(image->cache != (Cache) NULL);
2554 cache_info=(CacheInfo *) image->cache;
2555 assert(cache_info->signature == MagickSignature);
2556 if (cache_info->type == UndefinedCache)
2557 return((const Quantum *) NULL);
2560 region.width=columns;
2562 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2564 if (pixels == (Quantum *) NULL)
2565 return((const Quantum *) NULL);
2567 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2568 nexus_info->region.x;
2569 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2570 nexus_info->region.width-1L;
2571 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2572 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2573 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2574 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2580 Pixel request is inside cache extents.
2582 if (nexus_info->authentic_pixel_cache != MagickFalse)
2584 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2585 if (status == MagickFalse)
2586 return((const Quantum *) NULL);
2587 if (cache_info->metacontent_extent != 0)
2589 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2590 if (status == MagickFalse)
2591 return((const Quantum *) NULL);
2596 Pixel request is outside cache extents.
2598 s=(unsigned char *) nexus_info->metacontent;
2599 virtual_nexus=AcquirePixelCacheNexus(1);
2600 if (virtual_nexus == (NexusInfo **) NULL)
2602 if (virtual_nexus != (NexusInfo **) NULL)
2603 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2604 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2605 "UnableToGetCacheNexus","`%s'",image->filename);
2606 return((const Quantum *) NULL);
2608 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2609 sizeof(*virtual_pixel));
2610 virtual_metacontent=(void *) NULL;
2611 switch (virtual_pixel_method)
2613 case BackgroundVirtualPixelMethod:
2614 case BlackVirtualPixelMethod:
2615 case GrayVirtualPixelMethod:
2616 case TransparentVirtualPixelMethod:
2617 case MaskVirtualPixelMethod:
2618 case WhiteVirtualPixelMethod:
2619 case EdgeVirtualPixelMethod:
2620 case CheckerTileVirtualPixelMethod:
2621 case HorizontalTileVirtualPixelMethod:
2622 case VerticalTileVirtualPixelMethod:
2624 if (cache_info->metacontent_extent != 0)
2627 Acquire a metacontent buffer.
2629 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2630 cache_info->metacontent_extent);
2631 if (virtual_metacontent == (void *) NULL)
2633 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2634 (void) ThrowMagickException(exception,GetMagickModule(),
2635 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2636 return((const Quantum *) NULL);
2638 (void) ResetMagickMemory(virtual_metacontent,0,
2639 cache_info->metacontent_extent);
2641 switch (virtual_pixel_method)
2643 case BlackVirtualPixelMethod:
2645 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2646 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2647 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2650 case GrayVirtualPixelMethod:
2652 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2653 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2655 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2658 case TransparentVirtualPixelMethod:
2660 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2661 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2662 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2665 case MaskVirtualPixelMethod:
2666 case WhiteVirtualPixelMethod:
2668 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2669 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2670 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2675 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2677 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2679 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2681 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2683 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2693 for (v=0; v < (ssize_t) rows; v++)
2699 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2700 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2701 y_offset=EdgeY(y_offset,cache_info->rows);
2702 for (u=0; u < (ssize_t) columns; u+=length)
2708 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2709 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2710 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2718 Transfer a single pixel.
2720 length=(MagickSizeType) 1;
2721 switch (virtual_pixel_method)
2723 case EdgeVirtualPixelMethod:
2726 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2727 EdgeX(x_offset,cache_info->columns),
2728 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2730 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2733 case RandomVirtualPixelMethod:
2735 if (cache_info->random_info == (RandomInfo *) NULL)
2736 cache_info->random_info=AcquireRandomInfo();
2737 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2738 RandomX(cache_info->random_info,cache_info->columns),
2739 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2740 *virtual_nexus,exception);
2741 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2744 case DitherVirtualPixelMethod:
2746 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2747 DitherX(x_offset,cache_info->columns),
2748 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2750 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2753 case TileVirtualPixelMethod:
2755 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2756 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2757 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2758 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2760 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2763 case MirrorVirtualPixelMethod:
2765 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2766 if ((x_modulo.quotient & 0x01) == 1L)
2767 x_modulo.remainder=(ssize_t) cache_info->columns-
2768 x_modulo.remainder-1L;
2769 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2770 if ((y_modulo.quotient & 0x01) == 1L)
2771 y_modulo.remainder=(ssize_t) cache_info->rows-
2772 y_modulo.remainder-1L;
2773 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2774 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2776 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2779 case HorizontalTileEdgeVirtualPixelMethod:
2781 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2782 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2783 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2784 *virtual_nexus,exception);
2785 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2788 case VerticalTileEdgeVirtualPixelMethod:
2790 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2791 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2792 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2793 *virtual_nexus,exception);
2794 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2797 case BackgroundVirtualPixelMethod:
2798 case BlackVirtualPixelMethod:
2799 case GrayVirtualPixelMethod:
2800 case TransparentVirtualPixelMethod:
2801 case MaskVirtualPixelMethod:
2802 case WhiteVirtualPixelMethod:
2805 r=virtual_metacontent;
2808 case CheckerTileVirtualPixelMethod:
2810 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2811 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2812 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2815 r=virtual_metacontent;
2818 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2819 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2821 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2824 case HorizontalTileVirtualPixelMethod:
2826 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2829 r=virtual_metacontent;
2832 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2833 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2834 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2835 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2837 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2840 case VerticalTileVirtualPixelMethod:
2842 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2845 r=virtual_metacontent;
2848 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2849 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2850 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2851 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2853 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2857 if (p == (const Quantum *) NULL)
2859 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2861 q+=cache_info->number_channels;
2862 if ((s != (void *) NULL) && (r != (const void *) NULL))
2864 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2865 s+=cache_info->metacontent_extent;
2870 Transfer a run of pixels.
2872 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2873 (size_t) length,1UL,*virtual_nexus,exception);
2874 if (p == (const Quantum *) NULL)
2876 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2877 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2878 q+=length*cache_info->number_channels;
2879 if ((r != (void *) NULL) && (s != (const void *) NULL))
2881 (void) memcpy(s,r,(size_t) length);
2882 s+=length*cache_info->metacontent_extent;
2889 if (virtual_metacontent != (void *) NULL)
2890 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2891 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2900 + G e t V i r t u a l P i x e l C a c h e %
2904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2906 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2907 % cache as defined by the geometry parameters. A pointer to the pixels
2908 % is returned if the pixels are transferred, otherwise a NULL is returned.
2910 % The format of the GetVirtualPixelCache() method is:
2912 % const Quantum *GetVirtualPixelCache(const Image *image,
2913 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2914 % const ssize_t y,const size_t columns,const size_t rows,
2915 % ExceptionInfo *exception)
2917 % A description of each parameter follows:
2919 % o image: the image.
2921 % o virtual_pixel_method: the virtual pixel method.
2923 % o x,y,columns,rows: These values define the perimeter of a region of
2926 % o exception: return any errors or warnings in this structure.
2929 static const Quantum *GetVirtualPixelCache(const Image *image,
2930 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2931 const size_t columns,const size_t rows,ExceptionInfo *exception)
2934 *restrict cache_info;
2937 id = GetOpenMPThreadId();
2942 assert(image != (const Image *) NULL);
2943 assert(image->signature == MagickSignature);
2944 assert(image->cache != (Cache) NULL);
2945 cache_info=(CacheInfo *) image->cache;
2946 assert(cache_info->signature == MagickSignature);
2947 assert(id < (int) cache_info->number_threads);
2948 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2949 cache_info->nexus_info[id],exception);
2954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2958 % G e t V i r t u a l P i x e l Q u e u e %
2962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2965 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2967 % The format of the GetVirtualPixelQueue() method is:
2969 % const Quantum *GetVirtualPixelQueue(const Image image)
2971 % A description of each parameter follows:
2973 % o image: the image.
2976 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2979 *restrict cache_info;
2982 id = GetOpenMPThreadId();
2984 assert(image != (const Image *) NULL);
2985 assert(image->signature == MagickSignature);
2986 assert(image->cache != (Cache) NULL);
2987 cache_info=(CacheInfo *) image->cache;
2988 assert(cache_info->signature == MagickSignature);
2989 if (cache_info->methods.get_virtual_pixels_handler !=
2990 (GetVirtualPixelsHandler) NULL)
2991 return(cache_info->methods.get_virtual_pixels_handler(image));
2992 assert(id < (int) cache_info->number_threads);
2993 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001 % G e t V i r t u a l P i x e l s %
3005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007 % GetVirtualPixels() returns an immutable pixel region. If the
3008 % region is successfully accessed, a pointer to it is returned, otherwise
3009 % NULL is returned. The returned pointer may point to a temporary working
3010 % copy of the pixels or it may point to the original pixels in memory.
3011 % Performance is maximized if the selected region is part of one row, or one
3012 % or more full rows, since there is opportunity to access the pixels in-place
3013 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3014 % returned pointer must *never* be deallocated by the user.
3016 % Pixels accessed via the returned pointer represent a simple array of type
3017 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3018 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3019 % access the meta-content (of type void) corresponding to the the
3022 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3024 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3025 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3026 % GetCacheViewAuthenticPixels() instead.
3028 % The format of the GetVirtualPixels() method is:
3030 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3031 % const ssize_t y,const size_t columns,const size_t rows,
3032 % ExceptionInfo *exception)
3034 % A description of each parameter follows:
3036 % o image: the image.
3038 % o x,y,columns,rows: These values define the perimeter of a region of
3041 % o exception: return any errors or warnings in this structure.
3044 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3045 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3046 ExceptionInfo *exception)
3049 *restrict cache_info;
3052 id = GetOpenMPThreadId();
3057 assert(image != (const Image *) NULL);
3058 assert(image->signature == MagickSignature);
3059 assert(image->cache != (Cache) NULL);
3060 cache_info=(CacheInfo *) image->cache;
3061 assert(cache_info->signature == MagickSignature);
3062 if (cache_info->methods.get_virtual_pixel_handler !=
3063 (GetVirtualPixelHandler) NULL)
3064 return(cache_info->methods.get_virtual_pixel_handler(image,
3065 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3066 assert(id < (int) cache_info->number_threads);
3067 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3068 columns,rows,cache_info->nexus_info[id],exception);
3073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3077 + 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 %
3081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3083 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3084 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3086 % The format of the GetVirtualPixelsCache() method is:
3088 % Quantum *GetVirtualPixelsCache(const Image *image)
3090 % A description of each parameter follows:
3092 % o image: the image.
3095 static const Quantum *GetVirtualPixelsCache(const Image *image)
3098 *restrict cache_info;
3101 id = GetOpenMPThreadId();
3103 assert(image != (const Image *) NULL);
3104 assert(image->signature == MagickSignature);
3105 assert(image->cache != (Cache) NULL);
3106 cache_info=(CacheInfo *) image->cache;
3107 assert(cache_info->signature == MagickSignature);
3108 assert(id < (int) cache_info->number_threads);
3109 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3117 + G e t V i r t u a l P i x e l s N e x u s %
3121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3123 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3126 % The format of the GetVirtualPixelsNexus() method is:
3128 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3129 % NexusInfo *nexus_info)
3131 % A description of each parameter follows:
3133 % o cache: the pixel cache.
3135 % o nexus_info: the cache nexus to return the colormap pixels.
3138 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3139 NexusInfo *restrict nexus_info)
3142 *restrict cache_info;
3144 assert(cache != (Cache) NULL);
3145 cache_info=(CacheInfo *) cache;
3146 assert(cache_info->signature == MagickSignature);
3147 if (cache_info->storage_class == UndefinedClass)
3148 return((Quantum *) NULL);
3149 return((const Quantum *) nexus_info->pixels);
3153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3157 + O p e n P i x e l C a c h e %
3161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3163 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3164 % dimensions, allocating space for the image pixels and optionally the
3165 % metacontent, and memory mapping the cache if it is disk based. The cache
3166 % nexus array is initialized as well.
3168 % The format of the OpenPixelCache() method is:
3170 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3171 % ExceptionInfo *exception)
3173 % A description of each parameter follows:
3175 % o image: the image.
3177 % o mode: ReadMode, WriteMode, or IOMode.
3179 % o exception: return any errors or warnings in this structure.
3183 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3185 cache_info->mapped=MagickFalse;
3186 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3187 (size_t) cache_info->length));
3188 if (cache_info->pixels == (Quantum *) NULL)
3190 cache_info->mapped=MagickTrue;
3191 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3192 cache_info->length);
3196 #if defined(__cplusplus) || defined(c_plusplus)
3201 static void CacheSignalHandler(int status)
3203 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3207 #if defined(__cplusplus) || defined(c_plusplus)
3211 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3218 Open pixel cache on disk.
3220 if (cache_info->file != -1)
3221 return(MagickTrue); /* cache already open */
3222 if (*cache_info->cache_filename == '\0')
3223 file=AcquireUniqueFileResource(cache_info->cache_filename);
3229 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3234 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3235 O_BINARY | O_EXCL,S_MODE);
3237 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3243 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3246 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3251 return(MagickFalse);
3252 (void) AcquireMagickResource(FileResource,1);
3253 cache_info->file=file;
3254 cache_info->mode=mode;
3258 static inline MagickOffsetType WritePixelCacheRegion(
3259 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3260 const MagickSizeType length,const unsigned char *restrict buffer)
3262 register MagickOffsetType
3268 #if !defined(MAGICKCORE_HAVE_PWRITE)
3269 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3270 return((MagickOffsetType) -1);
3273 for (i=0; i < (MagickOffsetType) length; i+=count)
3275 #if !defined(MAGICKCORE_HAVE_PWRITE)
3276 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3277 (MagickSizeType) SSIZE_MAX));
3279 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3280 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3292 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3295 *restrict cache_info;
3302 cache_info=(CacheInfo *) image->cache;
3303 if (image->debug != MagickFalse)
3306 format[MaxTextExtent],
3307 message[MaxTextExtent];
3309 (void) FormatMagickSize(length,MagickFalse,format);
3310 (void) FormatLocaleString(message,MaxTextExtent,
3311 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3312 cache_info->cache_filename,cache_info->file,format);
3313 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3315 if (length != (MagickSizeType) ((MagickOffsetType) length))
3316 return(MagickFalse);
3317 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3319 return(MagickFalse);
3320 if ((MagickSizeType) offset >= length)
3322 extent=(MagickOffsetType) length-1;
3323 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3324 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3325 if (cache_info->synchronize != MagickFalse)
3330 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3332 return(MagickFalse);
3336 (void) signal(SIGBUS,CacheSignalHandler);
3338 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3341 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3342 ExceptionInfo *exception)
3345 *restrict cache_info,
3349 format[MaxTextExtent],
3350 message[MaxTextExtent];
3366 assert(image != (const Image *) NULL);
3367 assert(image->signature == MagickSignature);
3368 assert(image->cache != (Cache) NULL);
3369 if (image->debug != MagickFalse)
3370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3371 if ((image->columns == 0) || (image->rows == 0))
3372 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3373 cache_info=(CacheInfo *) image->cache;
3374 assert(cache_info->signature == MagickSignature);
3375 source_info=(*cache_info);
3376 source_info.file=(-1);
3377 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3378 image->filename,(double) GetImageIndexInList(image));
3379 cache_info->storage_class=image->storage_class;
3380 cache_info->colorspace=image->colorspace;
3381 cache_info->alpha_trait=image->alpha_trait;
3382 cache_info->read_mask=image->read_mask;
3383 cache_info->write_mask=image->write_mask;
3384 cache_info->rows=image->rows;
3385 cache_info->columns=image->columns;
3386 InitializePixelChannelMap(image);
3387 cache_info->number_channels=GetPixelChannels(image);
3388 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3389 sizeof(*image->channel_map));
3390 cache_info->metacontent_extent=image->metacontent_extent;
3391 cache_info->mode=mode;
3392 if (image->ping != MagickFalse)
3394 cache_info->type=PingCache;
3395 cache_info->pixels=(Quantum *) NULL;
3396 cache_info->metacontent=(void *) NULL;
3397 cache_info->length=0;
3400 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3401 packet_size=cache_info->number_channels*sizeof(Quantum);
3402 if (image->metacontent_extent != 0)
3403 packet_size+=cache_info->metacontent_extent;
3404 length=number_pixels*packet_size;
3405 columns=(size_t) (length/cache_info->rows/packet_size);
3406 if (cache_info->columns != columns)
3407 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3409 cache_info->length=length;
3410 status=AcquireMagickResource(AreaResource,cache_info->length);
3411 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3412 cache_info->metacontent_extent);
3413 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3415 status=AcquireMagickResource(MemoryResource,cache_info->length);
3416 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3417 (cache_info->type == MemoryCache))
3419 AllocatePixelCachePixels(cache_info);
3420 if (cache_info->pixels == (Quantum *) NULL)
3421 cache_info->pixels=source_info.pixels;
3425 Create memory pixel cache.
3428 cache_info->type=MemoryCache;
3429 cache_info->metacontent=(void *) NULL;
3430 if (cache_info->metacontent_extent != 0)
3431 cache_info->metacontent=(void *) (cache_info->pixels+
3432 number_pixels*cache_info->number_channels);
3433 if ((source_info.storage_class != UndefinedClass) &&
3436 status=ClonePixelCacheRepository(cache_info,&source_info,
3438 RelinquishPixelCachePixels(&source_info);
3440 if (image->debug != MagickFalse)
3442 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3443 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3445 (void) FormatLocaleString(message,MaxTextExtent,
3446 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3447 cache_info->filename,cache_info->mapped != MagickFalse ?
3448 "Anonymous" : "Heap",type,(double) cache_info->columns,
3449 (double) cache_info->rows,(double)
3450 cache_info->number_channels,format);
3451 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3457 RelinquishMagickResource(MemoryResource,cache_info->length);
3460 Create pixel cache on disk.
3462 status=AcquireMagickResource(DiskResource,cache_info->length);
3463 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3468 if (cache_info->type == DistributedCache)
3469 RelinquishMagickResource(DiskResource,cache_info->length);
3470 server_info=AcquireDistributeCacheInfo(exception);
3471 if (server_info != (DistributeCacheInfo *) NULL)
3473 status=OpenDistributePixelCache(server_info,image);
3474 if (status == MagickFalse)
3476 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3477 GetDistributeCacheHostname(server_info));
3478 server_info=DestroyDistributeCacheInfo(server_info);
3483 Create a distributed pixel cache.
3485 cache_info->type=DistributedCache;
3486 cache_info->server_info=server_info;
3487 (void) FormatLocaleString(cache_info->cache_filename,
3488 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3489 (DistributeCacheInfo *) cache_info->server_info),
3490 GetDistributeCachePort((DistributeCacheInfo *)
3491 cache_info->server_info));
3492 if ((source_info.storage_class != UndefinedClass) &&
3495 status=ClonePixelCacheRepository(cache_info,&source_info,
3497 RelinquishPixelCachePixels(&source_info);
3499 if (image->debug != MagickFalse)
3501 (void) FormatMagickSize(cache_info->length,MagickFalse,
3503 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3505 (void) FormatLocaleString(message,MaxTextExtent,
3506 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3507 cache_info->filename,cache_info->cache_filename,
3508 GetDistributeCacheFile((DistributeCacheInfo *)
3509 cache_info->server_info),type,(double) cache_info->columns,
3510 (double) cache_info->rows,(double)
3511 cache_info->number_channels,format);
3512 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3518 RelinquishMagickResource(DiskResource,cache_info->length);
3519 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3520 "CacheResourcesExhausted","`%s'",image->filename);
3521 return(MagickFalse);
3523 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3525 (void) ClosePixelCacheOnDisk(cache_info);
3526 *cache_info->cache_filename='\0';
3528 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3530 RelinquishMagickResource(DiskResource,cache_info->length);
3531 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3533 return(MagickFalse);
3535 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3536 cache_info->length);
3537 if (status == MagickFalse)
3539 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3541 return(MagickFalse);
3543 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3544 cache_info->metacontent_extent);
3545 if (length != (MagickSizeType) ((size_t) length))
3546 cache_info->type=DiskCache;
3549 status=AcquireMagickResource(MapResource,cache_info->length);
3550 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3551 (cache_info->type != MemoryCache))
3552 cache_info->type=DiskCache;
3555 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3556 cache_info->offset,(size_t) cache_info->length);
3557 if (cache_info->pixels == (Quantum *) NULL)
3559 cache_info->type=DiskCache;
3560 cache_info->pixels=source_info.pixels;
3565 Create file-backed memory-mapped pixel cache.
3568 (void) ClosePixelCacheOnDisk(cache_info);
3569 cache_info->type=MapCache;
3570 cache_info->mapped=MagickTrue;
3571 cache_info->metacontent=(void *) NULL;
3572 if (cache_info->metacontent_extent != 0)
3573 cache_info->metacontent=(void *) (cache_info->pixels+
3574 number_pixels*cache_info->number_channels);
3575 if ((source_info.storage_class != UndefinedClass) &&
3578 status=ClonePixelCacheRepository(cache_info,&source_info,
3580 RelinquishPixelCachePixels(&source_info);
3582 if (image->debug != MagickFalse)
3584 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3585 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3587 (void) FormatLocaleString(message,MaxTextExtent,
3588 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3589 cache_info->filename,cache_info->cache_filename,
3590 cache_info->file,type,(double) cache_info->columns,(double)
3591 cache_info->rows,(double) cache_info->number_channels,
3593 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3599 RelinquishMagickResource(MapResource,cache_info->length);
3602 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3604 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3605 RelinquishPixelCachePixels(&source_info);
3607 if (image->debug != MagickFalse)
3609 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3610 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3612 (void) FormatLocaleString(message,MaxTextExtent,
3613 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3614 cache_info->cache_filename,cache_info->file,type,(double)
3615 cache_info->columns,(double) cache_info->rows,(double)
3616 cache_info->number_channels,format);
3617 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3627 + P e r s i s t P i x e l C a c h e %
3631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3633 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3634 % persistent pixel cache is one that resides on disk and is not destroyed
3635 % when the program exits.
3637 % The format of the PersistPixelCache() method is:
3639 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3640 % const MagickBooleanType attach,MagickOffsetType *offset,
3641 % ExceptionInfo *exception)
3643 % A description of each parameter follows:
3645 % o image: the image.
3647 % o filename: the persistent pixel cache filename.
3649 % o attach: A value other than zero initializes the persistent pixel cache.
3651 % o initialize: A value other than zero initializes the persistent pixel
3654 % o offset: the offset in the persistent cache to store pixels.
3656 % o exception: return any errors or warnings in this structure.
3659 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3660 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3661 ExceptionInfo *exception)
3664 *restrict cache_info,
3665 *restrict clone_info;
3676 assert(image != (Image *) NULL);
3677 assert(image->signature == MagickSignature);
3678 if (image->debug != MagickFalse)
3679 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3680 assert(image->cache != (void *) NULL);
3681 assert(filename != (const char *) NULL);
3682 assert(offset != (MagickOffsetType *) NULL);
3683 page_size=GetMagickPageSize();
3684 cache_info=(CacheInfo *) image->cache;
3685 assert(cache_info->signature == MagickSignature);
3686 if (attach != MagickFalse)
3689 Attach existing persistent pixel cache.
3691 if (image->debug != MagickFalse)
3692 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3693 "attach persistent cache");
3694 (void) CopyMagickString(cache_info->cache_filename,filename,
3696 cache_info->type=DiskCache;
3697 cache_info->offset=(*offset);
3698 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3699 return(MagickFalse);
3700 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3703 if ((cache_info->mode != ReadMode) &&
3704 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3705 (cache_info->reference_count == 1))
3707 LockSemaphoreInfo(cache_info->semaphore);
3708 if ((cache_info->mode != ReadMode) &&
3709 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3710 (cache_info->reference_count == 1))
3716 Usurp existing persistent pixel cache.
3718 status=rename_utf8(cache_info->cache_filename,filename);
3721 (void) CopyMagickString(cache_info->cache_filename,filename,
3723 *offset+=cache_info->length+page_size-(cache_info->length %
3725 UnlockSemaphoreInfo(cache_info->semaphore);
3726 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3727 if (image->debug != MagickFalse)
3728 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3729 "Usurp resident persistent cache");
3733 UnlockSemaphoreInfo(cache_info->semaphore);
3736 Clone persistent pixel cache.
3738 clone_image=(*image);
3739 clone_info=(CacheInfo *) clone_image.cache;
3740 image->cache=ClonePixelCache(cache_info);
3741 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3742 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3743 cache_info->type=DiskCache;
3744 cache_info->offset=(*offset);
3745 cache_info=(CacheInfo *) image->cache;
3746 status=OpenPixelCache(image,IOMode,exception);
3747 if (status != MagickFalse)
3748 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3749 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3750 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3759 + 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 %
3763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3766 % defined by the region rectangle and returns a pointer to the region. This
3767 % region is subsequently transferred from the pixel cache with
3768 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3769 % pixels are transferred, otherwise a NULL is returned.
3771 % The format of the QueueAuthenticPixelCacheNexus() method is:
3773 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3774 % const ssize_t y,const size_t columns,const size_t rows,
3775 % const MagickBooleanType clone,NexusInfo *nexus_info,
3776 % ExceptionInfo *exception)
3778 % A description of each parameter follows:
3780 % o image: the image.
3782 % o x,y,columns,rows: These values define the perimeter of a region of
3785 % o nexus_info: the cache nexus to set.
3787 % o clone: clone the pixel cache.
3789 % o exception: return any errors or warnings in this structure.
3792 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3793 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3794 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3797 *restrict cache_info;
3812 Validate pixel cache geometry.
3814 assert(image != (const Image *) NULL);
3815 assert(image->signature == MagickSignature);
3816 assert(image->cache != (Cache) NULL);
3817 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3818 if (cache_info == (Cache) NULL)
3819 return((Quantum *) NULL);
3820 assert(cache_info->signature == MagickSignature);
3821 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3822 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3823 (y >= (ssize_t) cache_info->rows))
3825 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3826 "PixelsAreNotAuthentic","`%s'",image->filename);
3827 return((Quantum *) NULL);
3829 offset=(MagickOffsetType) y*cache_info->columns+x;
3831 return((Quantum *) NULL);
3832 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3833 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3834 if ((MagickSizeType) offset >= number_pixels)
3835 return((Quantum *) NULL);
3841 region.width=columns;
3843 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3853 + 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 %
3857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3859 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3860 % defined by the region rectangle and returns a pointer to the region. This
3861 % region is subsequently transferred from the pixel cache with
3862 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3863 % pixels are transferred, otherwise a NULL is returned.
3865 % The format of the QueueAuthenticPixelsCache() method is:
3867 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3868 % const ssize_t y,const size_t columns,const size_t rows,
3869 % ExceptionInfo *exception)
3871 % A description of each parameter follows:
3873 % o image: the image.
3875 % o x,y,columns,rows: These values define the perimeter of a region of
3878 % o exception: return any errors or warnings in this structure.
3881 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3882 const ssize_t y,const size_t columns,const size_t rows,
3883 ExceptionInfo *exception)
3886 *restrict cache_info;
3889 id = GetOpenMPThreadId();
3894 assert(image != (const Image *) NULL);
3895 assert(image->signature == MagickSignature);
3896 assert(image->cache != (Cache) NULL);
3897 cache_info=(CacheInfo *) image->cache;
3898 assert(cache_info->signature == MagickSignature);
3899 assert(id < (int) cache_info->number_threads);
3900 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3901 cache_info->nexus_info[id],exception);
3906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3910 % Q u e u e A u t h e n t i c P i x e l s %
3914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3916 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3917 % successfully initialized a pointer to a Quantum array representing the
3918 % region is returned, otherwise NULL is returned. The returned pointer may
3919 % point to a temporary working buffer for the pixels or it may point to the
3920 % final location of the pixels in memory.
3922 % Write-only access means that any existing pixel values corresponding to
3923 % the region are ignored. This is useful if the initial image is being
3924 % created from scratch, or if the existing pixel values are to be
3925 % completely replaced without need to refer to their pre-existing values.
3926 % The application is free to read and write the pixel buffer returned by
3927 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3928 % initialize the pixel array values. Initializing pixel array values is the
3929 % application's responsibility.
3931 % Performance is maximized if the selected region is part of one row, or
3932 % one or more full rows, since then there is opportunity to access the
3933 % pixels in-place (without a copy) if the image is in memory, or in a
3934 % memory-mapped file. The returned pointer must *never* be deallocated
3937 % Pixels accessed via the returned pointer represent a simple array of type
3938 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3939 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3940 % obtain the meta-content (of type void) corresponding to the region.
3941 % Once the Quantum (and/or Quantum) array has been updated, the
3942 % changes must be saved back to the underlying image using
3943 % SyncAuthenticPixels() or they may be lost.
3945 % The format of the QueueAuthenticPixels() method is:
3947 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3948 % const ssize_t y,const size_t columns,const size_t rows,
3949 % ExceptionInfo *exception)
3951 % A description of each parameter follows:
3953 % o image: the image.
3955 % o x,y,columns,rows: These values define the perimeter of a region of
3958 % o exception: return any errors or warnings in this structure.
3961 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3962 const ssize_t y,const size_t columns,const size_t rows,
3963 ExceptionInfo *exception)
3966 *restrict cache_info;
3969 id = GetOpenMPThreadId();
3974 assert(image != (Image *) NULL);
3975 assert(image->signature == MagickSignature);
3976 assert(image->cache != (Cache) NULL);
3977 cache_info=(CacheInfo *) image->cache;
3978 assert(cache_info->signature == MagickSignature);
3979 if (cache_info->methods.queue_authentic_pixels_handler !=
3980 (QueueAuthenticPixelsHandler) NULL)
3982 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3983 columns,rows,exception);
3986 assert(id < (int) cache_info->number_threads);
3987 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3988 cache_info->nexus_info[id],exception);
3993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3997 + 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 %
4001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4003 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4006 % The format of the ReadPixelCacheMetacontent() method is:
4008 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4009 % NexusInfo *nexus_info,ExceptionInfo *exception)
4011 % A description of each parameter follows:
4013 % o cache_info: the pixel cache.
4015 % o nexus_info: the cache nexus to read the metacontent.
4017 % o exception: return any errors or warnings in this structure.
4021 static inline MagickOffsetType ReadPixelCacheRegion(
4022 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4023 const MagickSizeType length,unsigned char *restrict buffer)
4025 register MagickOffsetType
4031 #if !defined(MAGICKCORE_HAVE_PREAD)
4032 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4033 return((MagickOffsetType) -1);
4036 for (i=0; i < (MagickOffsetType) length; i+=count)
4038 #if !defined(MAGICKCORE_HAVE_PREAD)
4039 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4040 (MagickSizeType) SSIZE_MAX));
4042 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4043 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4055 static MagickBooleanType ReadPixelCacheMetacontent(
4056 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4057 ExceptionInfo *exception)
4070 register unsigned char
4076 if (cache_info->metacontent_extent == 0)
4077 return(MagickFalse);
4078 if (nexus_info->authentic_pixel_cache != MagickFalse)
4080 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4081 nexus_info->region.x;
4082 length=(MagickSizeType) nexus_info->region.width*
4083 cache_info->metacontent_extent;
4084 extent=length*nexus_info->region.height;
4085 rows=nexus_info->region.height;
4087 q=(unsigned char *) nexus_info->metacontent;
4088 switch (cache_info->type)
4093 register unsigned char
4097 Read meta-content from memory.
4099 if ((cache_info->columns == nexus_info->region.width) &&
4100 (extent == (MagickSizeType) ((size_t) extent)))
4105 p=(unsigned char *) cache_info->metacontent+offset*
4106 cache_info->metacontent_extent;
4107 for (y=0; y < (ssize_t) rows; y++)
4109 (void) memcpy(q,p,(size_t) length);
4110 p+=cache_info->metacontent_extent*cache_info->columns;
4111 q+=cache_info->metacontent_extent*nexus_info->region.width;
4118 Read meta content from disk.
4120 LockSemaphoreInfo(cache_info->file_semaphore);
4121 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4123 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4124 cache_info->cache_filename);
4125 UnlockSemaphoreInfo(cache_info->file_semaphore);
4126 return(MagickFalse);
4128 if ((cache_info->columns == nexus_info->region.width) &&
4129 (extent <= MagickMaxBufferExtent))
4134 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4135 for (y=0; y < (ssize_t) rows; y++)
4137 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4138 cache_info->number_channels*sizeof(Quantum)+offset*
4139 cache_info->metacontent_extent,length,(unsigned char *) q);
4140 if (count != (MagickOffsetType) length)
4142 offset+=cache_info->columns;
4143 q+=cache_info->metacontent_extent*nexus_info->region.width;
4145 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4146 (void) ClosePixelCacheOnDisk(cache_info);
4147 UnlockSemaphoreInfo(cache_info->file_semaphore);
4150 case DistributedCache:
4156 Read metacontent from distributed cache.
4158 LockSemaphoreInfo(cache_info->file_semaphore);
4159 region=nexus_info->region;
4160 if ((cache_info->columns != nexus_info->region.width) ||
4161 (extent > MagickMaxBufferExtent))
4168 for (y=0; y < (ssize_t) rows; y++)
4170 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4171 cache_info->server_info,®ion,length,(unsigned char *) q);
4172 if (count != (MagickOffsetType) length)
4174 q+=cache_info->metacontent_extent*nexus_info->region.width;
4177 UnlockSemaphoreInfo(cache_info->file_semaphore);
4183 if (y < (ssize_t) rows)
4185 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4186 cache_info->cache_filename);
4187 return(MagickFalse);
4189 if ((cache_info->debug != MagickFalse) &&
4190 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4191 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4192 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4193 nexus_info->region.width,(double) nexus_info->region.height,(double)
4194 nexus_info->region.x,(double) nexus_info->region.y);
4199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4203 + R e a d P i x e l C a c h e P i x e l s %
4207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4209 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4212 % The format of the ReadPixelCachePixels() method is:
4214 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4215 % NexusInfo *nexus_info,ExceptionInfo *exception)
4217 % A description of each parameter follows:
4219 % o cache_info: the pixel cache.
4221 % o nexus_info: the cache nexus to read the pixels.
4223 % o exception: return any errors or warnings in this structure.
4226 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4227 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4246 if (nexus_info->authentic_pixel_cache != MagickFalse)
4248 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4249 nexus_info->region.x;
4250 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4252 extent=length*nexus_info->region.height;
4253 rows=nexus_info->region.height;
4255 q=nexus_info->pixels;
4256 switch (cache_info->type)
4265 Read pixels from memory.
4267 if ((cache_info->columns == nexus_info->region.width) &&
4268 (extent == (MagickSizeType) ((size_t) extent)))
4273 p=cache_info->pixels+offset*cache_info->number_channels;
4274 for (y=0; y < (ssize_t) rows; y++)
4276 (void) memcpy(q,p,(size_t) length);
4277 p+=cache_info->number_channels*cache_info->columns;
4278 q+=cache_info->number_channels*nexus_info->region.width;
4285 Read pixels from disk.
4287 LockSemaphoreInfo(cache_info->file_semaphore);
4288 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4290 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4291 cache_info->cache_filename);
4292 UnlockSemaphoreInfo(cache_info->file_semaphore);
4293 return(MagickFalse);
4295 if ((cache_info->columns == nexus_info->region.width) &&
4296 (extent <= MagickMaxBufferExtent))
4301 for (y=0; y < (ssize_t) rows; y++)
4303 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4304 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4305 if (count != (MagickOffsetType) length)
4307 offset+=cache_info->columns;
4308 q+=cache_info->number_channels*nexus_info->region.width;
4310 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4311 (void) ClosePixelCacheOnDisk(cache_info);
4312 UnlockSemaphoreInfo(cache_info->file_semaphore);
4315 case DistributedCache:
4321 Read pixels from distributed cache.
4323 LockSemaphoreInfo(cache_info->file_semaphore);
4324 region=nexus_info->region;
4325 if ((cache_info->columns != nexus_info->region.width) ||
4326 (extent > MagickMaxBufferExtent))
4333 for (y=0; y < (ssize_t) rows; y++)
4335 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4336 cache_info->server_info,®ion,length,(unsigned char *) q);
4337 if (count != (MagickOffsetType) length)
4339 q+=cache_info->number_channels*nexus_info->region.width;
4342 UnlockSemaphoreInfo(cache_info->file_semaphore);
4348 if (y < (ssize_t) rows)
4350 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4351 cache_info->cache_filename);
4352 return(MagickFalse);
4354 if ((cache_info->debug != MagickFalse) &&
4355 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4356 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4357 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4358 nexus_info->region.width,(double) nexus_info->region.height,(double)
4359 nexus_info->region.x,(double) nexus_info->region.y);
4364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4368 + R e f e r e n c e P i x e l C a c h e %
4372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4374 % ReferencePixelCache() increments the reference count associated with the
4375 % pixel cache returning a pointer to the cache.
4377 % The format of the ReferencePixelCache method is:
4379 % Cache ReferencePixelCache(Cache cache_info)
4381 % A description of each parameter follows:
4383 % o cache_info: the pixel cache.
4386 MagickPrivate Cache ReferencePixelCache(Cache cache)
4389 *restrict cache_info;
4391 assert(cache != (Cache *) NULL);
4392 cache_info=(CacheInfo *) cache;
4393 assert(cache_info->signature == MagickSignature);
4394 LockSemaphoreInfo(cache_info->semaphore);
4395 cache_info->reference_count++;
4396 UnlockSemaphoreInfo(cache_info->semaphore);
4401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4405 + S e t P i x e l C a c h e M e t h o d s %
4409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4411 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4413 % The format of the SetPixelCacheMethods() method is:
4415 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4417 % A description of each parameter follows:
4419 % o cache: the pixel cache.
4421 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4424 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4427 *restrict cache_info;
4429 GetOneAuthenticPixelFromHandler
4430 get_one_authentic_pixel_from_handler;
4432 GetOneVirtualPixelFromHandler
4433 get_one_virtual_pixel_from_handler;
4436 Set cache pixel methods.
4438 assert(cache != (Cache) NULL);
4439 assert(cache_methods != (CacheMethods *) NULL);
4440 cache_info=(CacheInfo *) cache;
4441 assert(cache_info->signature == MagickSignature);
4442 if (cache_info->debug != MagickFalse)
4443 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4444 cache_info->filename);
4445 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4446 cache_info->methods.get_virtual_pixel_handler=
4447 cache_methods->get_virtual_pixel_handler;
4448 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4449 cache_info->methods.destroy_pixel_handler=
4450 cache_methods->destroy_pixel_handler;
4451 if (cache_methods->get_virtual_metacontent_from_handler !=
4452 (GetVirtualMetacontentFromHandler) NULL)
4453 cache_info->methods.get_virtual_metacontent_from_handler=
4454 cache_methods->get_virtual_metacontent_from_handler;
4455 if (cache_methods->get_authentic_pixels_handler !=
4456 (GetAuthenticPixelsHandler) NULL)
4457 cache_info->methods.get_authentic_pixels_handler=
4458 cache_methods->get_authentic_pixels_handler;
4459 if (cache_methods->queue_authentic_pixels_handler !=
4460 (QueueAuthenticPixelsHandler) NULL)
4461 cache_info->methods.queue_authentic_pixels_handler=
4462 cache_methods->queue_authentic_pixels_handler;
4463 if (cache_methods->sync_authentic_pixels_handler !=
4464 (SyncAuthenticPixelsHandler) NULL)
4465 cache_info->methods.sync_authentic_pixels_handler=
4466 cache_methods->sync_authentic_pixels_handler;
4467 if (cache_methods->get_authentic_pixels_from_handler !=
4468 (GetAuthenticPixelsFromHandler) NULL)
4469 cache_info->methods.get_authentic_pixels_from_handler=
4470 cache_methods->get_authentic_pixels_from_handler;
4471 if (cache_methods->get_authentic_metacontent_from_handler !=
4472 (GetAuthenticMetacontentFromHandler) NULL)
4473 cache_info->methods.get_authentic_metacontent_from_handler=
4474 cache_methods->get_authentic_metacontent_from_handler;
4475 get_one_virtual_pixel_from_handler=
4476 cache_info->methods.get_one_virtual_pixel_from_handler;
4477 if (get_one_virtual_pixel_from_handler !=
4478 (GetOneVirtualPixelFromHandler) NULL)
4479 cache_info->methods.get_one_virtual_pixel_from_handler=
4480 cache_methods->get_one_virtual_pixel_from_handler;
4481 get_one_authentic_pixel_from_handler=
4482 cache_methods->get_one_authentic_pixel_from_handler;
4483 if (get_one_authentic_pixel_from_handler !=
4484 (GetOneAuthenticPixelFromHandler) NULL)
4485 cache_info->methods.get_one_authentic_pixel_from_handler=
4486 cache_methods->get_one_authentic_pixel_from_handler;
4490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4494 + S e t P i x e l C a c h e N e x u s P i x e l s %
4498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4500 % SetPixelCacheNexusPixels() defines the region of the cache for the
4501 % specified cache nexus.
4503 % The format of the SetPixelCacheNexusPixels() method is:
4505 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4506 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4507 % ExceptionInfo *exception)
4509 % A description of each parameter follows:
4511 % o cache_info: the pixel cache.
4513 % o mode: ReadMode, WriteMode, or IOMode.
4515 % o region: A pointer to the RectangleInfo structure that defines the
4516 % region of this particular cache nexus.
4518 % o nexus_info: the cache nexus to set.
4520 % o exception: return any errors or warnings in this structure.
4524 static inline MagickBooleanType AcquireCacheNexusPixels(
4525 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4526 ExceptionInfo *exception)
4528 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4529 return(MagickFalse);
4530 nexus_info->mapped=MagickFalse;
4531 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4532 (size_t) nexus_info->length));
4533 if (nexus_info->cache == (Quantum *) NULL)
4535 nexus_info->mapped=MagickTrue;
4536 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4537 nexus_info->length);
4539 if (nexus_info->cache == (Quantum *) NULL)
4541 (void) ThrowMagickException(exception,GetMagickModule(),
4542 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4543 cache_info->filename);
4544 return(MagickFalse);
4549 static inline MagickBooleanType IsPixelCacheAuthentic(
4550 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4559 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4561 if (cache_info->type == PingCache)
4563 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4564 nexus_info->region.x;
4565 status=nexus_info->pixels == (cache_info->pixels+offset*
4566 cache_info->number_channels) ? MagickTrue : MagickFalse;
4570 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4573 if (mode == ReadMode)
4575 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4578 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4581 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4582 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4583 ExceptionInfo *exception)
4592 assert(cache_info != (const CacheInfo *) NULL);
4593 assert(cache_info->signature == MagickSignature);
4594 if (cache_info->type == UndefinedCache)
4595 return((Quantum *) NULL);
4596 nexus_info->region=(*region);
4597 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4603 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4604 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4605 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4606 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4607 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4608 ((nexus_info->region.width == cache_info->columns) ||
4609 ((nexus_info->region.width % cache_info->columns) == 0)))))
4615 Pixels are accessed directly from memory.
4617 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4618 nexus_info->region.x;
4619 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4621 nexus_info->metacontent=(void *) NULL;
4622 if (cache_info->metacontent_extent != 0)
4623 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4624 offset*cache_info->metacontent_extent;
4625 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4626 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4628 return(nexus_info->pixels);
4632 Pixels are stored in a staging region until they are synced to the cache.
4634 number_pixels=(MagickSizeType) nexus_info->region.width*
4635 nexus_info->region.height;
4636 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4637 if (cache_info->metacontent_extent != 0)
4638 length+=number_pixels*cache_info->metacontent_extent;
4639 if (nexus_info->cache == (Quantum *) NULL)
4641 nexus_info->length=length;
4642 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4643 if (status == MagickFalse)
4645 nexus_info->length=0;
4646 return((Quantum *) NULL);
4650 if (nexus_info->length < length)
4652 RelinquishCacheNexusPixels(nexus_info);
4653 nexus_info->length=length;
4654 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4655 if (status == MagickFalse)
4657 nexus_info->length=0;
4658 return((Quantum *) NULL);
4661 nexus_info->pixels=nexus_info->cache;
4662 nexus_info->metacontent=(void *) NULL;
4663 if (cache_info->metacontent_extent != 0)
4664 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4665 cache_info->number_channels);
4666 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4667 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4669 return(nexus_info->pixels);
4673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4677 % 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 %
4681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4683 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4684 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4685 % access that is outside the boundaries of the image cache.
4687 % The format of the SetPixelCacheVirtualMethod() method is:
4689 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4690 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4692 % A description of each parameter follows:
4694 % o image: the image.
4696 % o virtual_pixel_method: choose the type of virtual pixel.
4698 % o exception: return any errors or warnings in this structure.
4702 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4703 ExceptionInfo *exception)
4706 *restrict cache_info;
4709 *restrict image_view;
4717 assert(image != (Image *) NULL);
4718 assert(image->signature == MagickSignature);
4719 if (image->debug != MagickFalse)
4720 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4721 assert(image->cache != (Cache) NULL);
4722 cache_info=(CacheInfo *) image->cache;
4723 assert(cache_info->signature == MagickSignature);
4724 image->alpha_trait=BlendPixelTrait;
4726 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4727 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4728 #pragma omp parallel for schedule(static,4) shared(status) \
4729 magick_threads(image,image,1,1)
4731 for (y=0; y < (ssize_t) image->rows; y++)
4739 if (status == MagickFalse)
4741 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4742 if (q == (Quantum *) NULL)
4747 for (x=0; x < (ssize_t) image->columns; x++)
4749 SetPixelAlpha(image,alpha,q);
4750 q+=GetPixelChannels(image);
4752 status=SyncCacheViewAuthenticPixels(image_view,exception);
4754 image_view=DestroyCacheView(image_view);
4758 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4759 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4762 *restrict cache_info;
4767 assert(image != (Image *) NULL);
4768 assert(image->signature == MagickSignature);
4769 if (image->debug != MagickFalse)
4770 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4771 assert(image->cache != (Cache) NULL);
4772 cache_info=(CacheInfo *) image->cache;
4773 assert(cache_info->signature == MagickSignature);
4774 method=cache_info->virtual_pixel_method;
4775 cache_info->virtual_pixel_method=virtual_pixel_method;
4776 if ((image->columns != 0) && (image->rows != 0))
4777 switch (virtual_pixel_method)
4779 case BackgroundVirtualPixelMethod:
4781 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4782 (image->alpha_trait != BlendPixelTrait))
4783 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4784 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4785 (IsGrayColorspace(image->colorspace) != MagickFalse))
4786 (void) SetImageColorspace(image,sRGBColorspace,exception);
4789 case TransparentVirtualPixelMethod:
4791 if (image->alpha_trait != BlendPixelTrait)
4792 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4806 + 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 %
4810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4812 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4813 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4814 % is synced, otherwise MagickFalse.
4816 % The format of the SyncAuthenticPixelCacheNexus() method is:
4818 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4819 % NexusInfo *nexus_info,ExceptionInfo *exception)
4821 % A description of each parameter follows:
4823 % o image: the image.
4825 % o nexus_info: the cache nexus to sync.
4827 % o exception: return any errors or warnings in this structure.
4830 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4831 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4834 *restrict cache_info;
4840 Transfer pixels to the cache.
4842 assert(image != (Image *) NULL);
4843 assert(image->signature == MagickSignature);
4844 if (image->cache == (Cache) NULL)
4845 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4846 cache_info=(CacheInfo *) image->cache;
4847 assert(cache_info->signature == MagickSignature);
4848 if (cache_info->type == UndefinedCache)
4849 return(MagickFalse);
4850 if (nexus_info->authentic_pixel_cache != MagickFalse)
4852 assert(cache_info->signature == MagickSignature);
4853 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4854 if ((cache_info->metacontent_extent != 0) &&
4855 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4856 return(MagickFalse);
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865 + S y n c A u t h e n t i c P i x e l C a c h e %
4869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4872 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4873 % otherwise MagickFalse.
4875 % The format of the SyncAuthenticPixelsCache() method is:
4877 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4878 % ExceptionInfo *exception)
4880 % A description of each parameter follows:
4882 % o image: the image.
4884 % o exception: return any errors or warnings in this structure.
4887 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4888 ExceptionInfo *exception)
4891 *restrict cache_info;
4894 id = GetOpenMPThreadId();
4899 assert(image != (Image *) NULL);
4900 assert(image->signature == MagickSignature);
4901 assert(image->cache != (Cache) NULL);
4902 cache_info=(CacheInfo *) image->cache;
4903 assert(cache_info->signature == MagickSignature);
4904 assert(id < (int) cache_info->number_threads);
4905 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4915 % S y n c A u t h e n t i c P i x e l s %
4919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4921 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4922 % The method returns MagickTrue if the pixel region is flushed, otherwise
4925 % The format of the SyncAuthenticPixels() method is:
4927 % MagickBooleanType SyncAuthenticPixels(Image *image,
4928 % ExceptionInfo *exception)
4930 % A description of each parameter follows:
4932 % o image: the image.
4934 % o exception: return any errors or warnings in this structure.
4937 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4938 ExceptionInfo *exception)
4941 *restrict cache_info;
4944 id = GetOpenMPThreadId();
4949 assert(image != (Image *) NULL);
4950 assert(image->signature == MagickSignature);
4951 assert(image->cache != (Cache) NULL);
4952 cache_info=(CacheInfo *) image->cache;
4953 assert(cache_info->signature == MagickSignature);
4954 if (cache_info->methods.sync_authentic_pixels_handler !=
4955 (SyncAuthenticPixelsHandler) NULL)
4957 status=cache_info->methods.sync_authentic_pixels_handler(image,
4961 assert(id < (int) cache_info->number_threads);
4962 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4972 + S y n c I m a g e P i x e l C a c h e %
4976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4978 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4979 % The method returns MagickTrue if the pixel region is flushed, otherwise
4982 % The format of the SyncImagePixelCache() method is:
4984 % MagickBooleanType SyncImagePixelCache(Image *image,
4985 % ExceptionInfo *exception)
4987 % A description of each parameter follows:
4989 % o image: the image.
4991 % o exception: return any errors or warnings in this structure.
4994 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4995 ExceptionInfo *exception)
4998 *restrict cache_info;
5000 assert(image != (Image *) NULL);
5001 assert(exception != (ExceptionInfo *) NULL);
5002 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5003 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5011 + 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 %
5015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5017 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5018 % of the pixel cache.
5020 % The format of the WritePixelCacheMetacontent() method is:
5022 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5023 % NexusInfo *nexus_info,ExceptionInfo *exception)
5025 % A description of each parameter follows:
5027 % o cache_info: the pixel cache.
5029 % o nexus_info: the cache nexus to write the meta-content.
5031 % o exception: return any errors or warnings in this structure.
5034 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5035 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5045 register const unsigned char
5054 if (cache_info->metacontent_extent == 0)
5055 return(MagickFalse);
5056 if (nexus_info->authentic_pixel_cache != MagickFalse)
5058 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5059 nexus_info->region.x;
5060 length=(MagickSizeType) nexus_info->region.width*
5061 cache_info->metacontent_extent;
5062 extent=(MagickSizeType) length*nexus_info->region.height;
5063 rows=nexus_info->region.height;
5065 p=(unsigned char *) nexus_info->metacontent;
5066 switch (cache_info->type)
5071 register unsigned char
5075 Write associated pixels to memory.
5077 if ((cache_info->columns == nexus_info->region.width) &&
5078 (extent == (MagickSizeType) ((size_t) extent)))
5083 q=(unsigned char *) cache_info->metacontent+offset*
5084 cache_info->metacontent_extent;
5085 for (y=0; y < (ssize_t) rows; y++)
5087 (void) memcpy(q,p,(size_t) length);
5088 p+=nexus_info->region.width*cache_info->metacontent_extent;
5089 q+=cache_info->columns*cache_info->metacontent_extent;
5096 Write associated pixels to disk.
5098 LockSemaphoreInfo(cache_info->file_semaphore);
5099 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5101 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5102 cache_info->cache_filename);
5103 UnlockSemaphoreInfo(cache_info->file_semaphore);
5104 return(MagickFalse);
5106 if ((cache_info->columns == nexus_info->region.width) &&
5107 (extent <= MagickMaxBufferExtent))
5112 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5113 for (y=0; y < (ssize_t) rows; y++)
5115 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5116 cache_info->number_channels*sizeof(Quantum)+offset*
5117 cache_info->metacontent_extent,length,(const unsigned char *) p);
5118 if (count != (MagickOffsetType) length)
5120 p+=cache_info->metacontent_extent*nexus_info->region.width;
5121 offset+=cache_info->columns;
5123 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5124 (void) ClosePixelCacheOnDisk(cache_info);
5125 UnlockSemaphoreInfo(cache_info->file_semaphore);
5128 case DistributedCache:
5134 Write metacontent to distributed cache.
5136 LockSemaphoreInfo(cache_info->file_semaphore);
5137 region=nexus_info->region;
5138 if ((cache_info->columns != nexus_info->region.width) ||
5139 (extent > MagickMaxBufferExtent))
5146 for (y=0; y < (ssize_t) rows; y++)
5148 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5149 cache_info->server_info,®ion,length,(const unsigned char *) p);
5150 if (count != (MagickOffsetType) length)
5152 p+=cache_info->metacontent_extent*nexus_info->region.width;
5155 UnlockSemaphoreInfo(cache_info->file_semaphore);
5161 if (y < (ssize_t) rows)
5163 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5164 cache_info->cache_filename);
5165 return(MagickFalse);
5167 if ((cache_info->debug != MagickFalse) &&
5168 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5169 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5170 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5171 nexus_info->region.width,(double) nexus_info->region.height,(double)
5172 nexus_info->region.x,(double) nexus_info->region.y);
5177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181 + W r i t e C a c h e P i x e l s %
5185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5187 % WritePixelCachePixels() writes image pixels to the specified region of the
5190 % The format of the WritePixelCachePixels() method is:
5192 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5193 % NexusInfo *nexus_info,ExceptionInfo *exception)
5195 % A description of each parameter follows:
5197 % o cache_info: the pixel cache.
5199 % o nexus_info: the cache nexus to write the pixels.
5201 % o exception: return any errors or warnings in this structure.
5204 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5205 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5215 register const Quantum
5224 if (nexus_info->authentic_pixel_cache != MagickFalse)
5226 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5227 nexus_info->region.x;
5228 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5230 extent=length*nexus_info->region.height;
5231 rows=nexus_info->region.height;
5233 p=nexus_info->pixels;
5234 switch (cache_info->type)
5243 Write pixels to memory.
5245 if ((cache_info->columns == nexus_info->region.width) &&
5246 (extent == (MagickSizeType) ((size_t) extent)))
5251 q=cache_info->pixels+offset*cache_info->number_channels;
5252 for (y=0; y < (ssize_t) rows; y++)
5254 (void) memcpy(q,p,(size_t) length);
5255 p+=cache_info->number_channels*nexus_info->region.width;
5256 q+=cache_info->columns*cache_info->number_channels;
5263 Write pixels to disk.
5265 LockSemaphoreInfo(cache_info->file_semaphore);
5266 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5268 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5269 cache_info->cache_filename);
5270 UnlockSemaphoreInfo(cache_info->file_semaphore);
5271 return(MagickFalse);
5273 if ((cache_info->columns == nexus_info->region.width) &&
5274 (extent <= MagickMaxBufferExtent))
5279 for (y=0; y < (ssize_t) rows; y++)
5281 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5282 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5284 if (count != (MagickOffsetType) length)
5286 p+=cache_info->number_channels*nexus_info->region.width;
5287 offset+=cache_info->columns;
5289 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5290 (void) ClosePixelCacheOnDisk(cache_info);
5291 UnlockSemaphoreInfo(cache_info->file_semaphore);
5294 case DistributedCache:
5300 Write pixels to distributed cache.
5302 LockSemaphoreInfo(cache_info->file_semaphore);
5303 region=nexus_info->region;
5304 if ((cache_info->columns != nexus_info->region.width) ||
5305 (extent > MagickMaxBufferExtent))
5312 for (y=0; y < (ssize_t) rows; y++)
5314 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5315 cache_info->server_info,®ion,length,(const unsigned char *) p);
5316 if (count != (MagickOffsetType) length)
5318 p+=cache_info->number_channels*nexus_info->region.width;
5321 UnlockSemaphoreInfo(cache_info->file_semaphore);
5327 if (y < (ssize_t) rows)
5329 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5330 cache_info->cache_filename);
5331 return(MagickFalse);
5333 if ((cache_info->debug != MagickFalse) &&
5334 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5335 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5336 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5337 nexus_info->region.width,(double) nexus_info->region.height,(double)
5338 nexus_info->region.x,(double) nexus_info->region.y);