2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
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 MagickSizeType MagickMin(const MagickSizeType x,
474 const MagickSizeType y)
481 static MagickBooleanType ClonePixelCacheRepository(
482 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
483 ExceptionInfo *exception)
485 #define MaxCacheThreads 2
486 #define cache_threads(source,destination,chunk) \
487 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
488 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
489 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
496 **restrict cache_nexus,
497 **restrict clone_nexus;
505 assert(cache_info != (CacheInfo *) NULL);
506 assert(clone_info != (CacheInfo *) NULL);
507 assert(exception != (ExceptionInfo *) NULL);
508 if (cache_info->type == PingCache)
510 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
511 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
512 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
513 (cache_info->columns == clone_info->columns) &&
514 (cache_info->rows == clone_info->rows) &&
515 (cache_info->number_channels == clone_info->number_channels) &&
516 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
517 (cache_info->metacontent_extent == clone_info->metacontent_extent))
523 Identical pixel cache morphology.
525 extent=cache_info->columns*cache_info->number_channels*cache_info->rows;
526 #if !defined(MAGICKCORE_OPENMP_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH <= 8)
527 (void) memcpy(clone_info->pixels,cache_info->pixels,extent*
528 sizeof(*cache_info->pixels));
531 register MagickSizeType
534 #pragma omp parallel for
535 for (i=0; i < extent; i++)
536 clone_info->pixels[i]=cache_info->pixels[i];
539 if (cache_info->metacontent_extent != 0)
540 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
541 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
542 sizeof(cache_info->metacontent));
546 Mismatched pixel cache morphology.
548 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
549 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
550 if ((cache_nexus == (NexusInfo **) NULL) ||
551 (clone_nexus == (NexusInfo **) NULL))
552 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
553 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
554 optimize=(cache_info->number_channels == clone_info->number_channels) &&
555 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
556 MagickTrue : MagickFalse;
557 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
558 clone_info->columns*clone_info->number_channels);
560 #if defined(MAGICKCORE_OPENMP_SUPPORT)
561 #pragma omp parallel for schedule(static,4) shared(status) \
562 cache_threads(cache_info,clone_info,cache_info->rows)
564 for (y=0; y < (ssize_t) cache_info->rows; y++)
567 id = GetOpenMPThreadId();
578 if (status == MagickFalse)
580 if (y >= (ssize_t) clone_info->rows)
582 region.width=cache_info->columns;
586 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
588 if (pixels == (Quantum *) NULL)
590 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
591 if (status == MagickFalse)
593 region.width=clone_info->columns;
594 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
595 clone_nexus[id],exception);
596 if (pixels == (Quantum *) NULL)
598 if (optimize != MagickFalse)
599 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
603 register const Quantum
610 Mismatched pixel channel map.
612 p=cache_nexus[id]->pixels;
613 q=clone_nexus[id]->pixels;
614 for (x=0; x < (ssize_t) cache_info->columns; x++)
619 if (x == (ssize_t) clone_info->columns)
621 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
629 channel=clone_info->channel_map[i].channel;
630 traits=cache_info->channel_map[channel].traits;
631 if (traits != UndefinedPixelTrait)
632 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
636 p+=cache_info->number_channels;
639 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
641 if ((cache_info->metacontent_extent != 0) &&
642 (clone_info->metacontent_extent != 0))
647 length=(size_t) MagickMin(cache_info->metacontent_extent,
648 clone_info->metacontent_extent);
649 #if defined(MAGICKCORE_OPENMP_SUPPORT)
650 #pragma omp parallel for schedule(static,4) shared(status) \
651 cache_threads(cache_info,clone_info,cache_info->rows)
653 for (y=0; y < (ssize_t) cache_info->rows; y++)
656 id = GetOpenMPThreadId();
664 if (status == MagickFalse)
666 if (y >= (ssize_t) clone_info->rows)
668 region.width=cache_info->columns;
672 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
673 cache_nexus[id],exception);
674 if (pixels == (Quantum *) NULL)
676 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
677 if (status == MagickFalse)
679 region.width=clone_info->columns;
680 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
681 clone_nexus[id],exception);
682 if (pixels == (Quantum *) NULL)
684 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
685 length*sizeof(cache_nexus[id]->metacontent));
686 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
689 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
690 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
691 if (cache_info->debug != MagickFalse)
694 message[MaxTextExtent];
696 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
697 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
698 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
699 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
709 + D e s t r o y I m a g e P i x e l C a c h e %
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
717 % The format of the DestroyImagePixelCache() method is:
719 % void DestroyImagePixelCache(Image *image)
721 % A description of each parameter follows:
723 % o image: the image.
726 static void DestroyImagePixelCache(Image *image)
728 assert(image != (Image *) NULL);
729 assert(image->signature == MagickSignature);
730 if (image->debug != MagickFalse)
731 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
732 if (image->cache == (void *) NULL)
734 image->cache=DestroyPixelCache(image->cache);
738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
742 + D e s t r o y I m a g e P i x e l s %
746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 % DestroyImagePixels() deallocates memory associated with the pixel cache.
750 % The format of the DestroyImagePixels() method is:
752 % void DestroyImagePixels(Image *image)
754 % A description of each parameter follows:
756 % o image: the image.
759 MagickExport void DestroyImagePixels(Image *image)
762 *restrict cache_info;
764 assert(image != (const Image *) NULL);
765 assert(image->signature == MagickSignature);
766 if (image->debug != MagickFalse)
767 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
768 assert(image->cache != (Cache) NULL);
769 cache_info=(CacheInfo *) image->cache;
770 assert(cache_info->signature == MagickSignature);
771 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
773 cache_info->methods.destroy_pixel_handler(image);
776 image->cache=DestroyPixelCache(image->cache);
780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
784 + D e s t r o y P i x e l C a c h e %
788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 % DestroyPixelCache() deallocates memory associated with the pixel cache.
792 % The format of the DestroyPixelCache() method is:
794 % Cache DestroyPixelCache(Cache cache)
796 % A description of each parameter follows:
798 % o cache: the pixel cache.
802 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
808 if (cache_info->file != -1)
810 status=close(cache_info->file);
811 cache_info->file=(-1);
812 RelinquishMagickResource(FileResource,1);
814 return(status == -1 ? MagickFalse : MagickTrue);
817 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
819 switch (cache_info->type)
823 if (cache_info->mapped == MagickFalse)
824 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
827 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
828 (size_t) cache_info->length);
829 RelinquishMagickResource(MemoryResource,cache_info->length);
834 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
836 if (cache_info->mode != ReadMode)
837 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
838 *cache_info->cache_filename='\0';
839 RelinquishMagickResource(MapResource,cache_info->length);
843 if (cache_info->file != -1)
844 (void) ClosePixelCacheOnDisk(cache_info);
845 if (cache_info->mode != ReadMode)
846 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
847 *cache_info->cache_filename='\0';
848 RelinquishMagickResource(DiskResource,cache_info->length);
851 case DistributedCache:
853 *cache_info->cache_filename='\0';
854 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
855 cache_info->server_info);
861 cache_info->type=UndefinedCache;
862 cache_info->mapped=MagickFalse;
863 cache_info->metacontent=(void *) NULL;
866 MagickPrivate Cache DestroyPixelCache(Cache cache)
869 *restrict cache_info;
871 assert(cache != (Cache) NULL);
872 cache_info=(CacheInfo *) cache;
873 assert(cache_info->signature == MagickSignature);
874 if (cache_info->debug != MagickFalse)
875 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
876 cache_info->filename);
877 LockSemaphoreInfo(cache_info->semaphore);
878 cache_info->reference_count--;
879 if (cache_info->reference_count != 0)
881 UnlockSemaphoreInfo(cache_info->semaphore);
882 return((Cache) NULL);
884 UnlockSemaphoreInfo(cache_info->semaphore);
885 if (cache_info->debug != MagickFalse)
888 message[MaxTextExtent];
890 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
891 cache_info->filename);
892 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
894 RelinquishPixelCachePixels(cache_info);
895 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
896 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
897 cache_info->server_info);
898 if (cache_info->nexus_info != (NexusInfo **) NULL)
899 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
900 cache_info->number_threads);
901 if (cache_info->random_info != (RandomInfo *) NULL)
902 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
903 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
904 DestroySemaphoreInfo(&cache_info->file_semaphore);
905 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
906 DestroySemaphoreInfo(&cache_info->semaphore);
907 cache_info->signature=(~MagickSignature);
908 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918 + D e s t r o y P i x e l C a c h e N e x u s %
922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
926 % The format of the DestroyPixelCacheNexus() method is:
928 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
929 % const size_t number_threads)
931 % A description of each parameter follows:
933 % o nexus_info: the nexus to destroy.
935 % o number_threads: the number of nexus threads.
939 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
941 if (nexus_info->mapped == MagickFalse)
942 (void) RelinquishAlignedMemory(nexus_info->cache);
944 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
945 nexus_info->cache=(Quantum *) NULL;
946 nexus_info->pixels=(Quantum *) NULL;
947 nexus_info->metacontent=(void *) NULL;
948 nexus_info->length=0;
949 nexus_info->mapped=MagickFalse;
952 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
953 const size_t number_threads)
958 assert(nexus_info != (NexusInfo **) NULL);
959 for (i=0; i < (ssize_t) number_threads; i++)
961 if (nexus_info[i]->cache != (Quantum *) NULL)
962 RelinquishCacheNexusPixels(nexus_info[i]);
963 nexus_info[i]->signature=(~MagickSignature);
965 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
966 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 % G e t A u t h e n t i c M e t a c o n t e n t %
979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
981 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
982 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
983 % returned if the associated pixels are not available.
985 % The format of the GetAuthenticMetacontent() method is:
987 % void *GetAuthenticMetacontent(const Image *image)
989 % A description of each parameter follows:
991 % o image: the image.
994 MagickExport void *GetAuthenticMetacontent(const Image *image)
997 *restrict cache_info;
1000 id = GetOpenMPThreadId();
1002 assert(image != (const Image *) NULL);
1003 assert(image->signature == MagickSignature);
1004 assert(image->cache != (Cache) NULL);
1005 cache_info=(CacheInfo *) image->cache;
1006 assert(cache_info->signature == MagickSignature);
1007 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1008 (GetAuthenticMetacontentFromHandler) NULL)
1013 metacontent=cache_info->methods.
1014 get_authentic_metacontent_from_handler(image);
1015 return(metacontent);
1017 assert(id < (int) cache_info->number_threads);
1018 return(cache_info->nexus_info[id]->metacontent);
1022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026 + 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 %
1030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1032 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1033 % with the last call to QueueAuthenticPixelsCache() or
1034 % GetAuthenticPixelsCache().
1036 % The format of the GetAuthenticMetacontentFromCache() method is:
1038 % void *GetAuthenticMetacontentFromCache(const Image *image)
1040 % A description of each parameter follows:
1042 % o image: the image.
1045 static void *GetAuthenticMetacontentFromCache(const Image *image)
1048 *restrict cache_info;
1051 id = GetOpenMPThreadId();
1053 assert(image != (const Image *) NULL);
1054 assert(image->signature == MagickSignature);
1055 assert(image->cache != (Cache) NULL);
1056 cache_info=(CacheInfo *) image->cache;
1057 assert(cache_info->signature == MagickSignature);
1058 assert(id < (int) cache_info->number_threads);
1059 return(cache_info->nexus_info[id]->metacontent);
1063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1067 + 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 %
1071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1074 % disk pixel cache as defined by the geometry parameters. A pointer to the
1075 % pixels is returned if the pixels are transferred, otherwise a NULL is
1078 % The format of the GetAuthenticPixelCacheNexus() method is:
1080 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1081 % const ssize_t y,const size_t columns,const size_t rows,
1082 % NexusInfo *nexus_info,ExceptionInfo *exception)
1084 % A description of each parameter follows:
1086 % o image: the image.
1088 % o x,y,columns,rows: These values define the perimeter of a region of
1091 % o nexus_info: the cache nexus to return.
1093 % o exception: return any errors or warnings in this structure.
1097 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1098 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1099 ExceptionInfo *exception)
1102 *restrict cache_info;
1108 Transfer pixels from the cache.
1110 assert(image != (Image *) NULL);
1111 assert(image->signature == MagickSignature);
1112 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1113 nexus_info,exception);
1114 if (pixels == (Quantum *) NULL)
1115 return((Quantum *) NULL);
1116 cache_info=(CacheInfo *) image->cache;
1117 assert(cache_info->signature == MagickSignature);
1118 if (nexus_info->authentic_pixel_cache != MagickFalse)
1120 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1121 return((Quantum *) NULL);
1122 if (cache_info->metacontent_extent != 0)
1123 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1124 return((Quantum *) NULL);
1129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1133 + 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 %
1137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1139 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1140 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1142 % The format of the GetAuthenticPixelsFromCache() method is:
1144 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1146 % A description of each parameter follows:
1148 % o image: the image.
1151 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1154 *restrict cache_info;
1157 id = GetOpenMPThreadId();
1159 assert(image != (const Image *) NULL);
1160 assert(image->signature == MagickSignature);
1161 assert(image->cache != (Cache) NULL);
1162 cache_info=(CacheInfo *) image->cache;
1163 assert(cache_info->signature == MagickSignature);
1164 assert(id < (int) cache_info->number_threads);
1165 return(cache_info->nexus_info[id]->pixels);
1169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 % G e t A u t h e n t i c P i x e l Q u e u e %
1177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179 % GetAuthenticPixelQueue() returns the authentic pixels associated
1180 % corresponding with the last call to QueueAuthenticPixels() or
1181 % GetAuthenticPixels().
1183 % The format of the GetAuthenticPixelQueue() method is:
1185 % Quantum *GetAuthenticPixelQueue(const Image image)
1187 % A description of each parameter follows:
1189 % o image: the image.
1192 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1195 *restrict cache_info;
1198 id = GetOpenMPThreadId();
1200 assert(image != (const Image *) NULL);
1201 assert(image->signature == MagickSignature);
1202 assert(image->cache != (Cache) NULL);
1203 cache_info=(CacheInfo *) image->cache;
1204 assert(cache_info->signature == MagickSignature);
1205 if (cache_info->methods.get_authentic_pixels_from_handler !=
1206 (GetAuthenticPixelsFromHandler) NULL)
1207 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1208 assert(id < (int) cache_info->number_threads);
1209 return(cache_info->nexus_info[id]->pixels);
1213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1217 % G e t A u t h e n t i c P i x e l s %
1220 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1222 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1223 % region is successfully accessed, a pointer to a Quantum array
1224 % representing the region is returned, otherwise NULL is returned.
1226 % The returned pointer may point to a temporary working copy of the pixels
1227 % or it may point to the original pixels in memory. Performance is maximized
1228 % if the selected region is part of one row, or one or more full rows, since
1229 % then there is opportunity to access the pixels in-place (without a copy)
1230 % if the image is in memory, or in a memory-mapped file. The returned pointer
1231 % must *never* be deallocated by the user.
1233 % Pixels accessed via the returned pointer represent a simple array of type
1234 % Quantum. If the image has corresponding metacontent,call
1235 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1236 % meta-content corresponding to the region. Once the Quantum array has
1237 % been updated, the changes must be saved back to the underlying image using
1238 % SyncAuthenticPixels() or they may be lost.
1240 % The format of the GetAuthenticPixels() method is:
1242 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1243 % const ssize_t y,const size_t columns,const size_t rows,
1244 % ExceptionInfo *exception)
1246 % A description of each parameter follows:
1248 % o image: the image.
1250 % o x,y,columns,rows: These values define the perimeter of a region of
1253 % o exception: return any errors or warnings in this structure.
1256 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1257 const ssize_t y,const size_t columns,const size_t rows,
1258 ExceptionInfo *exception)
1261 *restrict cache_info;
1264 id = GetOpenMPThreadId();
1269 assert(image != (Image *) NULL);
1270 assert(image->signature == MagickSignature);
1271 assert(image->cache != (Cache) NULL);
1272 cache_info=(CacheInfo *) image->cache;
1273 assert(cache_info->signature == MagickSignature);
1274 if (cache_info->methods.get_authentic_pixels_handler !=
1275 (GetAuthenticPixelsHandler) NULL)
1277 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1281 assert(id < (int) cache_info->number_threads);
1282 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1283 cache_info->nexus_info[id],exception);
1288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1292 + G e t A u t h e n t i c P i x e l s C a c h e %
1296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1298 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1299 % as defined by the geometry parameters. A pointer to the pixels is returned
1300 % if the pixels are transferred, otherwise a NULL is returned.
1302 % The format of the GetAuthenticPixelsCache() method is:
1304 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1305 % const ssize_t y,const size_t columns,const size_t rows,
1306 % ExceptionInfo *exception)
1308 % A description of each parameter follows:
1310 % o image: the image.
1312 % o x,y,columns,rows: These values define the perimeter of a region of
1315 % o exception: return any errors or warnings in this structure.
1318 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1319 const ssize_t y,const size_t columns,const size_t rows,
1320 ExceptionInfo *exception)
1323 *restrict cache_info;
1326 id = GetOpenMPThreadId();
1331 assert(image != (const Image *) NULL);
1332 assert(image->signature == MagickSignature);
1333 assert(image->cache != (Cache) NULL);
1334 cache_info=(CacheInfo *) image->cache;
1335 if (cache_info == (Cache) NULL)
1336 return((Quantum *) NULL);
1337 assert(cache_info->signature == MagickSignature);
1338 assert(id < (int) cache_info->number_threads);
1339 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1340 cache_info->nexus_info[id],exception);
1345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1349 + G e t I m a g e E x t e n t %
1353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355 % GetImageExtent() returns the extent of the pixels associated corresponding
1356 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1358 % The format of the GetImageExtent() method is:
1360 % MagickSizeType GetImageExtent(const Image *image)
1362 % A description of each parameter follows:
1364 % o image: the image.
1367 MagickExport MagickSizeType GetImageExtent(const Image *image)
1370 *restrict cache_info;
1373 id = GetOpenMPThreadId();
1375 assert(image != (Image *) NULL);
1376 assert(image->signature == MagickSignature);
1377 if (image->debug != MagickFalse)
1378 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1379 assert(image->cache != (Cache) NULL);
1380 cache_info=(CacheInfo *) image->cache;
1381 assert(cache_info->signature == MagickSignature);
1382 assert(id < (int) cache_info->number_threads);
1383 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391 + G e t I m a g e P i x e l C a c h e %
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1397 % GetImagePixelCache() ensures that there is only a single reference to the
1398 % pixel cache to be modified, updating the provided cache pointer to point to
1399 % a clone of the original pixel cache if necessary.
1401 % The format of the GetImagePixelCache method is:
1403 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1404 % ExceptionInfo *exception)
1406 % A description of each parameter follows:
1408 % o image: the image.
1410 % o clone: any value other than MagickFalse clones the cache pixels.
1412 % o exception: return any errors or warnings in this structure.
1416 static inline MagickBooleanType ValidatePixelCacheMorphology(
1417 const Image *restrict image)
1420 *restrict cache_info;
1422 const PixelChannelMap
1427 Does the image match the pixel cache morphology?
1429 cache_info=(CacheInfo *) image->cache;
1430 p=image->channel_map;
1431 q=cache_info->channel_map;
1432 if ((image->storage_class != cache_info->storage_class) ||
1433 (image->colorspace != cache_info->colorspace) ||
1434 (image->alpha_trait != cache_info->alpha_trait) ||
1435 (image->read_mask != cache_info->read_mask) ||
1436 (image->write_mask != cache_info->write_mask) ||
1437 (image->columns != cache_info->columns) ||
1438 (image->rows != cache_info->rows) ||
1439 (image->number_channels != cache_info->number_channels) ||
1440 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1441 (image->metacontent_extent != cache_info->metacontent_extent) ||
1442 (cache_info->nexus_info == (NexusInfo **) NULL))
1443 return(MagickFalse);
1447 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1448 ExceptionInfo *exception)
1451 *restrict cache_info;
1457 static MagickSizeType
1463 cache_timestamp = 0;
1466 LockSemaphoreInfo(image->semaphore);
1467 if (cpu_throttle == 0)
1468 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1469 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1470 MagickDelay(cpu_throttle);
1471 if (time_limit == 0)
1474 Set the expire time in seconds.
1476 time_limit=GetMagickResourceLimit(TimeResource);
1477 cache_timestamp=time((time_t *) NULL);
1479 if ((time_limit != MagickResourceInfinity) &&
1480 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1481 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1482 assert(image->cache != (Cache) NULL);
1483 cache_info=(CacheInfo *) image->cache;
1484 destroy=MagickFalse;
1485 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1487 LockSemaphoreInfo(cache_info->semaphore);
1488 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1499 clone_image=(*image);
1500 clone_image.semaphore=AllocateSemaphoreInfo();
1501 clone_image.reference_count=1;
1502 clone_image.cache=ClonePixelCache(cache_info);
1503 clone_info=(CacheInfo *) clone_image.cache;
1504 status=OpenPixelCache(&clone_image,IOMode,exception);
1505 if (status != MagickFalse)
1507 if (clone != MagickFalse)
1508 status=ClonePixelCacheRepository(clone_info,cache_info,
1510 if (status != MagickFalse)
1512 if (cache_info->reference_count == 1)
1513 cache_info->nexus_info=(NexusInfo **) NULL;
1515 image->cache=clone_image.cache;
1518 DestroySemaphoreInfo(&clone_image.semaphore);
1520 UnlockSemaphoreInfo(cache_info->semaphore);
1522 if (destroy != MagickFalse)
1523 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1524 if (status != MagickFalse)
1527 Ensure the image matches the pixel cache morphology.
1529 image->taint=MagickTrue;
1530 image->type=UndefinedType;
1531 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1533 status=OpenPixelCache(image,IOMode,exception);
1534 cache_info=(CacheInfo *) image->cache;
1535 if (cache_info->type == DiskCache)
1536 (void) ClosePixelCacheOnDisk(cache_info);
1539 UnlockSemaphoreInfo(image->semaphore);
1540 if (status == MagickFalse)
1541 return((Cache) NULL);
1542 return(image->cache);
1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550 + G e t I m a g e P i x e l C a c h e T y p e %
1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1557 % DiskCache, MemoryCache, MapCache, or PingCache.
1559 % The format of the GetImagePixelCacheType() method is:
1561 % CacheType GetImagePixelCacheType(const Image *image)
1563 % A description of each parameter follows:
1565 % o image: the image.
1568 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1571 *restrict cache_info;
1573 assert(image != (Image *) NULL);
1574 assert(image->signature == MagickSignature);
1575 assert(image->cache != (Cache) NULL);
1576 cache_info=(CacheInfo *) image->cache;
1577 assert(cache_info->signature == MagickSignature);
1578 return(cache_info->type);
1582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586 % G e t O n e A u t h e n t i c P i x e l %
1590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1593 % location. The image background color is returned if an error occurs.
1595 % The format of the GetOneAuthenticPixel() method is:
1597 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1598 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1600 % A description of each parameter follows:
1602 % o image: the image.
1604 % o x,y: These values define the location of the pixel to return.
1606 % o pixel: return a pixel at the specified (x,y) location.
1608 % o exception: return any errors or warnings in this structure.
1611 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1612 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1615 *restrict cache_info;
1623 assert(image != (Image *) NULL);
1624 assert(image->signature == MagickSignature);
1625 assert(image->cache != (Cache) NULL);
1626 cache_info=(CacheInfo *) image->cache;
1627 assert(cache_info->signature == MagickSignature);
1628 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1629 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1630 (GetOneAuthenticPixelFromHandler) NULL)
1631 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1633 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1634 if (q == (Quantum *) NULL)
1636 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1637 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1638 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1639 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1640 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1641 return(MagickFalse);
1643 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1645 PixelChannel channel=GetPixelChannelChannel(image,i);
1646 pixel[channel]=q[i];
1652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1656 + 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 %
1660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1662 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1663 % location. The image background color is returned if an error occurs.
1665 % The format of the GetOneAuthenticPixelFromCache() method is:
1667 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1668 % const ssize_t x,const ssize_t y,Quantum *pixel,
1669 % ExceptionInfo *exception)
1671 % A description of each parameter follows:
1673 % o image: the image.
1675 % o x,y: These values define the location of the pixel to return.
1677 % o pixel: return a pixel at the specified (x,y) location.
1679 % o exception: return any errors or warnings in this structure.
1682 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1683 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1686 *restrict cache_info;
1689 id = GetOpenMPThreadId();
1697 assert(image != (const Image *) NULL);
1698 assert(image->signature == MagickSignature);
1699 assert(image->cache != (Cache) NULL);
1700 cache_info=(CacheInfo *) image->cache;
1701 assert(cache_info->signature == MagickSignature);
1702 assert(id < (int) cache_info->number_threads);
1703 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1704 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1706 if (q == (Quantum *) NULL)
1708 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1709 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1710 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1711 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1712 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1713 return(MagickFalse);
1715 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1717 PixelChannel channel=GetPixelChannelChannel(image,i);
1718 pixel[channel]=q[i];
1724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1728 % G e t O n e V i r t u a l P i x e l %
1732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1735 % (x,y) location. The image background color is returned if an error occurs.
1736 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1738 % The format of the GetOneVirtualPixel() method is:
1740 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1741 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1743 % A description of each parameter follows:
1745 % o image: the image.
1747 % o x,y: These values define the location of the pixel to return.
1749 % o pixel: return a pixel at the specified (x,y) location.
1751 % o exception: return any errors or warnings in this structure.
1754 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1755 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1758 *restrict cache_info;
1761 id = GetOpenMPThreadId();
1769 assert(image != (const Image *) NULL);
1770 assert(image->signature == MagickSignature);
1771 assert(image->cache != (Cache) NULL);
1772 cache_info=(CacheInfo *) image->cache;
1773 assert(cache_info->signature == MagickSignature);
1774 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1775 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1776 (GetOneVirtualPixelFromHandler) NULL)
1777 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1778 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1779 assert(id < (int) cache_info->number_threads);
1780 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1781 1UL,1UL,cache_info->nexus_info[id],exception);
1782 if (p == (const Quantum *) NULL)
1784 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1785 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1786 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1787 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1788 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1789 return(MagickFalse);
1791 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1793 PixelChannel channel=GetPixelChannelChannel(image,i);
1794 pixel[channel]=p[i];
1800 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1804 + 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 %
1808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1810 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1811 % specified (x,y) location. The image background color is returned if an
1814 % The format of the GetOneVirtualPixelFromCache() method is:
1816 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1817 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1818 % Quantum *pixel,ExceptionInfo *exception)
1820 % A description of each parameter follows:
1822 % o image: the image.
1824 % o virtual_pixel_method: the virtual pixel method.
1826 % o x,y: These values define the location of the pixel to return.
1828 % o pixel: return a pixel at the specified (x,y) location.
1830 % o exception: return any errors or warnings in this structure.
1833 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1834 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1835 Quantum *pixel,ExceptionInfo *exception)
1838 *restrict cache_info;
1841 id = GetOpenMPThreadId();
1849 assert(image != (const Image *) NULL);
1850 assert(image->signature == MagickSignature);
1851 assert(image->cache != (Cache) NULL);
1852 cache_info=(CacheInfo *) image->cache;
1853 assert(cache_info->signature == MagickSignature);
1854 assert(id < (int) cache_info->number_threads);
1855 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1856 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1857 cache_info->nexus_info[id],exception);
1858 if (p == (const Quantum *) NULL)
1860 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1861 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1862 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1863 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1864 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1865 return(MagickFalse);
1867 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1869 PixelChannel channel=GetPixelChannelChannel(image,i);
1870 pixel[channel]=p[i];
1876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1880 % G e t O n e V i r t u a l P i x e l I n f o %
1884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1886 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1887 % location. The image background color is returned if an error occurs. If
1888 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1890 % The format of the GetOneVirtualPixelInfo() method is:
1892 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1893 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1894 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1896 % A description of each parameter follows:
1898 % o image: the image.
1900 % o virtual_pixel_method: the virtual pixel method.
1902 % o x,y: these values define the location of the pixel to return.
1904 % o pixel: return a pixel at the specified (x,y) location.
1906 % o exception: return any errors or warnings in this structure.
1909 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1910 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1911 PixelInfo *pixel,ExceptionInfo *exception)
1914 *restrict cache_info;
1917 id = GetOpenMPThreadId();
1919 register const Quantum
1922 assert(image != (const Image *) NULL);
1923 assert(image->signature == MagickSignature);
1924 assert(image->cache != (Cache) NULL);
1925 cache_info=(CacheInfo *) image->cache;
1926 assert(cache_info->signature == MagickSignature);
1927 assert(id < (int) cache_info->number_threads);
1928 GetPixelInfo(image,pixel);
1929 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1930 cache_info->nexus_info[id],exception);
1931 if (p == (const Quantum *) NULL)
1932 return(MagickFalse);
1933 GetPixelInfoPixel(image,p,pixel);
1938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942 + G e t P i x e l C a c h e C o l o r s p a c e %
1946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1948 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1950 % The format of the GetPixelCacheColorspace() method is:
1952 % Colorspace GetPixelCacheColorspace(Cache cache)
1954 % A description of each parameter follows:
1956 % o cache: the pixel cache.
1959 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1962 *restrict cache_info;
1964 assert(cache != (Cache) NULL);
1965 cache_info=(CacheInfo *) cache;
1966 assert(cache_info->signature == MagickSignature);
1967 if (cache_info->debug != MagickFalse)
1968 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1969 cache_info->filename);
1970 return(cache_info->colorspace);
1974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978 + G e t P i x e l C a c h e M e t h o d s %
1982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1984 % GetPixelCacheMethods() initializes the CacheMethods structure.
1986 % The format of the GetPixelCacheMethods() method is:
1988 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1990 % A description of each parameter follows:
1992 % o cache_methods: Specifies a pointer to a CacheMethods structure.
1995 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
1997 assert(cache_methods != (CacheMethods *) NULL);
1998 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
1999 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2000 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2001 cache_methods->get_virtual_metacontent_from_handler=
2002 GetVirtualMetacontentFromCache;
2003 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2004 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2005 cache_methods->get_authentic_metacontent_from_handler=
2006 GetAuthenticMetacontentFromCache;
2007 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2008 cache_methods->get_one_authentic_pixel_from_handler=
2009 GetOneAuthenticPixelFromCache;
2010 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2011 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2012 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2020 + G e t P i x e l C a c h e N e x u s E x t e n t %
2024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2026 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2027 % corresponding with the last call to SetPixelCacheNexusPixels() or
2028 % GetPixelCacheNexusPixels().
2030 % The format of the GetPixelCacheNexusExtent() method is:
2032 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2033 % NexusInfo *nexus_info)
2035 % A description of each parameter follows:
2037 % o nexus_info: the nexus info.
2040 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2041 NexusInfo *restrict nexus_info)
2044 *restrict cache_info;
2049 assert(cache != NULL);
2050 cache_info=(CacheInfo *) cache;
2051 assert(cache_info->signature == MagickSignature);
2052 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2054 return((MagickSizeType) cache_info->columns*cache_info->rows);
2059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063 + G e t P i x e l C a c h e P i x e l s %
2067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2069 % GetPixelCachePixels() returns the pixels associated with the specified image.
2071 % The format of the GetPixelCachePixels() method is:
2073 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2074 % ExceptionInfo *exception)
2076 % A description of each parameter follows:
2078 % o image: the image.
2080 % o length: the pixel cache length.
2082 % o exception: return any errors or warnings in this structure.
2085 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2086 ExceptionInfo *exception)
2089 *restrict cache_info;
2091 assert(image != (const Image *) NULL);
2092 assert(image->signature == MagickSignature);
2093 assert(image->cache != (Cache) NULL);
2094 assert(length != (MagickSizeType *) NULL);
2095 assert(exception != (ExceptionInfo *) NULL);
2096 assert(exception->signature == MagickSignature);
2097 cache_info=(CacheInfo *) image->cache;
2098 assert(cache_info->signature == MagickSignature);
2100 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2101 return((void *) NULL);
2102 *length=cache_info->length;
2103 return((void *) cache_info->pixels);
2107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2111 + 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 %
2115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2117 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2119 % The format of the GetPixelCacheStorageClass() method is:
2121 % ClassType GetPixelCacheStorageClass(Cache cache)
2123 % A description of each parameter follows:
2125 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2127 % o cache: the pixel cache.
2130 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2133 *restrict cache_info;
2135 assert(cache != (Cache) NULL);
2136 cache_info=(CacheInfo *) cache;
2137 assert(cache_info->signature == MagickSignature);
2138 if (cache_info->debug != MagickFalse)
2139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2140 cache_info->filename);
2141 return(cache_info->storage_class);
2145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2149 + G e t P i x e l C a c h e T i l e S i z e %
2153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2155 % GetPixelCacheTileSize() returns the pixel cache tile size.
2157 % The format of the GetPixelCacheTileSize() method is:
2159 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2162 % A description of each parameter follows:
2164 % o image: the image.
2166 % o width: the optimize cache tile width in pixels.
2168 % o height: the optimize cache tile height in pixels.
2171 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2175 *restrict cache_info;
2177 assert(image != (Image *) NULL);
2178 assert(image->signature == MagickSignature);
2179 if (image->debug != MagickFalse)
2180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2181 cache_info=(CacheInfo *) image->cache;
2182 assert(cache_info->signature == MagickSignature);
2183 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2184 if (GetImagePixelCacheType(image) == DiskCache)
2185 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2194 + 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 %
2198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2200 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2201 % pixel cache. A virtual pixel is any pixel access that is outside the
2202 % boundaries of the image cache.
2204 % The format of the GetPixelCacheVirtualMethod() method is:
2206 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2208 % A description of each parameter follows:
2210 % o image: the image.
2213 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2216 *restrict cache_info;
2218 assert(image != (Image *) NULL);
2219 assert(image->signature == MagickSignature);
2220 assert(image->cache != (Cache) NULL);
2221 cache_info=(CacheInfo *) image->cache;
2222 assert(cache_info->signature == MagickSignature);
2223 return(cache_info->virtual_pixel_method);
2227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2231 + 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 %
2235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2237 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2238 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2240 % The format of the GetVirtualMetacontentFromCache() method is:
2242 % void *GetVirtualMetacontentFromCache(const Image *image)
2244 % A description of each parameter follows:
2246 % o image: the image.
2249 static const void *GetVirtualMetacontentFromCache(const Image *image)
2252 *restrict cache_info;
2255 id = GetOpenMPThreadId();
2258 *restrict metacontent;
2260 assert(image != (const Image *) NULL);
2261 assert(image->signature == MagickSignature);
2262 assert(image->cache != (Cache) NULL);
2263 cache_info=(CacheInfo *) image->cache;
2264 assert(cache_info->signature == MagickSignature);
2265 assert(id < (int) cache_info->number_threads);
2266 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2267 cache_info->nexus_info[id]);
2268 return(metacontent);
2272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2276 + 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 %
2280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2282 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2285 % The format of the GetVirtualMetacontentFromNexus() method is:
2287 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2288 % NexusInfo *nexus_info)
2290 % A description of each parameter follows:
2292 % o cache: the pixel cache.
2294 % o nexus_info: the cache nexus to return the meta-content.
2297 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2298 NexusInfo *restrict nexus_info)
2301 *restrict cache_info;
2303 assert(cache != (Cache) NULL);
2304 cache_info=(CacheInfo *) cache;
2305 assert(cache_info->signature == MagickSignature);
2306 if (cache_info->storage_class == UndefinedClass)
2307 return((void *) NULL);
2308 return(nexus_info->metacontent);
2312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2316 % G e t V i r t u a l M e t a c o n t e n t %
2320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2323 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2324 % returned if the meta-content are not available.
2326 % The format of the GetVirtualMetacontent() method is:
2328 % const void *GetVirtualMetacontent(const Image *image)
2330 % A description of each parameter follows:
2332 % o image: the image.
2335 MagickExport const void *GetVirtualMetacontent(const Image *image)
2338 *restrict cache_info;
2341 id = GetOpenMPThreadId();
2344 *restrict metacontent;
2346 assert(image != (const Image *) NULL);
2347 assert(image->signature == MagickSignature);
2348 assert(image->cache != (Cache) NULL);
2349 cache_info=(CacheInfo *) image->cache;
2350 assert(cache_info->signature == MagickSignature);
2351 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2352 if (metacontent != (void *) NULL)
2353 return(metacontent);
2354 assert(id < (int) cache_info->number_threads);
2355 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2356 cache_info->nexus_info[id]);
2357 return(metacontent);
2361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2365 + 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 %
2369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2371 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2372 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2373 % is returned if the pixels are transferred, otherwise a NULL is returned.
2375 % The format of the GetVirtualPixelsFromNexus() method is:
2377 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2378 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2379 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2380 % ExceptionInfo *exception)
2382 % A description of each parameter follows:
2384 % o image: the image.
2386 % o virtual_pixel_method: the virtual pixel method.
2388 % o x,y,columns,rows: These values define the perimeter of a region of
2391 % o nexus_info: the cache nexus to acquire.
2393 % o exception: return any errors or warnings in this structure.
2400 0, 48, 12, 60, 3, 51, 15, 63,
2401 32, 16, 44, 28, 35, 19, 47, 31,
2402 8, 56, 4, 52, 11, 59, 7, 55,
2403 40, 24, 36, 20, 43, 27, 39, 23,
2404 2, 50, 14, 62, 1, 49, 13, 61,
2405 34, 18, 46, 30, 33, 17, 45, 29,
2406 10, 58, 6, 54, 9, 57, 5, 53,
2407 42, 26, 38, 22, 41, 25, 37, 21
2410 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2415 index=x+DitherMatrix[x & 0x07]-32L;
2418 if (index >= (ssize_t) columns)
2419 return((ssize_t) columns-1L);
2423 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2428 index=y+DitherMatrix[y & 0x07]-32L;
2431 if (index >= (ssize_t) rows)
2432 return((ssize_t) rows-1L);
2436 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2440 if (x >= (ssize_t) columns)
2441 return((ssize_t) (columns-1));
2445 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2449 if (y >= (ssize_t) rows)
2450 return((ssize_t) (rows-1));
2454 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2456 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2459 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2461 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2464 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2465 const size_t extent)
2471 Compute the remainder of dividing offset by extent. It returns not only
2472 the quotient (tile the offset falls in) but also the positive remainer
2473 within that tile such that 0 <= remainder < extent. This method is
2474 essentially a ldiv() using a floored modulo division rather than the
2475 normal default truncated modulo division.
2477 modulo.quotient=offset/(ssize_t) extent;
2480 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2484 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2485 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2486 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2487 ExceptionInfo *exception)
2490 *restrict cache_info;
2500 **restrict virtual_nexus;
2504 virtual_pixel[MaxPixelChannels];
2509 register const Quantum
2522 register unsigned char
2529 *restrict virtual_metacontent;
2534 assert(image != (const Image *) NULL);
2535 assert(image->signature == MagickSignature);
2536 assert(image->cache != (Cache) NULL);
2537 cache_info=(CacheInfo *) image->cache;
2538 assert(cache_info->signature == MagickSignature);
2539 if (cache_info->type == UndefinedCache)
2540 return((const Quantum *) NULL);
2543 region.width=columns;
2545 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2547 if (pixels == (Quantum *) NULL)
2548 return((const Quantum *) NULL);
2550 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2551 nexus_info->region.x;
2552 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2553 nexus_info->region.width-1L;
2554 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2555 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2556 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2557 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2563 Pixel request is inside cache extents.
2565 if (nexus_info->authentic_pixel_cache != MagickFalse)
2567 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2568 if (status == MagickFalse)
2569 return((const Quantum *) NULL);
2570 if (cache_info->metacontent_extent != 0)
2572 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2573 if (status == MagickFalse)
2574 return((const Quantum *) NULL);
2579 Pixel request is outside cache extents.
2581 s=(unsigned char *) nexus_info->metacontent;
2582 virtual_nexus=AcquirePixelCacheNexus(1);
2583 if (virtual_nexus == (NexusInfo **) NULL)
2585 if (virtual_nexus != (NexusInfo **) NULL)
2586 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2587 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2588 "UnableToGetCacheNexus","`%s'",image->filename);
2589 return((const Quantum *) NULL);
2591 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2592 sizeof(*virtual_pixel));
2593 virtual_metacontent=(void *) NULL;
2594 switch (virtual_pixel_method)
2596 case BackgroundVirtualPixelMethod:
2597 case BlackVirtualPixelMethod:
2598 case GrayVirtualPixelMethod:
2599 case TransparentVirtualPixelMethod:
2600 case MaskVirtualPixelMethod:
2601 case WhiteVirtualPixelMethod:
2602 case EdgeVirtualPixelMethod:
2603 case CheckerTileVirtualPixelMethod:
2604 case HorizontalTileVirtualPixelMethod:
2605 case VerticalTileVirtualPixelMethod:
2607 if (cache_info->metacontent_extent != 0)
2610 Acquire a metacontent buffer.
2612 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2613 cache_info->metacontent_extent);
2614 if (virtual_metacontent == (void *) NULL)
2616 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2617 (void) ThrowMagickException(exception,GetMagickModule(),
2618 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2619 return((const Quantum *) NULL);
2621 (void) ResetMagickMemory(virtual_metacontent,0,
2622 cache_info->metacontent_extent);
2624 switch (virtual_pixel_method)
2626 case BlackVirtualPixelMethod:
2628 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2629 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2630 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2633 case GrayVirtualPixelMethod:
2635 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2636 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2638 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2641 case TransparentVirtualPixelMethod:
2643 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2644 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2645 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2648 case MaskVirtualPixelMethod:
2649 case WhiteVirtualPixelMethod:
2651 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2652 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2653 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2658 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2660 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2662 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2664 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2666 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2676 for (v=0; v < (ssize_t) rows; v++)
2682 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2683 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2684 y_offset=EdgeY(y_offset,cache_info->rows);
2685 for (u=0; u < (ssize_t) columns; u+=length)
2691 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2692 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2693 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2701 Transfer a single pixel.
2703 length=(MagickSizeType) 1;
2704 switch (virtual_pixel_method)
2706 case EdgeVirtualPixelMethod:
2709 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2710 EdgeX(x_offset,cache_info->columns),
2711 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2713 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2716 case RandomVirtualPixelMethod:
2718 if (cache_info->random_info == (RandomInfo *) NULL)
2719 cache_info->random_info=AcquireRandomInfo();
2720 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2721 RandomX(cache_info->random_info,cache_info->columns),
2722 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2723 *virtual_nexus,exception);
2724 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2727 case DitherVirtualPixelMethod:
2729 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2730 DitherX(x_offset,cache_info->columns),
2731 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2733 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2736 case TileVirtualPixelMethod:
2738 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2739 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2740 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2741 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2743 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2746 case MirrorVirtualPixelMethod:
2748 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2749 if ((x_modulo.quotient & 0x01) == 1L)
2750 x_modulo.remainder=(ssize_t) cache_info->columns-
2751 x_modulo.remainder-1L;
2752 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2753 if ((y_modulo.quotient & 0x01) == 1L)
2754 y_modulo.remainder=(ssize_t) cache_info->rows-
2755 y_modulo.remainder-1L;
2756 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2757 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2759 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2762 case HorizontalTileEdgeVirtualPixelMethod:
2764 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2765 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2766 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2767 *virtual_nexus,exception);
2768 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2771 case VerticalTileEdgeVirtualPixelMethod:
2773 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2774 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2775 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2776 *virtual_nexus,exception);
2777 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2780 case BackgroundVirtualPixelMethod:
2781 case BlackVirtualPixelMethod:
2782 case GrayVirtualPixelMethod:
2783 case TransparentVirtualPixelMethod:
2784 case MaskVirtualPixelMethod:
2785 case WhiteVirtualPixelMethod:
2788 r=virtual_metacontent;
2791 case CheckerTileVirtualPixelMethod:
2793 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2794 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2795 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2798 r=virtual_metacontent;
2801 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2802 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2804 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2807 case HorizontalTileVirtualPixelMethod:
2809 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2812 r=virtual_metacontent;
2815 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2816 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2817 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2818 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2820 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2823 case VerticalTileVirtualPixelMethod:
2825 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2828 r=virtual_metacontent;
2831 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2832 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2833 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2834 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2836 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2840 if (p == (const Quantum *) NULL)
2842 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2844 q+=cache_info->number_channels;
2845 if ((s != (void *) NULL) && (r != (const void *) NULL))
2847 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2848 s+=cache_info->metacontent_extent;
2853 Transfer a run of pixels.
2855 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2856 (size_t) length,1UL,*virtual_nexus,exception);
2857 if (p == (const Quantum *) NULL)
2859 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2860 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2861 q+=length*cache_info->number_channels;
2862 if ((r != (void *) NULL) && (s != (const void *) NULL))
2864 (void) memcpy(s,r,(size_t) length);
2865 s+=length*cache_info->metacontent_extent;
2872 if (virtual_metacontent != (void *) NULL)
2873 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2874 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883 + G e t V i r t u a l P i x e l C a c h e %
2887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2889 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2890 % cache as defined by the geometry parameters. A pointer to the pixels
2891 % is returned if the pixels are transferred, otherwise a NULL is returned.
2893 % The format of the GetVirtualPixelCache() method is:
2895 % const Quantum *GetVirtualPixelCache(const Image *image,
2896 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2897 % const ssize_t y,const size_t columns,const size_t rows,
2898 % ExceptionInfo *exception)
2900 % A description of each parameter follows:
2902 % o image: the image.
2904 % o virtual_pixel_method: the virtual pixel method.
2906 % o x,y,columns,rows: These values define the perimeter of a region of
2909 % o exception: return any errors or warnings in this structure.
2912 static const Quantum *GetVirtualPixelCache(const Image *image,
2913 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2914 const size_t columns,const size_t rows,ExceptionInfo *exception)
2917 *restrict cache_info;
2920 id = GetOpenMPThreadId();
2925 assert(image != (const Image *) NULL);
2926 assert(image->signature == MagickSignature);
2927 assert(image->cache != (Cache) NULL);
2928 cache_info=(CacheInfo *) image->cache;
2929 assert(cache_info->signature == MagickSignature);
2930 assert(id < (int) cache_info->number_threads);
2931 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2932 cache_info->nexus_info[id],exception);
2937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2941 % G e t V i r t u a l P i x e l Q u e u e %
2945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2947 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2948 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2950 % The format of the GetVirtualPixelQueue() method is:
2952 % const Quantum *GetVirtualPixelQueue(const Image image)
2954 % A description of each parameter follows:
2956 % o image: the image.
2959 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2962 *restrict cache_info;
2965 id = GetOpenMPThreadId();
2967 assert(image != (const Image *) NULL);
2968 assert(image->signature == MagickSignature);
2969 assert(image->cache != (Cache) NULL);
2970 cache_info=(CacheInfo *) image->cache;
2971 assert(cache_info->signature == MagickSignature);
2972 if (cache_info->methods.get_virtual_pixels_handler !=
2973 (GetVirtualPixelsHandler) NULL)
2974 return(cache_info->methods.get_virtual_pixels_handler(image));
2975 assert(id < (int) cache_info->number_threads);
2976 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2984 % G e t V i r t u a l P i x e l s %
2988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2990 % GetVirtualPixels() returns an immutable pixel region. If the
2991 % region is successfully accessed, a pointer to it is returned, otherwise
2992 % NULL is returned. The returned pointer may point to a temporary working
2993 % copy of the pixels or it may point to the original pixels in memory.
2994 % Performance is maximized if the selected region is part of one row, or one
2995 % or more full rows, since there is opportunity to access the pixels in-place
2996 % (without a copy) if the image is in memory, or in a memory-mapped file. The
2997 % returned pointer must *never* be deallocated by the user.
2999 % Pixels accessed via the returned pointer represent a simple array of type
3000 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3001 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3002 % access the meta-content (of type void) corresponding to the the
3005 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3007 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3008 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3009 % GetCacheViewAuthenticPixels() instead.
3011 % The format of the GetVirtualPixels() method is:
3013 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3014 % const ssize_t y,const size_t columns,const size_t rows,
3015 % ExceptionInfo *exception)
3017 % A description of each parameter follows:
3019 % o image: the image.
3021 % o x,y,columns,rows: These values define the perimeter of a region of
3024 % o exception: return any errors or warnings in this structure.
3027 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3028 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3029 ExceptionInfo *exception)
3032 *restrict cache_info;
3035 id = GetOpenMPThreadId();
3040 assert(image != (const Image *) NULL);
3041 assert(image->signature == MagickSignature);
3042 assert(image->cache != (Cache) NULL);
3043 cache_info=(CacheInfo *) image->cache;
3044 assert(cache_info->signature == MagickSignature);
3045 if (cache_info->methods.get_virtual_pixel_handler !=
3046 (GetVirtualPixelHandler) NULL)
3047 return(cache_info->methods.get_virtual_pixel_handler(image,
3048 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3049 assert(id < (int) cache_info->number_threads);
3050 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3051 columns,rows,cache_info->nexus_info[id],exception);
3056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3060 + 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 %
3064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3066 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3067 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3069 % The format of the GetVirtualPixelsCache() method is:
3071 % Quantum *GetVirtualPixelsCache(const Image *image)
3073 % A description of each parameter follows:
3075 % o image: the image.
3078 static const Quantum *GetVirtualPixelsCache(const Image *image)
3081 *restrict cache_info;
3084 id = GetOpenMPThreadId();
3086 assert(image != (const Image *) NULL);
3087 assert(image->signature == MagickSignature);
3088 assert(image->cache != (Cache) NULL);
3089 cache_info=(CacheInfo *) image->cache;
3090 assert(cache_info->signature == MagickSignature);
3091 assert(id < (int) cache_info->number_threads);
3092 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3100 + G e t V i r t u a l P i x e l s N e x u s %
3104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3106 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3109 % The format of the GetVirtualPixelsNexus() method is:
3111 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3112 % NexusInfo *nexus_info)
3114 % A description of each parameter follows:
3116 % o cache: the pixel cache.
3118 % o nexus_info: the cache nexus to return the colormap pixels.
3121 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3122 NexusInfo *restrict nexus_info)
3125 *restrict cache_info;
3127 assert(cache != (Cache) NULL);
3128 cache_info=(CacheInfo *) cache;
3129 assert(cache_info->signature == MagickSignature);
3130 if (cache_info->storage_class == UndefinedClass)
3131 return((Quantum *) NULL);
3132 return((const Quantum *) nexus_info->pixels);
3136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3140 + O p e n P i x e l C a c h e %
3144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3146 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3147 % dimensions, allocating space for the image pixels and optionally the
3148 % metacontent, and memory mapping the cache if it is disk based. The cache
3149 % nexus array is initialized as well.
3151 % The format of the OpenPixelCache() method is:
3153 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3154 % ExceptionInfo *exception)
3156 % A description of each parameter follows:
3158 % o image: the image.
3160 % o mode: ReadMode, WriteMode, or IOMode.
3162 % o exception: return any errors or warnings in this structure.
3166 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3168 cache_info->mapped=MagickFalse;
3169 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3170 (size_t) cache_info->length));
3171 if (cache_info->pixels == (Quantum *) NULL)
3173 cache_info->mapped=MagickTrue;
3174 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3175 cache_info->length);
3179 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3186 Open pixel cache on disk.
3188 if (cache_info->file != -1)
3189 return(MagickTrue); /* cache already open */
3190 if (*cache_info->cache_filename == '\0')
3191 file=AcquireUniqueFileResource(cache_info->cache_filename);
3197 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3202 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3203 O_BINARY | O_EXCL,S_MODE);
3205 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3211 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3214 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3219 return(MagickFalse);
3220 (void) AcquireMagickResource(FileResource,1);
3221 cache_info->file=file;
3222 cache_info->mode=mode;
3226 static inline MagickOffsetType WritePixelCacheRegion(
3227 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3228 const MagickSizeType length,const unsigned char *restrict buffer)
3230 register MagickOffsetType
3236 #if !defined(MAGICKCORE_HAVE_PWRITE)
3237 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3238 return((MagickOffsetType) -1);
3241 for (i=0; i < (MagickOffsetType) length; i+=count)
3243 #if !defined(MAGICKCORE_HAVE_PWRITE)
3244 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3245 (MagickSizeType) SSIZE_MAX));
3247 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3248 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3260 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3263 *restrict cache_info;
3270 cache_info=(CacheInfo *) image->cache;
3271 if (image->debug != MagickFalse)
3274 format[MaxTextExtent],
3275 message[MaxTextExtent];
3277 (void) FormatMagickSize(length,MagickFalse,format);
3278 (void) FormatLocaleString(message,MaxTextExtent,
3279 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3280 cache_info->cache_filename,cache_info->file,format);
3281 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3283 if (length != (MagickSizeType) ((MagickOffsetType) length))
3284 return(MagickFalse);
3285 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3287 return(MagickFalse);
3288 if ((MagickSizeType) offset >= length)
3290 extent=(MagickOffsetType) length-1;
3291 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3292 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3293 if (cache_info->synchronize != MagickFalse)
3298 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3300 return(MagickFalse);
3303 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3306 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3307 ExceptionInfo *exception)
3310 *restrict cache_info,
3314 format[MaxTextExtent],
3315 message[MaxTextExtent];
3331 assert(image != (const Image *) NULL);
3332 assert(image->signature == MagickSignature);
3333 assert(image->cache != (Cache) NULL);
3334 if (image->debug != MagickFalse)
3335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3336 if ((image->columns == 0) || (image->rows == 0))
3337 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3338 cache_info=(CacheInfo *) image->cache;
3339 assert(cache_info->signature == MagickSignature);
3340 source_info=(*cache_info);
3341 source_info.file=(-1);
3342 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3343 image->filename,(double) GetImageIndexInList(image));
3344 cache_info->storage_class=image->storage_class;
3345 cache_info->colorspace=image->colorspace;
3346 cache_info->alpha_trait=image->alpha_trait;
3347 cache_info->read_mask=image->read_mask;
3348 cache_info->write_mask=image->write_mask;
3349 cache_info->rows=image->rows;
3350 cache_info->columns=image->columns;
3351 InitializePixelChannelMap(image);
3352 cache_info->number_channels=GetPixelChannels(image);
3353 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3354 sizeof(*image->channel_map));
3355 cache_info->metacontent_extent=image->metacontent_extent;
3356 cache_info->mode=mode;
3357 if (image->ping != MagickFalse)
3359 cache_info->type=PingCache;
3360 cache_info->pixels=(Quantum *) NULL;
3361 cache_info->metacontent=(void *) NULL;
3362 cache_info->length=0;
3365 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3366 packet_size=cache_info->number_channels*sizeof(Quantum);
3367 if (image->metacontent_extent != 0)
3368 packet_size+=cache_info->metacontent_extent;
3369 length=number_pixels*packet_size;
3370 columns=(size_t) (length/cache_info->rows/packet_size);
3371 if (cache_info->columns != columns)
3372 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3374 cache_info->length=length;
3375 status=AcquireMagickResource(AreaResource,cache_info->length);
3376 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3377 cache_info->metacontent_extent);
3378 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3380 status=AcquireMagickResource(MemoryResource,cache_info->length);
3381 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3382 (cache_info->type == MemoryCache))
3384 AllocatePixelCachePixels(cache_info);
3385 if (cache_info->pixels == (Quantum *) NULL)
3386 cache_info->pixels=source_info.pixels;
3390 Create memory pixel cache.
3393 cache_info->type=MemoryCache;
3394 cache_info->metacontent=(void *) NULL;
3395 if (cache_info->metacontent_extent != 0)
3396 cache_info->metacontent=(void *) (cache_info->pixels+
3397 number_pixels*cache_info->number_channels);
3398 if ((source_info.storage_class != UndefinedClass) &&
3401 status=ClonePixelCacheRepository(cache_info,&source_info,
3403 RelinquishPixelCachePixels(&source_info);
3405 if (image->debug != MagickFalse)
3407 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3408 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3410 (void) FormatLocaleString(message,MaxTextExtent,
3411 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3412 cache_info->filename,cache_info->mapped != MagickFalse ?
3413 "Anonymous" : "Heap",type,(double) cache_info->columns,
3414 (double) cache_info->rows,(double)
3415 cache_info->number_channels,format);
3416 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3422 RelinquishMagickResource(MemoryResource,cache_info->length);
3425 Create pixel cache on disk.
3427 status=AcquireMagickResource(DiskResource,cache_info->length);
3428 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3433 if (cache_info->type == DistributedCache)
3434 RelinquishMagickResource(DiskResource,cache_info->length);
3435 server_info=AcquireDistributeCacheInfo(exception);
3436 if (server_info != (DistributeCacheInfo *) NULL)
3438 status=OpenDistributePixelCache(server_info,image);
3439 if (status == MagickFalse)
3441 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3442 GetDistributeCacheHostname(server_info));
3443 server_info=DestroyDistributeCacheInfo(server_info);
3448 Create a distributed pixel cache.
3450 cache_info->type=DistributedCache;
3451 cache_info->server_info=server_info;
3452 (void) FormatLocaleString(cache_info->cache_filename,
3453 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3454 (DistributeCacheInfo *) cache_info->server_info),
3455 GetDistributeCachePort((DistributeCacheInfo *)
3456 cache_info->server_info));
3457 if ((source_info.storage_class != UndefinedClass) &&
3460 status=ClonePixelCacheRepository(cache_info,&source_info,
3462 RelinquishPixelCachePixels(&source_info);
3464 if (image->debug != MagickFalse)
3466 (void) FormatMagickSize(cache_info->length,MagickFalse,
3468 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3470 (void) FormatLocaleString(message,MaxTextExtent,
3471 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3472 cache_info->filename,cache_info->cache_filename,
3473 GetDistributeCacheFile((DistributeCacheInfo *)
3474 cache_info->server_info),type,(double) cache_info->columns,
3475 (double) cache_info->rows,(double)
3476 cache_info->number_channels,format);
3477 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3483 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3484 "CacheResourcesExhausted","`%s'",image->filename);
3485 return(MagickFalse);
3487 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3489 (void) ClosePixelCacheOnDisk(cache_info);
3490 *cache_info->cache_filename='\0';
3492 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3494 RelinquishMagickResource(DiskResource,cache_info->length);
3495 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3497 return(MagickFalse);
3499 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3500 cache_info->length);
3501 if (status == MagickFalse)
3503 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3505 return(MagickFalse);
3507 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3508 cache_info->metacontent_extent);
3509 if (length != (MagickSizeType) ((size_t) length))
3510 cache_info->type=DiskCache;
3513 status=AcquireMagickResource(MapResource,cache_info->length);
3514 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3515 (cache_info->type != MemoryCache))
3516 cache_info->type=DiskCache;
3519 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3520 cache_info->offset,(size_t) cache_info->length);
3521 if (cache_info->pixels == (Quantum *) NULL)
3523 cache_info->type=DiskCache;
3524 cache_info->pixels=source_info.pixels;
3529 Create file-backed memory-mapped pixel cache.
3532 (void) ClosePixelCacheOnDisk(cache_info);
3533 cache_info->type=MapCache;
3534 cache_info->mapped=MagickTrue;
3535 cache_info->metacontent=(void *) NULL;
3536 if (cache_info->metacontent_extent != 0)
3537 cache_info->metacontent=(void *) (cache_info->pixels+
3538 number_pixels*cache_info->number_channels);
3539 if ((source_info.storage_class != UndefinedClass) &&
3542 status=ClonePixelCacheRepository(cache_info,&source_info,
3544 RelinquishPixelCachePixels(&source_info);
3546 if (image->debug != MagickFalse)
3548 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3549 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3551 (void) FormatLocaleString(message,MaxTextExtent,
3552 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3553 cache_info->filename,cache_info->cache_filename,
3554 cache_info->file,type,(double) cache_info->columns,(double)
3555 cache_info->rows,(double) cache_info->number_channels,
3557 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3563 RelinquishMagickResource(MapResource,cache_info->length);
3566 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3568 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3569 RelinquishPixelCachePixels(&source_info);
3571 if (image->debug != MagickFalse)
3573 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3574 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3576 (void) FormatLocaleString(message,MaxTextExtent,
3577 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3578 cache_info->cache_filename,cache_info->file,type,(double)
3579 cache_info->columns,(double) cache_info->rows,(double)
3580 cache_info->number_channels,format);
3581 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3591 + P e r s i s t P i x e l C a c h e %
3595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3598 % persistent pixel cache is one that resides on disk and is not destroyed
3599 % when the program exits.
3601 % The format of the PersistPixelCache() method is:
3603 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3604 % const MagickBooleanType attach,MagickOffsetType *offset,
3605 % ExceptionInfo *exception)
3607 % A description of each parameter follows:
3609 % o image: the image.
3611 % o filename: the persistent pixel cache filename.
3613 % o attach: A value other than zero initializes the persistent pixel cache.
3615 % o initialize: A value other than zero initializes the persistent pixel
3618 % o offset: the offset in the persistent cache to store pixels.
3620 % o exception: return any errors or warnings in this structure.
3623 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3624 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3625 ExceptionInfo *exception)
3628 *restrict cache_info,
3629 *restrict clone_info;
3640 assert(image != (Image *) NULL);
3641 assert(image->signature == MagickSignature);
3642 if (image->debug != MagickFalse)
3643 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3644 assert(image->cache != (void *) NULL);
3645 assert(filename != (const char *) NULL);
3646 assert(offset != (MagickOffsetType *) NULL);
3647 page_size=GetMagickPageSize();
3648 cache_info=(CacheInfo *) image->cache;
3649 assert(cache_info->signature == MagickSignature);
3650 if (attach != MagickFalse)
3653 Attach existing persistent pixel cache.
3655 if (image->debug != MagickFalse)
3656 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3657 "attach persistent cache");
3658 (void) CopyMagickString(cache_info->cache_filename,filename,
3660 cache_info->type=DiskCache;
3661 cache_info->offset=(*offset);
3662 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3663 return(MagickFalse);
3664 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3667 if ((cache_info->mode != ReadMode) &&
3668 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3669 (cache_info->reference_count == 1))
3671 LockSemaphoreInfo(cache_info->semaphore);
3672 if ((cache_info->mode != ReadMode) &&
3673 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3674 (cache_info->reference_count == 1))
3680 Usurp existing persistent pixel cache.
3682 status=rename_utf8(cache_info->cache_filename,filename);
3685 (void) CopyMagickString(cache_info->cache_filename,filename,
3687 *offset+=cache_info->length+page_size-(cache_info->length %
3689 UnlockSemaphoreInfo(cache_info->semaphore);
3690 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3691 if (image->debug != MagickFalse)
3692 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3693 "Usurp resident persistent cache");
3697 UnlockSemaphoreInfo(cache_info->semaphore);
3700 Clone persistent pixel cache.
3702 clone_image=(*image);
3703 clone_info=(CacheInfo *) clone_image.cache;
3704 image->cache=ClonePixelCache(cache_info);
3705 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3706 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3707 cache_info->type=DiskCache;
3708 cache_info->offset=(*offset);
3709 cache_info=(CacheInfo *) image->cache;
3710 status=OpenPixelCache(image,IOMode,exception);
3711 if (status != MagickFalse)
3712 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3713 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3714 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3723 + 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 %
3727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3729 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3730 % defined by the region rectangle and returns a pointer to the region. This
3731 % region is subsequently transferred from the pixel cache with
3732 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3733 % pixels are transferred, otherwise a NULL is returned.
3735 % The format of the QueueAuthenticPixelCacheNexus() method is:
3737 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3738 % const ssize_t y,const size_t columns,const size_t rows,
3739 % const MagickBooleanType clone,NexusInfo *nexus_info,
3740 % ExceptionInfo *exception)
3742 % A description of each parameter follows:
3744 % o image: the image.
3746 % o x,y,columns,rows: These values define the perimeter of a region of
3749 % o nexus_info: the cache nexus to set.
3751 % o clone: clone the pixel cache.
3753 % o exception: return any errors or warnings in this structure.
3756 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3757 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3758 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3761 *restrict cache_info;
3776 Validate pixel cache geometry.
3778 assert(image != (const Image *) NULL);
3779 assert(image->signature == MagickSignature);
3780 assert(image->cache != (Cache) NULL);
3781 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3782 if (cache_info == (Cache) NULL)
3783 return((Quantum *) NULL);
3784 assert(cache_info->signature == MagickSignature);
3785 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3786 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3787 (y >= (ssize_t) cache_info->rows))
3789 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3790 "PixelsAreNotAuthentic","`%s'",image->filename);
3791 return((Quantum *) NULL);
3793 offset=(MagickOffsetType) y*cache_info->columns+x;
3795 return((Quantum *) NULL);
3796 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3797 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3798 if ((MagickSizeType) offset >= number_pixels)
3799 return((Quantum *) NULL);
3805 region.width=columns;
3807 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3817 + 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 %
3821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3823 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3824 % defined by the region rectangle and returns a pointer to the region. This
3825 % region is subsequently transferred from the pixel cache with
3826 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3827 % pixels are transferred, otherwise a NULL is returned.
3829 % The format of the QueueAuthenticPixelsCache() method is:
3831 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3832 % const ssize_t y,const size_t columns,const size_t rows,
3833 % ExceptionInfo *exception)
3835 % A description of each parameter follows:
3837 % o image: the image.
3839 % o x,y,columns,rows: These values define the perimeter of a region of
3842 % o exception: return any errors or warnings in this structure.
3845 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3846 const ssize_t y,const size_t columns,const size_t rows,
3847 ExceptionInfo *exception)
3850 *restrict cache_info;
3853 id = GetOpenMPThreadId();
3858 assert(image != (const Image *) NULL);
3859 assert(image->signature == MagickSignature);
3860 assert(image->cache != (Cache) NULL);
3861 cache_info=(CacheInfo *) image->cache;
3862 assert(cache_info->signature == MagickSignature);
3863 assert(id < (int) cache_info->number_threads);
3864 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3865 cache_info->nexus_info[id],exception);
3870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3874 % Q u e u e A u t h e n t i c P i x e l s %
3878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3880 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3881 % successfully initialized a pointer to a Quantum array representing the
3882 % region is returned, otherwise NULL is returned. The returned pointer may
3883 % point to a temporary working buffer for the pixels or it may point to the
3884 % final location of the pixels in memory.
3886 % Write-only access means that any existing pixel values corresponding to
3887 % the region are ignored. This is useful if the initial image is being
3888 % created from scratch, or if the existing pixel values are to be
3889 % completely replaced without need to refer to their pre-existing values.
3890 % The application is free to read and write the pixel buffer returned by
3891 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3892 % initialize the pixel array values. Initializing pixel array values is the
3893 % application's responsibility.
3895 % Performance is maximized if the selected region is part of one row, or
3896 % one or more full rows, since then there is opportunity to access the
3897 % pixels in-place (without a copy) if the image is in memory, or in a
3898 % memory-mapped file. The returned pointer must *never* be deallocated
3901 % Pixels accessed via the returned pointer represent a simple array of type
3902 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3903 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3904 % obtain the meta-content (of type void) corresponding to the region.
3905 % Once the Quantum (and/or Quantum) array has been updated, the
3906 % changes must be saved back to the underlying image using
3907 % SyncAuthenticPixels() or they may be lost.
3909 % The format of the QueueAuthenticPixels() method is:
3911 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3912 % const ssize_t y,const size_t columns,const size_t rows,
3913 % ExceptionInfo *exception)
3915 % A description of each parameter follows:
3917 % o image: the image.
3919 % o x,y,columns,rows: These values define the perimeter of a region of
3922 % o exception: return any errors or warnings in this structure.
3925 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3926 const ssize_t y,const size_t columns,const size_t rows,
3927 ExceptionInfo *exception)
3930 *restrict cache_info;
3933 id = GetOpenMPThreadId();
3938 assert(image != (Image *) NULL);
3939 assert(image->signature == MagickSignature);
3940 assert(image->cache != (Cache) NULL);
3941 cache_info=(CacheInfo *) image->cache;
3942 assert(cache_info->signature == MagickSignature);
3943 if (cache_info->methods.queue_authentic_pixels_handler !=
3944 (QueueAuthenticPixelsHandler) NULL)
3946 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3947 columns,rows,exception);
3950 assert(id < (int) cache_info->number_threads);
3951 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3952 cache_info->nexus_info[id],exception);
3957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3961 + 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 %
3965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3970 % The format of the ReadPixelCacheMetacontent() method is:
3972 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
3973 % NexusInfo *nexus_info,ExceptionInfo *exception)
3975 % A description of each parameter follows:
3977 % o cache_info: the pixel cache.
3979 % o nexus_info: the cache nexus to read the metacontent.
3981 % o exception: return any errors or warnings in this structure.
3985 static inline MagickOffsetType ReadPixelCacheRegion(
3986 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3987 const MagickSizeType length,unsigned char *restrict buffer)
3989 register MagickOffsetType
3995 #if !defined(MAGICKCORE_HAVE_PREAD)
3996 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3997 return((MagickOffsetType) -1);
4000 for (i=0; i < (MagickOffsetType) length; i+=count)
4002 #if !defined(MAGICKCORE_HAVE_PREAD)
4003 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4004 (MagickSizeType) SSIZE_MAX));
4006 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4007 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4019 static MagickBooleanType ReadPixelCacheMetacontent(
4020 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4021 ExceptionInfo *exception)
4034 register unsigned char
4040 if (cache_info->metacontent_extent == 0)
4041 return(MagickFalse);
4042 if (nexus_info->authentic_pixel_cache != MagickFalse)
4044 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4045 nexus_info->region.x;
4046 length=(MagickSizeType) nexus_info->region.width*
4047 cache_info->metacontent_extent;
4048 extent=length*nexus_info->region.height;
4049 rows=nexus_info->region.height;
4051 q=(unsigned char *) nexus_info->metacontent;
4052 switch (cache_info->type)
4057 register unsigned char
4061 Read meta-content from memory.
4063 if ((cache_info->columns == nexus_info->region.width) &&
4064 (extent == (MagickSizeType) ((size_t) extent)))
4069 p=(unsigned char *) cache_info->metacontent+offset*
4070 cache_info->metacontent_extent;
4071 for (y=0; y < (ssize_t) rows; y++)
4073 (void) memcpy(q,p,(size_t) length);
4074 p+=cache_info->metacontent_extent*cache_info->columns;
4075 q+=cache_info->metacontent_extent*nexus_info->region.width;
4082 Read meta content from disk.
4084 LockSemaphoreInfo(cache_info->file_semaphore);
4085 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4087 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4088 cache_info->cache_filename);
4089 UnlockSemaphoreInfo(cache_info->file_semaphore);
4090 return(MagickFalse);
4092 if ((cache_info->columns == nexus_info->region.width) &&
4093 (extent <= MagickMaxBufferExtent))
4098 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4099 for (y=0; y < (ssize_t) rows; y++)
4101 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4102 cache_info->number_channels*sizeof(Quantum)+offset*
4103 cache_info->metacontent_extent,length,(unsigned char *) q);
4104 if (count != (MagickOffsetType) length)
4106 offset+=cache_info->columns;
4107 q+=cache_info->metacontent_extent*nexus_info->region.width;
4109 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4110 (void) ClosePixelCacheOnDisk(cache_info);
4111 UnlockSemaphoreInfo(cache_info->file_semaphore);
4114 case DistributedCache:
4120 Read metacontent from distributed cache.
4122 LockSemaphoreInfo(cache_info->file_semaphore);
4123 region=nexus_info->region;
4124 if ((cache_info->columns != nexus_info->region.width) ||
4125 (extent > MagickMaxBufferExtent))
4132 for (y=0; y < (ssize_t) rows; y++)
4134 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4135 cache_info->server_info,®ion,length,(unsigned char *) q);
4136 if (count != (MagickOffsetType) length)
4138 q+=cache_info->metacontent_extent*nexus_info->region.width;
4141 UnlockSemaphoreInfo(cache_info->file_semaphore);
4147 if (y < (ssize_t) rows)
4149 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4150 cache_info->cache_filename);
4151 return(MagickFalse);
4153 if ((cache_info->debug != MagickFalse) &&
4154 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4155 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4156 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4157 nexus_info->region.width,(double) nexus_info->region.height,(double)
4158 nexus_info->region.x,(double) nexus_info->region.y);
4163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4167 + R e a d P i x e l C a c h e P i x e l s %
4171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4173 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4176 % The format of the ReadPixelCachePixels() method is:
4178 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4179 % NexusInfo *nexus_info,ExceptionInfo *exception)
4181 % A description of each parameter follows:
4183 % o cache_info: the pixel cache.
4185 % o nexus_info: the cache nexus to read the pixels.
4187 % o exception: return any errors or warnings in this structure.
4190 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4191 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4210 if (nexus_info->authentic_pixel_cache != MagickFalse)
4212 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4213 nexus_info->region.x;
4214 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4216 extent=length*nexus_info->region.height;
4217 rows=nexus_info->region.height;
4219 q=nexus_info->pixels;
4220 switch (cache_info->type)
4229 Read pixels from memory.
4231 if ((cache_info->columns == nexus_info->region.width) &&
4232 (extent == (MagickSizeType) ((size_t) extent)))
4237 p=cache_info->pixels+offset*cache_info->number_channels;
4238 for (y=0; y < (ssize_t) rows; y++)
4240 (void) memcpy(q,p,(size_t) length);
4241 p+=cache_info->number_channels*cache_info->columns;
4242 q+=cache_info->number_channels*nexus_info->region.width;
4249 Read pixels from disk.
4251 LockSemaphoreInfo(cache_info->file_semaphore);
4252 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4254 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4255 cache_info->cache_filename);
4256 UnlockSemaphoreInfo(cache_info->file_semaphore);
4257 return(MagickFalse);
4259 if ((cache_info->columns == nexus_info->region.width) &&
4260 (extent <= MagickMaxBufferExtent))
4265 for (y=0; y < (ssize_t) rows; y++)
4267 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4268 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4269 if (count != (MagickOffsetType) length)
4271 offset+=cache_info->columns;
4272 q+=cache_info->number_channels*nexus_info->region.width;
4274 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4275 (void) ClosePixelCacheOnDisk(cache_info);
4276 UnlockSemaphoreInfo(cache_info->file_semaphore);
4279 case DistributedCache:
4285 Read pixels from distributed cache.
4287 LockSemaphoreInfo(cache_info->file_semaphore);
4288 region=nexus_info->region;
4289 if ((cache_info->columns != nexus_info->region.width) ||
4290 (extent > MagickMaxBufferExtent))
4297 for (y=0; y < (ssize_t) rows; y++)
4299 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4300 cache_info->server_info,®ion,length,(unsigned char *) q);
4301 if (count != (MagickOffsetType) length)
4303 q+=cache_info->number_channels*nexus_info->region.width;
4306 UnlockSemaphoreInfo(cache_info->file_semaphore);
4312 if (y < (ssize_t) rows)
4314 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4315 cache_info->cache_filename);
4316 return(MagickFalse);
4318 if ((cache_info->debug != MagickFalse) &&
4319 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4320 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4321 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4322 nexus_info->region.width,(double) nexus_info->region.height,(double)
4323 nexus_info->region.x,(double) nexus_info->region.y);
4328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4332 + R e f e r e n c e P i x e l C a c h e %
4336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4338 % ReferencePixelCache() increments the reference count associated with the
4339 % pixel cache returning a pointer to the cache.
4341 % The format of the ReferencePixelCache method is:
4343 % Cache ReferencePixelCache(Cache cache_info)
4345 % A description of each parameter follows:
4347 % o cache_info: the pixel cache.
4350 MagickPrivate Cache ReferencePixelCache(Cache cache)
4353 *restrict cache_info;
4355 assert(cache != (Cache *) NULL);
4356 cache_info=(CacheInfo *) cache;
4357 assert(cache_info->signature == MagickSignature);
4358 LockSemaphoreInfo(cache_info->semaphore);
4359 cache_info->reference_count++;
4360 UnlockSemaphoreInfo(cache_info->semaphore);
4365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4369 + S e t P i x e l C a c h e M e t h o d s %
4373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4377 % The format of the SetPixelCacheMethods() method is:
4379 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4381 % A description of each parameter follows:
4383 % o cache: the pixel cache.
4385 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4388 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4391 *restrict cache_info;
4393 GetOneAuthenticPixelFromHandler
4394 get_one_authentic_pixel_from_handler;
4396 GetOneVirtualPixelFromHandler
4397 get_one_virtual_pixel_from_handler;
4400 Set cache pixel methods.
4402 assert(cache != (Cache) NULL);
4403 assert(cache_methods != (CacheMethods *) NULL);
4404 cache_info=(CacheInfo *) cache;
4405 assert(cache_info->signature == MagickSignature);
4406 if (cache_info->debug != MagickFalse)
4407 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4408 cache_info->filename);
4409 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4410 cache_info->methods.get_virtual_pixel_handler=
4411 cache_methods->get_virtual_pixel_handler;
4412 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4413 cache_info->methods.destroy_pixel_handler=
4414 cache_methods->destroy_pixel_handler;
4415 if (cache_methods->get_virtual_metacontent_from_handler !=
4416 (GetVirtualMetacontentFromHandler) NULL)
4417 cache_info->methods.get_virtual_metacontent_from_handler=
4418 cache_methods->get_virtual_metacontent_from_handler;
4419 if (cache_methods->get_authentic_pixels_handler !=
4420 (GetAuthenticPixelsHandler) NULL)
4421 cache_info->methods.get_authentic_pixels_handler=
4422 cache_methods->get_authentic_pixels_handler;
4423 if (cache_methods->queue_authentic_pixels_handler !=
4424 (QueueAuthenticPixelsHandler) NULL)
4425 cache_info->methods.queue_authentic_pixels_handler=
4426 cache_methods->queue_authentic_pixels_handler;
4427 if (cache_methods->sync_authentic_pixels_handler !=
4428 (SyncAuthenticPixelsHandler) NULL)
4429 cache_info->methods.sync_authentic_pixels_handler=
4430 cache_methods->sync_authentic_pixels_handler;
4431 if (cache_methods->get_authentic_pixels_from_handler !=
4432 (GetAuthenticPixelsFromHandler) NULL)
4433 cache_info->methods.get_authentic_pixels_from_handler=
4434 cache_methods->get_authentic_pixels_from_handler;
4435 if (cache_methods->get_authentic_metacontent_from_handler !=
4436 (GetAuthenticMetacontentFromHandler) NULL)
4437 cache_info->methods.get_authentic_metacontent_from_handler=
4438 cache_methods->get_authentic_metacontent_from_handler;
4439 get_one_virtual_pixel_from_handler=
4440 cache_info->methods.get_one_virtual_pixel_from_handler;
4441 if (get_one_virtual_pixel_from_handler !=
4442 (GetOneVirtualPixelFromHandler) NULL)
4443 cache_info->methods.get_one_virtual_pixel_from_handler=
4444 cache_methods->get_one_virtual_pixel_from_handler;
4445 get_one_authentic_pixel_from_handler=
4446 cache_methods->get_one_authentic_pixel_from_handler;
4447 if (get_one_authentic_pixel_from_handler !=
4448 (GetOneAuthenticPixelFromHandler) NULL)
4449 cache_info->methods.get_one_authentic_pixel_from_handler=
4450 cache_methods->get_one_authentic_pixel_from_handler;
4454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4458 + S e t P i x e l C a c h e N e x u s P i x e l s %
4462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4464 % SetPixelCacheNexusPixels() defines the region of the cache for the
4465 % specified cache nexus.
4467 % The format of the SetPixelCacheNexusPixels() method is:
4469 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4470 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4471 % ExceptionInfo *exception)
4473 % A description of each parameter follows:
4475 % o cache_info: the pixel cache.
4477 % o mode: ReadMode, WriteMode, or IOMode.
4479 % o region: A pointer to the RectangleInfo structure that defines the
4480 % region of this particular cache nexus.
4482 % o nexus_info: the cache nexus to set.
4484 % o exception: return any errors or warnings in this structure.
4488 static inline MagickBooleanType AcquireCacheNexusPixels(
4489 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4490 ExceptionInfo *exception)
4492 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4493 return(MagickFalse);
4494 nexus_info->mapped=MagickFalse;
4495 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4496 (size_t) nexus_info->length));
4497 if (nexus_info->cache == (Quantum *) NULL)
4499 nexus_info->mapped=MagickTrue;
4500 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4501 nexus_info->length);
4503 if (nexus_info->cache == (Quantum *) NULL)
4505 (void) ThrowMagickException(exception,GetMagickModule(),
4506 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4507 cache_info->filename);
4508 return(MagickFalse);
4513 static inline MagickBooleanType IsPixelCacheAuthentic(
4514 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4523 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4525 if (cache_info->type == PingCache)
4527 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4528 nexus_info->region.x;
4529 status=nexus_info->pixels == (cache_info->pixels+offset*
4530 cache_info->number_channels) ? MagickTrue : MagickFalse;
4534 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4537 if (mode == ReadMode)
4539 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4542 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4545 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4546 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4547 ExceptionInfo *exception)
4556 assert(cache_info != (const CacheInfo *) NULL);
4557 assert(cache_info->signature == MagickSignature);
4558 if (cache_info->type == UndefinedCache)
4559 return((Quantum *) NULL);
4560 nexus_info->region=(*region);
4561 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4567 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4568 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4569 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4570 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4571 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4572 ((nexus_info->region.width == cache_info->columns) ||
4573 ((nexus_info->region.width % cache_info->columns) == 0)))))
4579 Pixels are accessed directly from memory.
4581 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4582 nexus_info->region.x;
4583 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4585 nexus_info->metacontent=(void *) NULL;
4586 if (cache_info->metacontent_extent != 0)
4587 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4588 offset*cache_info->metacontent_extent;
4589 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4590 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4592 return(nexus_info->pixels);
4596 Pixels are stored in a staging region until they are synced to the cache.
4598 number_pixels=(MagickSizeType) nexus_info->region.width*
4599 nexus_info->region.height;
4600 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4601 if (cache_info->metacontent_extent != 0)
4602 length+=number_pixels*cache_info->metacontent_extent;
4603 if (nexus_info->cache == (Quantum *) NULL)
4605 nexus_info->length=length;
4606 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4607 if (status == MagickFalse)
4609 nexus_info->length=0;
4610 return((Quantum *) NULL);
4614 if (nexus_info->length < length)
4616 RelinquishCacheNexusPixels(nexus_info);
4617 nexus_info->length=length;
4618 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4619 if (status == MagickFalse)
4621 nexus_info->length=0;
4622 return((Quantum *) NULL);
4625 nexus_info->pixels=nexus_info->cache;
4626 nexus_info->metacontent=(void *) NULL;
4627 if (cache_info->metacontent_extent != 0)
4628 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4629 cache_info->number_channels);
4630 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4631 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4633 return(nexus_info->pixels);
4637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4641 % 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 %
4645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4647 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4648 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4649 % access that is outside the boundaries of the image cache.
4651 % The format of the SetPixelCacheVirtualMethod() method is:
4653 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4654 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4656 % A description of each parameter follows:
4658 % o image: the image.
4660 % o virtual_pixel_method: choose the type of virtual pixel.
4662 % o exception: return any errors or warnings in this structure.
4666 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4667 ExceptionInfo *exception)
4670 *restrict cache_info;
4673 *restrict image_view;
4681 assert(image != (Image *) NULL);
4682 assert(image->signature == MagickSignature);
4683 if (image->debug != MagickFalse)
4684 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4685 assert(image->cache != (Cache) NULL);
4686 cache_info=(CacheInfo *) image->cache;
4687 assert(cache_info->signature == MagickSignature);
4688 image->alpha_trait=BlendPixelTrait;
4690 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4691 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4692 #pragma omp parallel for schedule(static,4) shared(status) \
4693 magick_threads(image,image,1,1)
4695 for (y=0; y < (ssize_t) image->rows; y++)
4703 if (status == MagickFalse)
4705 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4706 if (q == (Quantum *) NULL)
4711 for (x=0; x < (ssize_t) image->columns; x++)
4713 SetPixelAlpha(image,alpha,q);
4714 q+=GetPixelChannels(image);
4716 status=SyncCacheViewAuthenticPixels(image_view,exception);
4718 image_view=DestroyCacheView(image_view);
4722 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4723 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4726 *restrict cache_info;
4731 assert(image != (Image *) NULL);
4732 assert(image->signature == MagickSignature);
4733 if (image->debug != MagickFalse)
4734 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4735 assert(image->cache != (Cache) NULL);
4736 cache_info=(CacheInfo *) image->cache;
4737 assert(cache_info->signature == MagickSignature);
4738 method=cache_info->virtual_pixel_method;
4739 cache_info->virtual_pixel_method=virtual_pixel_method;
4740 if ((image->columns != 0) && (image->rows != 0))
4741 switch (virtual_pixel_method)
4743 case BackgroundVirtualPixelMethod:
4745 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4746 (image->alpha_trait != BlendPixelTrait))
4747 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4748 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4749 (IsGrayColorspace(image->colorspace) != MagickFalse))
4750 (void) SetImageColorspace(image,sRGBColorspace,exception);
4753 case TransparentVirtualPixelMethod:
4755 if (image->alpha_trait != BlendPixelTrait)
4756 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4770 + 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 %
4774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4776 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4777 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4778 % is synced, otherwise MagickFalse.
4780 % The format of the SyncAuthenticPixelCacheNexus() method is:
4782 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4783 % NexusInfo *nexus_info,ExceptionInfo *exception)
4785 % A description of each parameter follows:
4787 % o image: the image.
4789 % o nexus_info: the cache nexus to sync.
4791 % o exception: return any errors or warnings in this structure.
4794 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4795 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4798 *restrict cache_info;
4804 Transfer pixels to the cache.
4806 assert(image != (Image *) NULL);
4807 assert(image->signature == MagickSignature);
4808 if (image->cache == (Cache) NULL)
4809 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4810 cache_info=(CacheInfo *) image->cache;
4811 assert(cache_info->signature == MagickSignature);
4812 if (cache_info->type == UndefinedCache)
4813 return(MagickFalse);
4814 if (nexus_info->authentic_pixel_cache != MagickFalse)
4816 assert(cache_info->signature == MagickSignature);
4817 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4818 if ((cache_info->metacontent_extent != 0) &&
4819 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4820 return(MagickFalse);
4825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4829 + S y n c A u t h e n t i c P i x e l C a c h e %
4833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4835 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4836 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4837 % otherwise MagickFalse.
4839 % The format of the SyncAuthenticPixelsCache() method is:
4841 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4842 % ExceptionInfo *exception)
4844 % A description of each parameter follows:
4846 % o image: the image.
4848 % o exception: return any errors or warnings in this structure.
4851 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4852 ExceptionInfo *exception)
4855 *restrict cache_info;
4858 id = GetOpenMPThreadId();
4863 assert(image != (Image *) NULL);
4864 assert(image->signature == MagickSignature);
4865 assert(image->cache != (Cache) NULL);
4866 cache_info=(CacheInfo *) image->cache;
4867 assert(cache_info->signature == MagickSignature);
4868 assert(id < (int) cache_info->number_threads);
4869 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4879 % S y n c A u t h e n t i c P i x e l s %
4883 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4885 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4886 % The method returns MagickTrue if the pixel region is flushed, otherwise
4889 % The format of the SyncAuthenticPixels() method is:
4891 % MagickBooleanType SyncAuthenticPixels(Image *image,
4892 % ExceptionInfo *exception)
4894 % A description of each parameter follows:
4896 % o image: the image.
4898 % o exception: return any errors or warnings in this structure.
4901 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4902 ExceptionInfo *exception)
4905 *restrict cache_info;
4908 id = GetOpenMPThreadId();
4913 assert(image != (Image *) NULL);
4914 assert(image->signature == MagickSignature);
4915 assert(image->cache != (Cache) NULL);
4916 cache_info=(CacheInfo *) image->cache;
4917 assert(cache_info->signature == MagickSignature);
4918 if (cache_info->methods.sync_authentic_pixels_handler !=
4919 (SyncAuthenticPixelsHandler) NULL)
4921 status=cache_info->methods.sync_authentic_pixels_handler(image,
4925 assert(id < (int) cache_info->number_threads);
4926 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4936 + S y n c I m a g e P i x e l C a c h e %
4940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4942 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4943 % The method returns MagickTrue if the pixel region is flushed, otherwise
4946 % The format of the SyncImagePixelCache() method is:
4948 % MagickBooleanType SyncImagePixelCache(Image *image,
4949 % ExceptionInfo *exception)
4951 % A description of each parameter follows:
4953 % o image: the image.
4955 % o exception: return any errors or warnings in this structure.
4958 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4959 ExceptionInfo *exception)
4962 *restrict cache_info;
4964 assert(image != (Image *) NULL);
4965 assert(exception != (ExceptionInfo *) NULL);
4966 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4967 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4975 + 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 %
4979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4981 % WritePixelCacheMetacontent() writes the meta-content to the specified region
4982 % of the pixel cache.
4984 % The format of the WritePixelCacheMetacontent() method is:
4986 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4987 % NexusInfo *nexus_info,ExceptionInfo *exception)
4989 % A description of each parameter follows:
4991 % o cache_info: the pixel cache.
4993 % o nexus_info: the cache nexus to write the meta-content.
4995 % o exception: return any errors or warnings in this structure.
4998 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4999 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5009 register const unsigned char
5018 if (cache_info->metacontent_extent == 0)
5019 return(MagickFalse);
5020 if (nexus_info->authentic_pixel_cache != MagickFalse)
5022 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5023 nexus_info->region.x;
5024 length=(MagickSizeType) nexus_info->region.width*
5025 cache_info->metacontent_extent;
5026 extent=(MagickSizeType) length*nexus_info->region.height;
5027 rows=nexus_info->region.height;
5029 p=(unsigned char *) nexus_info->metacontent;
5030 switch (cache_info->type)
5035 register unsigned char
5039 Write associated pixels to memory.
5041 if ((cache_info->columns == nexus_info->region.width) &&
5042 (extent == (MagickSizeType) ((size_t) extent)))
5047 q=(unsigned char *) cache_info->metacontent+offset*
5048 cache_info->metacontent_extent;
5049 for (y=0; y < (ssize_t) rows; y++)
5051 (void) memcpy(q,p,(size_t) length);
5052 p+=nexus_info->region.width*cache_info->metacontent_extent;
5053 q+=cache_info->columns*cache_info->metacontent_extent;
5060 Write associated pixels to disk.
5062 LockSemaphoreInfo(cache_info->file_semaphore);
5063 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5065 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5066 cache_info->cache_filename);
5067 UnlockSemaphoreInfo(cache_info->file_semaphore);
5068 return(MagickFalse);
5070 if ((cache_info->columns == nexus_info->region.width) &&
5071 (extent <= MagickMaxBufferExtent))
5076 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5077 for (y=0; y < (ssize_t) rows; y++)
5079 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5080 cache_info->number_channels*sizeof(Quantum)+offset*
5081 cache_info->metacontent_extent,length,(const unsigned char *) p);
5082 if (count != (MagickOffsetType) length)
5084 p+=cache_info->metacontent_extent*nexus_info->region.width;
5085 offset+=cache_info->columns;
5087 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5088 (void) ClosePixelCacheOnDisk(cache_info);
5089 UnlockSemaphoreInfo(cache_info->file_semaphore);
5092 case DistributedCache:
5098 Write metacontent to distributed cache.
5100 LockSemaphoreInfo(cache_info->file_semaphore);
5101 region=nexus_info->region;
5102 if ((cache_info->columns != nexus_info->region.width) ||
5103 (extent > MagickMaxBufferExtent))
5110 for (y=0; y < (ssize_t) rows; y++)
5112 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5113 cache_info->server_info,®ion,length,(const unsigned char *) p);
5114 if (count != (MagickOffsetType) length)
5116 p+=cache_info->metacontent_extent*nexus_info->region.width;
5119 UnlockSemaphoreInfo(cache_info->file_semaphore);
5125 if (y < (ssize_t) rows)
5127 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5128 cache_info->cache_filename);
5129 return(MagickFalse);
5131 if ((cache_info->debug != MagickFalse) &&
5132 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5133 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5134 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5135 nexus_info->region.width,(double) nexus_info->region.height,(double)
5136 nexus_info->region.x,(double) nexus_info->region.y);
5141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5145 + W r i t e C a c h e P i x e l s %
5149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151 % WritePixelCachePixels() writes image pixels to the specified region of the
5154 % The format of the WritePixelCachePixels() method is:
5156 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5157 % NexusInfo *nexus_info,ExceptionInfo *exception)
5159 % A description of each parameter follows:
5161 % o cache_info: the pixel cache.
5163 % o nexus_info: the cache nexus to write the pixels.
5165 % o exception: return any errors or warnings in this structure.
5168 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5169 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5179 register const Quantum
5188 if (nexus_info->authentic_pixel_cache != MagickFalse)
5190 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5191 nexus_info->region.x;
5192 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5194 extent=length*nexus_info->region.height;
5195 rows=nexus_info->region.height;
5197 p=nexus_info->pixels;
5198 switch (cache_info->type)
5207 Write pixels to memory.
5209 if ((cache_info->columns == nexus_info->region.width) &&
5210 (extent == (MagickSizeType) ((size_t) extent)))
5215 q=cache_info->pixels+offset*cache_info->number_channels;
5216 for (y=0; y < (ssize_t) rows; y++)
5218 (void) memcpy(q,p,(size_t) length);
5219 p+=cache_info->number_channels*nexus_info->region.width;
5220 q+=cache_info->columns*cache_info->number_channels;
5227 Write pixels to disk.
5229 LockSemaphoreInfo(cache_info->file_semaphore);
5230 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5232 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5233 cache_info->cache_filename);
5234 UnlockSemaphoreInfo(cache_info->file_semaphore);
5235 return(MagickFalse);
5237 if ((cache_info->columns == nexus_info->region.width) &&
5238 (extent <= MagickMaxBufferExtent))
5243 for (y=0; y < (ssize_t) rows; y++)
5245 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5246 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5248 if (count != (MagickOffsetType) length)
5250 p+=cache_info->number_channels*nexus_info->region.width;
5251 offset+=cache_info->columns;
5253 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5254 (void) ClosePixelCacheOnDisk(cache_info);
5255 UnlockSemaphoreInfo(cache_info->file_semaphore);
5258 case DistributedCache:
5264 Write pixels to distributed cache.
5266 LockSemaphoreInfo(cache_info->file_semaphore);
5267 region=nexus_info->region;
5268 if ((cache_info->columns != nexus_info->region.width) ||
5269 (extent > MagickMaxBufferExtent))
5276 for (y=0; y < (ssize_t) rows; y++)
5278 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5279 cache_info->server_info,®ion,length,(const unsigned char *) p);
5280 if (count != (MagickOffsetType) length)
5282 p+=cache_info->number_channels*nexus_info->region.width;
5285 UnlockSemaphoreInfo(cache_info->file_semaphore);
5291 if (y < (ssize_t) rows)
5293 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5294 cache_info->cache_filename);
5295 return(MagickFalse);
5297 if ((cache_info->debug != MagickFalse) &&
5298 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5299 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5300 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5301 nexus_info->region.width,(double) nexus_info->region.height,(double)
5302 nexus_info->region.x,(double) nexus_info->region.y);