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 void CopyPixels(Quantum *destination,const Quantum *source,
474 const MagickSizeType number_pixels)
476 #if !defined(MAGICKCORE_OPENMP_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH <= 8)
477 (void) memcpy(destination,source,(size_t) number_pixels*sizeof(*source));
480 register MagickOffsetType
483 if ((number_pixels*sizeof(*source)) < MagickMaxBufferExtent)
485 (void) memcpy(destination,source,(size_t) number_pixels*
489 #pragma omp parallel for
490 for (i=0; i < (MagickOffsetType) number_pixels; i++)
491 destination[i]=source[i];
496 static inline MagickSizeType MagickMin(const MagickSizeType x,
497 const MagickSizeType y)
504 static MagickBooleanType ClonePixelCacheRepository(
505 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
506 ExceptionInfo *exception)
508 #define MaxCacheThreads 2
509 #define cache_threads(source,destination,chunk) \
510 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
511 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
512 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
519 **restrict cache_nexus,
520 **restrict clone_nexus;
528 assert(cache_info != (CacheInfo *) NULL);
529 assert(clone_info != (CacheInfo *) NULL);
530 assert(exception != (ExceptionInfo *) NULL);
531 if (cache_info->type == PingCache)
533 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
534 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
535 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
536 (cache_info->columns == clone_info->columns) &&
537 (cache_info->rows == clone_info->rows) &&
538 (cache_info->number_channels == clone_info->number_channels) &&
539 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
540 (cache_info->metacontent_extent == clone_info->metacontent_extent))
542 CopyPixels(clone_info->pixels,cache_info->pixels,cache_info->columns*
543 cache_info->number_channels*cache_info->rows);
544 if (cache_info->metacontent_extent != 0)
545 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
546 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
547 sizeof(cache_info->metacontent));
551 Mismatched pixel cache morphology.
553 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
554 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
555 if ((cache_nexus == (NexusInfo **) NULL) ||
556 (clone_nexus == (NexusInfo **) NULL))
557 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
558 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
559 optimize=(cache_info->number_channels == clone_info->number_channels) &&
560 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
561 MagickTrue : MagickFalse;
562 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
563 clone_info->columns*clone_info->number_channels);
565 #if defined(MAGICKCORE_OPENMP_SUPPORT)
566 #pragma omp parallel for schedule(static,4) shared(status) \
567 cache_threads(cache_info,clone_info,cache_info->rows)
569 for (y=0; y < (ssize_t) cache_info->rows; y++)
572 id = GetOpenMPThreadId();
583 if (status == MagickFalse)
585 if (y >= (ssize_t) clone_info->rows)
587 region.width=cache_info->columns;
591 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
593 if (pixels == (Quantum *) NULL)
595 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
596 if (status == MagickFalse)
598 region.width=clone_info->columns;
599 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
600 clone_nexus[id],exception);
601 if (pixels == (Quantum *) NULL)
603 if (optimize != MagickFalse)
604 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
608 register const Quantum
615 Mismatched pixel channel map.
617 p=cache_nexus[id]->pixels;
618 q=clone_nexus[id]->pixels;
619 for (x=0; x < (ssize_t) cache_info->columns; x++)
624 if (x == (ssize_t) clone_info->columns)
626 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
634 channel=clone_info->channel_map[i].channel;
635 traits=cache_info->channel_map[channel].traits;
636 if (traits != UndefinedPixelTrait)
637 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
641 p+=cache_info->number_channels;
644 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
646 if ((cache_info->metacontent_extent != 0) &&
647 (clone_info->metacontent_extent != 0))
652 length=(size_t) MagickMin(cache_info->metacontent_extent,
653 clone_info->metacontent_extent);
654 #if defined(MAGICKCORE_OPENMP_SUPPORT)
655 #pragma omp parallel for schedule(static,4) shared(status) \
656 cache_threads(cache_info,clone_info,cache_info->rows)
658 for (y=0; y < (ssize_t) cache_info->rows; y++)
661 id = GetOpenMPThreadId();
669 if (status == MagickFalse)
671 if (y >= (ssize_t) clone_info->rows)
673 region.width=cache_info->columns;
677 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
678 cache_nexus[id],exception);
679 if (pixels == (Quantum *) NULL)
681 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
682 if (status == MagickFalse)
684 region.width=clone_info->columns;
685 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
686 clone_nexus[id],exception);
687 if (pixels == (Quantum *) NULL)
689 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
690 length*sizeof(cache_nexus[id]->metacontent));
691 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
694 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
695 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
696 if (cache_info->debug != MagickFalse)
699 message[MaxTextExtent];
701 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
702 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
703 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
704 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 + D e s t r o y I m a g e P i x e l C a c h e %
718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
722 % The format of the DestroyImagePixelCache() method is:
724 % void DestroyImagePixelCache(Image *image)
726 % A description of each parameter follows:
728 % o image: the image.
731 static void DestroyImagePixelCache(Image *image)
733 assert(image != (Image *) NULL);
734 assert(image->signature == MagickSignature);
735 if (image->debug != MagickFalse)
736 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
737 if (image->cache == (void *) NULL)
739 image->cache=DestroyPixelCache(image->cache);
743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747 + D e s t r o y I m a g e P i x e l s %
751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753 % DestroyImagePixels() deallocates memory associated with the pixel cache.
755 % The format of the DestroyImagePixels() method is:
757 % void DestroyImagePixels(Image *image)
759 % A description of each parameter follows:
761 % o image: the image.
764 MagickExport void DestroyImagePixels(Image *image)
767 *restrict cache_info;
769 assert(image != (const Image *) NULL);
770 assert(image->signature == MagickSignature);
771 if (image->debug != MagickFalse)
772 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
773 assert(image->cache != (Cache) NULL);
774 cache_info=(CacheInfo *) image->cache;
775 assert(cache_info->signature == MagickSignature);
776 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
778 cache_info->methods.destroy_pixel_handler(image);
781 image->cache=DestroyPixelCache(image->cache);
785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789 + D e s t r o y P i x e l C a c h e %
793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795 % DestroyPixelCache() deallocates memory associated with the pixel cache.
797 % The format of the DestroyPixelCache() method is:
799 % Cache DestroyPixelCache(Cache cache)
801 % A description of each parameter follows:
803 % o cache: the pixel cache.
807 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
813 if (cache_info->file != -1)
815 status=close(cache_info->file);
816 cache_info->file=(-1);
817 RelinquishMagickResource(FileResource,1);
819 return(status == -1 ? MagickFalse : MagickTrue);
822 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
824 switch (cache_info->type)
828 if (cache_info->mapped == MagickFalse)
829 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
832 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
833 (size_t) cache_info->length);
834 RelinquishMagickResource(MemoryResource,cache_info->length);
839 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
841 if (cache_info->mode != ReadMode)
842 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
843 *cache_info->cache_filename='\0';
844 RelinquishMagickResource(MapResource,cache_info->length);
848 if (cache_info->file != -1)
849 (void) ClosePixelCacheOnDisk(cache_info);
850 if (cache_info->mode != ReadMode)
851 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
852 *cache_info->cache_filename='\0';
853 RelinquishMagickResource(DiskResource,cache_info->length);
856 case DistributedCache:
858 *cache_info->cache_filename='\0';
859 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
860 cache_info->server_info);
866 cache_info->type=UndefinedCache;
867 cache_info->mapped=MagickFalse;
868 cache_info->metacontent=(void *) NULL;
871 MagickPrivate Cache DestroyPixelCache(Cache cache)
874 *restrict cache_info;
876 assert(cache != (Cache) NULL);
877 cache_info=(CacheInfo *) cache;
878 assert(cache_info->signature == MagickSignature);
879 if (cache_info->debug != MagickFalse)
880 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
881 cache_info->filename);
882 LockSemaphoreInfo(cache_info->semaphore);
883 cache_info->reference_count--;
884 if (cache_info->reference_count != 0)
886 UnlockSemaphoreInfo(cache_info->semaphore);
887 return((Cache) NULL);
889 UnlockSemaphoreInfo(cache_info->semaphore);
890 if (cache_info->debug != MagickFalse)
893 message[MaxTextExtent];
895 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
896 cache_info->filename);
897 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
899 RelinquishPixelCachePixels(cache_info);
900 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
901 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
902 cache_info->server_info);
903 if (cache_info->nexus_info != (NexusInfo **) NULL)
904 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
905 cache_info->number_threads);
906 if (cache_info->random_info != (RandomInfo *) NULL)
907 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
908 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
909 DestroySemaphoreInfo(&cache_info->file_semaphore);
910 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
911 DestroySemaphoreInfo(&cache_info->semaphore);
912 cache_info->signature=(~MagickSignature);
913 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923 + D e s t r o y P i x e l C a c h e N e x u s %
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
931 % The format of the DestroyPixelCacheNexus() method is:
933 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
934 % const size_t number_threads)
936 % A description of each parameter follows:
938 % o nexus_info: the nexus to destroy.
940 % o number_threads: the number of nexus threads.
944 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
946 if (nexus_info->mapped == MagickFalse)
947 (void) RelinquishAlignedMemory(nexus_info->cache);
949 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
950 nexus_info->cache=(Quantum *) NULL;
951 nexus_info->pixels=(Quantum *) NULL;
952 nexus_info->metacontent=(void *) NULL;
953 nexus_info->length=0;
954 nexus_info->mapped=MagickFalse;
957 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
958 const size_t number_threads)
963 assert(nexus_info != (NexusInfo **) NULL);
964 for (i=0; i < (ssize_t) number_threads; i++)
966 if (nexus_info[i]->cache != (Quantum *) NULL)
967 RelinquishCacheNexusPixels(nexus_info[i]);
968 nexus_info[i]->signature=(~MagickSignature);
970 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
971 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980 % G e t A u t h e n t i c M e t a c o n t e n t %
984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
987 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
988 % returned if the associated pixels are not available.
990 % The format of the GetAuthenticMetacontent() method is:
992 % void *GetAuthenticMetacontent(const Image *image)
994 % A description of each parameter follows:
996 % o image: the image.
999 MagickExport void *GetAuthenticMetacontent(const Image *image)
1002 *restrict cache_info;
1005 id = GetOpenMPThreadId();
1007 assert(image != (const Image *) NULL);
1008 assert(image->signature == MagickSignature);
1009 assert(image->cache != (Cache) NULL);
1010 cache_info=(CacheInfo *) image->cache;
1011 assert(cache_info->signature == MagickSignature);
1012 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1013 (GetAuthenticMetacontentFromHandler) NULL)
1018 metacontent=cache_info->methods.
1019 get_authentic_metacontent_from_handler(image);
1020 return(metacontent);
1022 assert(id < (int) cache_info->number_threads);
1023 return(cache_info->nexus_info[id]->metacontent);
1027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1031 + 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 %
1035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1037 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1038 % with the last call to QueueAuthenticPixelsCache() or
1039 % GetAuthenticPixelsCache().
1041 % The format of the GetAuthenticMetacontentFromCache() method is:
1043 % void *GetAuthenticMetacontentFromCache(const Image *image)
1045 % A description of each parameter follows:
1047 % o image: the image.
1050 static void *GetAuthenticMetacontentFromCache(const Image *image)
1053 *restrict cache_info;
1056 id = GetOpenMPThreadId();
1058 assert(image != (const Image *) NULL);
1059 assert(image->signature == MagickSignature);
1060 assert(image->cache != (Cache) NULL);
1061 cache_info=(CacheInfo *) image->cache;
1062 assert(cache_info->signature == MagickSignature);
1063 assert(id < (int) cache_info->number_threads);
1064 return(cache_info->nexus_info[id]->metacontent);
1068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072 + 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 %
1076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1079 % disk pixel cache as defined by the geometry parameters. A pointer to the
1080 % pixels is returned if the pixels are transferred, otherwise a NULL is
1083 % The format of the GetAuthenticPixelCacheNexus() method is:
1085 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1086 % const ssize_t y,const size_t columns,const size_t rows,
1087 % NexusInfo *nexus_info,ExceptionInfo *exception)
1089 % A description of each parameter follows:
1091 % o image: the image.
1093 % o x,y,columns,rows: These values define the perimeter of a region of
1096 % o nexus_info: the cache nexus to return.
1098 % o exception: return any errors or warnings in this structure.
1102 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1103 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1104 ExceptionInfo *exception)
1107 *restrict cache_info;
1113 Transfer pixels from the cache.
1115 assert(image != (Image *) NULL);
1116 assert(image->signature == MagickSignature);
1117 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1118 nexus_info,exception);
1119 if (pixels == (Quantum *) NULL)
1120 return((Quantum *) NULL);
1121 cache_info=(CacheInfo *) image->cache;
1122 assert(cache_info->signature == MagickSignature);
1123 if (nexus_info->authentic_pixel_cache != MagickFalse)
1125 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1126 return((Quantum *) NULL);
1127 if (cache_info->metacontent_extent != 0)
1128 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1129 return((Quantum *) NULL);
1134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138 + 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 %
1142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1144 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1145 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1147 % The format of the GetAuthenticPixelsFromCache() method is:
1149 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1151 % A description of each parameter follows:
1153 % o image: the image.
1156 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1159 *restrict cache_info;
1162 id = GetOpenMPThreadId();
1164 assert(image != (const Image *) NULL);
1165 assert(image->signature == MagickSignature);
1166 assert(image->cache != (Cache) NULL);
1167 cache_info=(CacheInfo *) image->cache;
1168 assert(cache_info->signature == MagickSignature);
1169 assert(id < (int) cache_info->number_threads);
1170 return(cache_info->nexus_info[id]->pixels);
1174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1178 % G e t A u t h e n t i c P i x e l Q u e u e %
1182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1184 % GetAuthenticPixelQueue() returns the authentic pixels associated
1185 % corresponding with the last call to QueueAuthenticPixels() or
1186 % GetAuthenticPixels().
1188 % The format of the GetAuthenticPixelQueue() method is:
1190 % Quantum *GetAuthenticPixelQueue(const Image image)
1192 % A description of each parameter follows:
1194 % o image: the image.
1197 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1200 *restrict cache_info;
1203 id = GetOpenMPThreadId();
1205 assert(image != (const Image *) NULL);
1206 assert(image->signature == MagickSignature);
1207 assert(image->cache != (Cache) NULL);
1208 cache_info=(CacheInfo *) image->cache;
1209 assert(cache_info->signature == MagickSignature);
1210 if (cache_info->methods.get_authentic_pixels_from_handler !=
1211 (GetAuthenticPixelsFromHandler) NULL)
1212 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1213 assert(id < (int) cache_info->number_threads);
1214 return(cache_info->nexus_info[id]->pixels);
1218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1222 % G e t A u t h e n t i c P i x e l s %
1225 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1227 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1228 % region is successfully accessed, a pointer to a Quantum array
1229 % representing the region is returned, otherwise NULL is returned.
1231 % The returned pointer may point to a temporary working copy of the pixels
1232 % or it may point to the original pixels in memory. Performance is maximized
1233 % if the selected region is part of one row, or one or more full rows, since
1234 % then there is opportunity to access the pixels in-place (without a copy)
1235 % if the image is in memory, or in a memory-mapped file. The returned pointer
1236 % must *never* be deallocated by the user.
1238 % Pixels accessed via the returned pointer represent a simple array of type
1239 % Quantum. If the image has corresponding metacontent,call
1240 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1241 % meta-content corresponding to the region. Once the Quantum array has
1242 % been updated, the changes must be saved back to the underlying image using
1243 % SyncAuthenticPixels() or they may be lost.
1245 % The format of the GetAuthenticPixels() method is:
1247 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1248 % const ssize_t y,const size_t columns,const size_t rows,
1249 % ExceptionInfo *exception)
1251 % A description of each parameter follows:
1253 % o image: the image.
1255 % o x,y,columns,rows: These values define the perimeter of a region of
1258 % o exception: return any errors or warnings in this structure.
1261 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1262 const ssize_t y,const size_t columns,const size_t rows,
1263 ExceptionInfo *exception)
1266 *restrict cache_info;
1269 id = GetOpenMPThreadId();
1274 assert(image != (Image *) NULL);
1275 assert(image->signature == MagickSignature);
1276 assert(image->cache != (Cache) NULL);
1277 cache_info=(CacheInfo *) image->cache;
1278 assert(cache_info->signature == MagickSignature);
1279 if (cache_info->methods.get_authentic_pixels_handler !=
1280 (GetAuthenticPixelsHandler) NULL)
1282 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1286 assert(id < (int) cache_info->number_threads);
1287 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1288 cache_info->nexus_info[id],exception);
1293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 + G e t A u t h e n t i c P i x e l s C a c h e %
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1304 % as defined by the geometry parameters. A pointer to the pixels is returned
1305 % if the pixels are transferred, otherwise a NULL is returned.
1307 % The format of the GetAuthenticPixelsCache() method is:
1309 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1310 % const ssize_t y,const size_t columns,const size_t rows,
1311 % ExceptionInfo *exception)
1313 % A description of each parameter follows:
1315 % o image: the image.
1317 % o x,y,columns,rows: These values define the perimeter of a region of
1320 % o exception: return any errors or warnings in this structure.
1323 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1324 const ssize_t y,const size_t columns,const size_t rows,
1325 ExceptionInfo *exception)
1328 *restrict cache_info;
1331 id = GetOpenMPThreadId();
1336 assert(image != (const Image *) NULL);
1337 assert(image->signature == MagickSignature);
1338 assert(image->cache != (Cache) NULL);
1339 cache_info=(CacheInfo *) image->cache;
1340 if (cache_info == (Cache) NULL)
1341 return((Quantum *) NULL);
1342 assert(cache_info->signature == MagickSignature);
1343 assert(id < (int) cache_info->number_threads);
1344 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1345 cache_info->nexus_info[id],exception);
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 + G e t I m a g e E x t e n t %
1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360 % GetImageExtent() returns the extent of the pixels associated corresponding
1361 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1363 % The format of the GetImageExtent() method is:
1365 % MagickSizeType GetImageExtent(const Image *image)
1367 % A description of each parameter follows:
1369 % o image: the image.
1372 MagickExport MagickSizeType GetImageExtent(const Image *image)
1375 *restrict cache_info;
1378 id = GetOpenMPThreadId();
1380 assert(image != (Image *) NULL);
1381 assert(image->signature == MagickSignature);
1382 if (image->debug != MagickFalse)
1383 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1384 assert(image->cache != (Cache) NULL);
1385 cache_info=(CacheInfo *) image->cache;
1386 assert(cache_info->signature == MagickSignature);
1387 assert(id < (int) cache_info->number_threads);
1388 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 + G e t I m a g e P i x e l C a c h e %
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 % GetImagePixelCache() ensures that there is only a single reference to the
1403 % pixel cache to be modified, updating the provided cache pointer to point to
1404 % a clone of the original pixel cache if necessary.
1406 % The format of the GetImagePixelCache method is:
1408 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1409 % ExceptionInfo *exception)
1411 % A description of each parameter follows:
1413 % o image: the image.
1415 % o clone: any value other than MagickFalse clones the cache pixels.
1417 % o exception: return any errors or warnings in this structure.
1421 static inline MagickBooleanType ValidatePixelCacheMorphology(
1422 const Image *restrict image)
1425 *restrict cache_info;
1427 const PixelChannelMap
1432 Does the image match the pixel cache morphology?
1434 cache_info=(CacheInfo *) image->cache;
1435 p=image->channel_map;
1436 q=cache_info->channel_map;
1437 if ((image->storage_class != cache_info->storage_class) ||
1438 (image->colorspace != cache_info->colorspace) ||
1439 (image->alpha_trait != cache_info->alpha_trait) ||
1440 (image->read_mask != cache_info->read_mask) ||
1441 (image->write_mask != cache_info->write_mask) ||
1442 (image->columns != cache_info->columns) ||
1443 (image->rows != cache_info->rows) ||
1444 (image->number_channels != cache_info->number_channels) ||
1445 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1446 (image->metacontent_extent != cache_info->metacontent_extent) ||
1447 (cache_info->nexus_info == (NexusInfo **) NULL))
1448 return(MagickFalse);
1452 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1453 ExceptionInfo *exception)
1456 *restrict cache_info;
1462 static MagickSizeType
1468 cache_timestamp = 0;
1471 LockSemaphoreInfo(image->semaphore);
1472 if (cpu_throttle == 0)
1473 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1474 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1475 MagickDelay(cpu_throttle);
1476 if (time_limit == 0)
1479 Set the expire time in seconds.
1481 time_limit=GetMagickResourceLimit(TimeResource);
1482 cache_timestamp=time((time_t *) NULL);
1484 if ((time_limit != MagickResourceInfinity) &&
1485 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1486 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1487 assert(image->cache != (Cache) NULL);
1488 cache_info=(CacheInfo *) image->cache;
1489 destroy=MagickFalse;
1490 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1492 LockSemaphoreInfo(cache_info->semaphore);
1493 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1504 clone_image=(*image);
1505 clone_image.semaphore=AllocateSemaphoreInfo();
1506 clone_image.reference_count=1;
1507 clone_image.cache=ClonePixelCache(cache_info);
1508 clone_info=(CacheInfo *) clone_image.cache;
1509 status=OpenPixelCache(&clone_image,IOMode,exception);
1510 if (status != MagickFalse)
1512 if (clone != MagickFalse)
1513 status=ClonePixelCacheRepository(clone_info,cache_info,
1515 if (status != MagickFalse)
1517 if (cache_info->reference_count == 1)
1518 cache_info->nexus_info=(NexusInfo **) NULL;
1520 image->cache=clone_image.cache;
1523 DestroySemaphoreInfo(&clone_image.semaphore);
1525 UnlockSemaphoreInfo(cache_info->semaphore);
1527 if (destroy != MagickFalse)
1528 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1529 if (status != MagickFalse)
1532 Ensure the image matches the pixel cache morphology.
1534 image->taint=MagickTrue;
1535 image->type=UndefinedType;
1536 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1538 status=OpenPixelCache(image,IOMode,exception);
1539 cache_info=(CacheInfo *) image->cache;
1540 if (cache_info->type == DiskCache)
1541 (void) ClosePixelCacheOnDisk(cache_info);
1544 UnlockSemaphoreInfo(image->semaphore);
1545 if (status == MagickFalse)
1546 return((Cache) NULL);
1547 return(image->cache);
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555 + G e t I m a g e P i x e l C a c h e T y p e %
1559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1561 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1562 % DiskCache, MemoryCache, MapCache, or PingCache.
1564 % The format of the GetImagePixelCacheType() method is:
1566 % CacheType GetImagePixelCacheType(const Image *image)
1568 % A description of each parameter follows:
1570 % o image: the image.
1573 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1576 *restrict cache_info;
1578 assert(image != (Image *) NULL);
1579 assert(image->signature == MagickSignature);
1580 assert(image->cache != (Cache) NULL);
1581 cache_info=(CacheInfo *) image->cache;
1582 assert(cache_info->signature == MagickSignature);
1583 return(cache_info->type);
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1591 % G e t O n e A u t h e n t i c P i x e l %
1595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1598 % location. The image background color is returned if an error occurs.
1600 % The format of the GetOneAuthenticPixel() method is:
1602 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1603 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1605 % A description of each parameter follows:
1607 % o image: the image.
1609 % o x,y: These values define the location of the pixel to return.
1611 % o pixel: return a pixel at the specified (x,y) location.
1613 % o exception: return any errors or warnings in this structure.
1616 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1617 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1620 *restrict cache_info;
1628 assert(image != (Image *) NULL);
1629 assert(image->signature == MagickSignature);
1630 assert(image->cache != (Cache) NULL);
1631 cache_info=(CacheInfo *) image->cache;
1632 assert(cache_info->signature == MagickSignature);
1633 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1634 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1635 (GetOneAuthenticPixelFromHandler) NULL)
1636 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1638 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1639 if (q == (Quantum *) NULL)
1641 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1642 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1643 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1644 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1645 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1646 return(MagickFalse);
1648 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1650 PixelChannel channel=GetPixelChannelChannel(image,i);
1651 pixel[channel]=q[i];
1657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1661 + 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 %
1665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1668 % location. The image background color is returned if an error occurs.
1670 % The format of the GetOneAuthenticPixelFromCache() method is:
1672 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1673 % const ssize_t x,const ssize_t y,Quantum *pixel,
1674 % ExceptionInfo *exception)
1676 % A description of each parameter follows:
1678 % o image: the image.
1680 % o x,y: These values define the location of the pixel to return.
1682 % o pixel: return a pixel at the specified (x,y) location.
1684 % o exception: return any errors or warnings in this structure.
1687 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1688 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1691 *restrict cache_info;
1694 id = GetOpenMPThreadId();
1702 assert(image != (const Image *) NULL);
1703 assert(image->signature == MagickSignature);
1704 assert(image->cache != (Cache) NULL);
1705 cache_info=(CacheInfo *) image->cache;
1706 assert(cache_info->signature == MagickSignature);
1707 assert(id < (int) cache_info->number_threads);
1708 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1709 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1711 if (q == (Quantum *) NULL)
1713 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1714 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1715 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1716 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1717 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1718 return(MagickFalse);
1720 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1722 PixelChannel channel=GetPixelChannelChannel(image,i);
1723 pixel[channel]=q[i];
1729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1733 % G e t O n e V i r t u a l P i x e l %
1737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1740 % (x,y) location. The image background color is returned if an error occurs.
1741 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1743 % The format of the GetOneVirtualPixel() method is:
1745 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1746 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1748 % A description of each parameter follows:
1750 % o image: the image.
1752 % o x,y: These values define the location of the pixel to return.
1754 % o pixel: return a pixel at the specified (x,y) location.
1756 % o exception: return any errors or warnings in this structure.
1759 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1760 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1763 *restrict cache_info;
1766 id = GetOpenMPThreadId();
1774 assert(image != (const Image *) NULL);
1775 assert(image->signature == MagickSignature);
1776 assert(image->cache != (Cache) NULL);
1777 cache_info=(CacheInfo *) image->cache;
1778 assert(cache_info->signature == MagickSignature);
1779 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1780 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1781 (GetOneVirtualPixelFromHandler) NULL)
1782 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1783 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1784 assert(id < (int) cache_info->number_threads);
1785 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1786 1UL,1UL,cache_info->nexus_info[id],exception);
1787 if (p == (const Quantum *) NULL)
1789 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1790 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1791 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1792 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1793 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1794 return(MagickFalse);
1796 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1798 PixelChannel channel=GetPixelChannelChannel(image,i);
1799 pixel[channel]=p[i];
1805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1809 + 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 %
1813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1816 % specified (x,y) location. The image background color is returned if an
1819 % The format of the GetOneVirtualPixelFromCache() method is:
1821 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1822 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1823 % Quantum *pixel,ExceptionInfo *exception)
1825 % A description of each parameter follows:
1827 % o image: the image.
1829 % o virtual_pixel_method: the virtual pixel method.
1831 % o x,y: These values define the location of the pixel to return.
1833 % o pixel: return a pixel at the specified (x,y) location.
1835 % o exception: return any errors or warnings in this structure.
1838 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1839 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1840 Quantum *pixel,ExceptionInfo *exception)
1843 *restrict cache_info;
1846 id = GetOpenMPThreadId();
1854 assert(image != (const Image *) NULL);
1855 assert(image->signature == MagickSignature);
1856 assert(image->cache != (Cache) NULL);
1857 cache_info=(CacheInfo *) image->cache;
1858 assert(cache_info->signature == MagickSignature);
1859 assert(id < (int) cache_info->number_threads);
1860 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1861 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1862 cache_info->nexus_info[id],exception);
1863 if (p == (const Quantum *) NULL)
1865 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1866 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1867 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1868 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1869 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1870 return(MagickFalse);
1872 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1874 PixelChannel channel=GetPixelChannelChannel(image,i);
1875 pixel[channel]=p[i];
1881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1885 % G e t O n e V i r t u a l P i x e l I n f o %
1889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1891 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1892 % location. The image background color is returned if an error occurs. If
1893 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1895 % The format of the GetOneVirtualPixelInfo() method is:
1897 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1898 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1899 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1901 % A description of each parameter follows:
1903 % o image: the image.
1905 % o virtual_pixel_method: the virtual pixel method.
1907 % o x,y: these values define the location of the pixel to return.
1909 % o pixel: return a pixel at the specified (x,y) location.
1911 % o exception: return any errors or warnings in this structure.
1914 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1915 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1916 PixelInfo *pixel,ExceptionInfo *exception)
1919 *restrict cache_info;
1922 id = GetOpenMPThreadId();
1924 register const Quantum
1927 assert(image != (const Image *) NULL);
1928 assert(image->signature == MagickSignature);
1929 assert(image->cache != (Cache) NULL);
1930 cache_info=(CacheInfo *) image->cache;
1931 assert(cache_info->signature == MagickSignature);
1932 assert(id < (int) cache_info->number_threads);
1933 GetPixelInfo(image,pixel);
1934 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1935 cache_info->nexus_info[id],exception);
1936 if (p == (const Quantum *) NULL)
1937 return(MagickFalse);
1938 GetPixelInfoPixel(image,p,pixel);
1943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1947 + G e t P i x e l C a c h e C o l o r s p a c e %
1951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1953 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1955 % The format of the GetPixelCacheColorspace() method is:
1957 % Colorspace GetPixelCacheColorspace(Cache cache)
1959 % A description of each parameter follows:
1961 % o cache: the pixel cache.
1964 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1967 *restrict cache_info;
1969 assert(cache != (Cache) NULL);
1970 cache_info=(CacheInfo *) cache;
1971 assert(cache_info->signature == MagickSignature);
1972 if (cache_info->debug != MagickFalse)
1973 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1974 cache_info->filename);
1975 return(cache_info->colorspace);
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983 + G e t P i x e l C a c h e M e t h o d s %
1987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989 % GetPixelCacheMethods() initializes the CacheMethods structure.
1991 % The format of the GetPixelCacheMethods() method is:
1993 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1995 % A description of each parameter follows:
1997 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2000 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2002 assert(cache_methods != (CacheMethods *) NULL);
2003 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2004 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2005 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2006 cache_methods->get_virtual_metacontent_from_handler=
2007 GetVirtualMetacontentFromCache;
2008 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2009 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2010 cache_methods->get_authentic_metacontent_from_handler=
2011 GetAuthenticMetacontentFromCache;
2012 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2013 cache_methods->get_one_authentic_pixel_from_handler=
2014 GetOneAuthenticPixelFromCache;
2015 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2016 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2017 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2025 + G e t P i x e l C a c h e N e x u s E x t e n t %
2029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2031 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2032 % corresponding with the last call to SetPixelCacheNexusPixels() or
2033 % GetPixelCacheNexusPixels().
2035 % The format of the GetPixelCacheNexusExtent() method is:
2037 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2038 % NexusInfo *nexus_info)
2040 % A description of each parameter follows:
2042 % o nexus_info: the nexus info.
2045 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2046 NexusInfo *restrict nexus_info)
2049 *restrict cache_info;
2054 assert(cache != NULL);
2055 cache_info=(CacheInfo *) cache;
2056 assert(cache_info->signature == MagickSignature);
2057 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2059 return((MagickSizeType) cache_info->columns*cache_info->rows);
2064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2068 + G e t P i x e l C a c h e P i x e l s %
2072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2074 % GetPixelCachePixels() returns the pixels associated with the specified image.
2076 % The format of the GetPixelCachePixels() method is:
2078 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2079 % ExceptionInfo *exception)
2081 % A description of each parameter follows:
2083 % o image: the image.
2085 % o length: the pixel cache length.
2087 % o exception: return any errors or warnings in this structure.
2090 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2091 ExceptionInfo *exception)
2094 *restrict cache_info;
2096 assert(image != (const Image *) NULL);
2097 assert(image->signature == MagickSignature);
2098 assert(image->cache != (Cache) NULL);
2099 assert(length != (MagickSizeType *) NULL);
2100 assert(exception != (ExceptionInfo *) NULL);
2101 assert(exception->signature == MagickSignature);
2102 cache_info=(CacheInfo *) image->cache;
2103 assert(cache_info->signature == MagickSignature);
2105 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2106 return((void *) NULL);
2107 *length=cache_info->length;
2108 return((void *) cache_info->pixels);
2112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2116 + 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 %
2120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2122 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2124 % The format of the GetPixelCacheStorageClass() method is:
2126 % ClassType GetPixelCacheStorageClass(Cache cache)
2128 % A description of each parameter follows:
2130 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2132 % o cache: the pixel cache.
2135 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2138 *restrict cache_info;
2140 assert(cache != (Cache) NULL);
2141 cache_info=(CacheInfo *) cache;
2142 assert(cache_info->signature == MagickSignature);
2143 if (cache_info->debug != MagickFalse)
2144 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2145 cache_info->filename);
2146 return(cache_info->storage_class);
2150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2154 + G e t P i x e l C a c h e T i l e S i z e %
2158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160 % GetPixelCacheTileSize() returns the pixel cache tile size.
2162 % The format of the GetPixelCacheTileSize() method is:
2164 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2167 % A description of each parameter follows:
2169 % o image: the image.
2171 % o width: the optimize cache tile width in pixels.
2173 % o height: the optimize cache tile height in pixels.
2176 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2180 *restrict cache_info;
2182 assert(image != (Image *) NULL);
2183 assert(image->signature == MagickSignature);
2184 if (image->debug != MagickFalse)
2185 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2186 cache_info=(CacheInfo *) image->cache;
2187 assert(cache_info->signature == MagickSignature);
2188 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2189 if (GetImagePixelCacheType(image) == DiskCache)
2190 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2199 + 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 %
2203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2206 % pixel cache. A virtual pixel is any pixel access that is outside the
2207 % boundaries of the image cache.
2209 % The format of the GetPixelCacheVirtualMethod() method is:
2211 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2213 % A description of each parameter follows:
2215 % o image: the image.
2218 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2221 *restrict cache_info;
2223 assert(image != (Image *) NULL);
2224 assert(image->signature == MagickSignature);
2225 assert(image->cache != (Cache) NULL);
2226 cache_info=(CacheInfo *) image->cache;
2227 assert(cache_info->signature == MagickSignature);
2228 return(cache_info->virtual_pixel_method);
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2236 + 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 %
2240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2243 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2245 % The format of the GetVirtualMetacontentFromCache() method is:
2247 % void *GetVirtualMetacontentFromCache(const Image *image)
2249 % A description of each parameter follows:
2251 % o image: the image.
2254 static const void *GetVirtualMetacontentFromCache(const Image *image)
2257 *restrict cache_info;
2260 id = GetOpenMPThreadId();
2263 *restrict metacontent;
2265 assert(image != (const Image *) NULL);
2266 assert(image->signature == MagickSignature);
2267 assert(image->cache != (Cache) NULL);
2268 cache_info=(CacheInfo *) image->cache;
2269 assert(cache_info->signature == MagickSignature);
2270 assert(id < (int) cache_info->number_threads);
2271 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2272 cache_info->nexus_info[id]);
2273 return(metacontent);
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281 + 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 %
2285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2287 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2290 % The format of the GetVirtualMetacontentFromNexus() method is:
2292 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2293 % NexusInfo *nexus_info)
2295 % A description of each parameter follows:
2297 % o cache: the pixel cache.
2299 % o nexus_info: the cache nexus to return the meta-content.
2302 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2303 NexusInfo *restrict nexus_info)
2306 *restrict cache_info;
2308 assert(cache != (Cache) NULL);
2309 cache_info=(CacheInfo *) cache;
2310 assert(cache_info->signature == MagickSignature);
2311 if (cache_info->storage_class == UndefinedClass)
2312 return((void *) NULL);
2313 return(nexus_info->metacontent);
2317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321 % G e t V i r t u a l M e t a c o n t e n t %
2325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2328 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2329 % returned if the meta-content are not available.
2331 % The format of the GetVirtualMetacontent() method is:
2333 % const void *GetVirtualMetacontent(const Image *image)
2335 % A description of each parameter follows:
2337 % o image: the image.
2340 MagickExport const void *GetVirtualMetacontent(const Image *image)
2343 *restrict cache_info;
2346 id = GetOpenMPThreadId();
2349 *restrict metacontent;
2351 assert(image != (const Image *) NULL);
2352 assert(image->signature == MagickSignature);
2353 assert(image->cache != (Cache) NULL);
2354 cache_info=(CacheInfo *) image->cache;
2355 assert(cache_info->signature == MagickSignature);
2356 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2357 if (metacontent != (void *) NULL)
2358 return(metacontent);
2359 assert(id < (int) cache_info->number_threads);
2360 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2361 cache_info->nexus_info[id]);
2362 return(metacontent);
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2370 + 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 %
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2377 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2378 % is returned if the pixels are transferred, otherwise a NULL is returned.
2380 % The format of the GetVirtualPixelsFromNexus() method is:
2382 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2383 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2384 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2385 % ExceptionInfo *exception)
2387 % A description of each parameter follows:
2389 % o image: the image.
2391 % o virtual_pixel_method: the virtual pixel method.
2393 % o x,y,columns,rows: These values define the perimeter of a region of
2396 % o nexus_info: the cache nexus to acquire.
2398 % o exception: return any errors or warnings in this structure.
2405 0, 48, 12, 60, 3, 51, 15, 63,
2406 32, 16, 44, 28, 35, 19, 47, 31,
2407 8, 56, 4, 52, 11, 59, 7, 55,
2408 40, 24, 36, 20, 43, 27, 39, 23,
2409 2, 50, 14, 62, 1, 49, 13, 61,
2410 34, 18, 46, 30, 33, 17, 45, 29,
2411 10, 58, 6, 54, 9, 57, 5, 53,
2412 42, 26, 38, 22, 41, 25, 37, 21
2415 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2420 index=x+DitherMatrix[x & 0x07]-32L;
2423 if (index >= (ssize_t) columns)
2424 return((ssize_t) columns-1L);
2428 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2433 index=y+DitherMatrix[y & 0x07]-32L;
2436 if (index >= (ssize_t) rows)
2437 return((ssize_t) rows-1L);
2441 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2445 if (x >= (ssize_t) columns)
2446 return((ssize_t) (columns-1));
2450 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2454 if (y >= (ssize_t) rows)
2455 return((ssize_t) (rows-1));
2459 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2461 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2464 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2466 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2469 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2470 const size_t extent)
2476 Compute the remainder of dividing offset by extent. It returns not only
2477 the quotient (tile the offset falls in) but also the positive remainer
2478 within that tile such that 0 <= remainder < extent. This method is
2479 essentially a ldiv() using a floored modulo division rather than the
2480 normal default truncated modulo division.
2482 modulo.quotient=offset/(ssize_t) extent;
2485 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2489 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2490 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2491 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2492 ExceptionInfo *exception)
2495 *restrict cache_info;
2505 **restrict virtual_nexus;
2509 virtual_pixel[MaxPixelChannels];
2514 register const Quantum
2527 register unsigned char
2534 *restrict virtual_metacontent;
2539 assert(image != (const Image *) NULL);
2540 assert(image->signature == MagickSignature);
2541 assert(image->cache != (Cache) NULL);
2542 cache_info=(CacheInfo *) image->cache;
2543 assert(cache_info->signature == MagickSignature);
2544 if (cache_info->type == UndefinedCache)
2545 return((const Quantum *) NULL);
2548 region.width=columns;
2550 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2552 if (pixels == (Quantum *) NULL)
2553 return((const Quantum *) NULL);
2555 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2556 nexus_info->region.x;
2557 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2558 nexus_info->region.width-1L;
2559 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2560 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2561 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2562 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2568 Pixel request is inside cache extents.
2570 if (nexus_info->authentic_pixel_cache != MagickFalse)
2572 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2573 if (status == MagickFalse)
2574 return((const Quantum *) NULL);
2575 if (cache_info->metacontent_extent != 0)
2577 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2578 if (status == MagickFalse)
2579 return((const Quantum *) NULL);
2584 Pixel request is outside cache extents.
2586 s=(unsigned char *) nexus_info->metacontent;
2587 virtual_nexus=AcquirePixelCacheNexus(1);
2588 if (virtual_nexus == (NexusInfo **) NULL)
2590 if (virtual_nexus != (NexusInfo **) NULL)
2591 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2592 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2593 "UnableToGetCacheNexus","`%s'",image->filename);
2594 return((const Quantum *) NULL);
2596 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2597 sizeof(*virtual_pixel));
2598 virtual_metacontent=(void *) NULL;
2599 switch (virtual_pixel_method)
2601 case BackgroundVirtualPixelMethod:
2602 case BlackVirtualPixelMethod:
2603 case GrayVirtualPixelMethod:
2604 case TransparentVirtualPixelMethod:
2605 case MaskVirtualPixelMethod:
2606 case WhiteVirtualPixelMethod:
2607 case EdgeVirtualPixelMethod:
2608 case CheckerTileVirtualPixelMethod:
2609 case HorizontalTileVirtualPixelMethod:
2610 case VerticalTileVirtualPixelMethod:
2612 if (cache_info->metacontent_extent != 0)
2615 Acquire a metacontent buffer.
2617 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2618 cache_info->metacontent_extent);
2619 if (virtual_metacontent == (void *) NULL)
2621 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2622 (void) ThrowMagickException(exception,GetMagickModule(),
2623 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2624 return((const Quantum *) NULL);
2626 (void) ResetMagickMemory(virtual_metacontent,0,
2627 cache_info->metacontent_extent);
2629 switch (virtual_pixel_method)
2631 case BlackVirtualPixelMethod:
2633 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2634 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2635 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2638 case GrayVirtualPixelMethod:
2640 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2641 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2643 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2646 case TransparentVirtualPixelMethod:
2648 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2649 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2650 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2653 case MaskVirtualPixelMethod:
2654 case WhiteVirtualPixelMethod:
2656 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2657 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2658 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2663 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2665 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2667 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2669 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2671 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2681 for (v=0; v < (ssize_t) rows; v++)
2687 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2688 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2689 y_offset=EdgeY(y_offset,cache_info->rows);
2690 for (u=0; u < (ssize_t) columns; u+=length)
2696 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2697 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2698 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2706 Transfer a single pixel.
2708 length=(MagickSizeType) 1;
2709 switch (virtual_pixel_method)
2711 case EdgeVirtualPixelMethod:
2714 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2715 EdgeX(x_offset,cache_info->columns),
2716 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2718 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2721 case RandomVirtualPixelMethod:
2723 if (cache_info->random_info == (RandomInfo *) NULL)
2724 cache_info->random_info=AcquireRandomInfo();
2725 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2726 RandomX(cache_info->random_info,cache_info->columns),
2727 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2728 *virtual_nexus,exception);
2729 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2732 case DitherVirtualPixelMethod:
2734 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2735 DitherX(x_offset,cache_info->columns),
2736 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2738 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2741 case TileVirtualPixelMethod:
2743 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2744 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2745 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2746 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2748 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2751 case MirrorVirtualPixelMethod:
2753 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2754 if ((x_modulo.quotient & 0x01) == 1L)
2755 x_modulo.remainder=(ssize_t) cache_info->columns-
2756 x_modulo.remainder-1L;
2757 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2758 if ((y_modulo.quotient & 0x01) == 1L)
2759 y_modulo.remainder=(ssize_t) cache_info->rows-
2760 y_modulo.remainder-1L;
2761 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2762 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2764 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2767 case HorizontalTileEdgeVirtualPixelMethod:
2769 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2770 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2771 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2772 *virtual_nexus,exception);
2773 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2776 case VerticalTileEdgeVirtualPixelMethod:
2778 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2779 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2780 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2781 *virtual_nexus,exception);
2782 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2785 case BackgroundVirtualPixelMethod:
2786 case BlackVirtualPixelMethod:
2787 case GrayVirtualPixelMethod:
2788 case TransparentVirtualPixelMethod:
2789 case MaskVirtualPixelMethod:
2790 case WhiteVirtualPixelMethod:
2793 r=virtual_metacontent;
2796 case CheckerTileVirtualPixelMethod:
2798 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2799 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2800 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2803 r=virtual_metacontent;
2806 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2807 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2809 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2812 case HorizontalTileVirtualPixelMethod:
2814 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2817 r=virtual_metacontent;
2820 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2821 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2822 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2823 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2825 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2828 case VerticalTileVirtualPixelMethod:
2830 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2833 r=virtual_metacontent;
2836 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2837 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2838 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2839 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2841 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2845 if (p == (const Quantum *) NULL)
2847 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2849 q+=cache_info->number_channels;
2850 if ((s != (void *) NULL) && (r != (const void *) NULL))
2852 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2853 s+=cache_info->metacontent_extent;
2858 Transfer a run of pixels.
2860 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2861 (size_t) length,1UL,*virtual_nexus,exception);
2862 if (p == (const Quantum *) NULL)
2864 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2865 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2866 q+=length*cache_info->number_channels;
2867 if ((r != (void *) NULL) && (s != (const void *) NULL))
2869 (void) memcpy(s,r,(size_t) length);
2870 s+=length*cache_info->metacontent_extent;
2877 if (virtual_metacontent != (void *) NULL)
2878 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2879 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2888 + G e t V i r t u a l P i x e l C a c h e %
2892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2894 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2895 % cache as defined by the geometry parameters. A pointer to the pixels
2896 % is returned if the pixels are transferred, otherwise a NULL is returned.
2898 % The format of the GetVirtualPixelCache() method is:
2900 % const Quantum *GetVirtualPixelCache(const Image *image,
2901 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2902 % const ssize_t y,const size_t columns,const size_t rows,
2903 % ExceptionInfo *exception)
2905 % A description of each parameter follows:
2907 % o image: the image.
2909 % o virtual_pixel_method: the virtual pixel method.
2911 % o x,y,columns,rows: These values define the perimeter of a region of
2914 % o exception: return any errors or warnings in this structure.
2917 static const Quantum *GetVirtualPixelCache(const Image *image,
2918 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2919 const size_t columns,const size_t rows,ExceptionInfo *exception)
2922 *restrict cache_info;
2925 id = GetOpenMPThreadId();
2930 assert(image != (const Image *) NULL);
2931 assert(image->signature == MagickSignature);
2932 assert(image->cache != (Cache) NULL);
2933 cache_info=(CacheInfo *) image->cache;
2934 assert(cache_info->signature == MagickSignature);
2935 assert(id < (int) cache_info->number_threads);
2936 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2937 cache_info->nexus_info[id],exception);
2942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2946 % G e t V i r t u a l P i x e l Q u e u e %
2950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2952 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2953 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2955 % The format of the GetVirtualPixelQueue() method is:
2957 % const Quantum *GetVirtualPixelQueue(const Image image)
2959 % A description of each parameter follows:
2961 % o image: the image.
2964 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2967 *restrict cache_info;
2970 id = GetOpenMPThreadId();
2972 assert(image != (const Image *) NULL);
2973 assert(image->signature == MagickSignature);
2974 assert(image->cache != (Cache) NULL);
2975 cache_info=(CacheInfo *) image->cache;
2976 assert(cache_info->signature == MagickSignature);
2977 if (cache_info->methods.get_virtual_pixels_handler !=
2978 (GetVirtualPixelsHandler) NULL)
2979 return(cache_info->methods.get_virtual_pixels_handler(image));
2980 assert(id < (int) cache_info->number_threads);
2981 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2989 % G e t V i r t u a l P i x e l s %
2993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2995 % GetVirtualPixels() returns an immutable pixel region. If the
2996 % region is successfully accessed, a pointer to it is returned, otherwise
2997 % NULL is returned. The returned pointer may point to a temporary working
2998 % copy of the pixels or it may point to the original pixels in memory.
2999 % Performance is maximized if the selected region is part of one row, or one
3000 % or more full rows, since there is opportunity to access the pixels in-place
3001 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3002 % returned pointer must *never* be deallocated by the user.
3004 % Pixels accessed via the returned pointer represent a simple array of type
3005 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3006 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3007 % access the meta-content (of type void) corresponding to the the
3010 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3012 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3013 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3014 % GetCacheViewAuthenticPixels() instead.
3016 % The format of the GetVirtualPixels() method is:
3018 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3019 % const ssize_t y,const size_t columns,const size_t rows,
3020 % ExceptionInfo *exception)
3022 % A description of each parameter follows:
3024 % o image: the image.
3026 % o x,y,columns,rows: These values define the perimeter of a region of
3029 % o exception: return any errors or warnings in this structure.
3032 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3033 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3034 ExceptionInfo *exception)
3037 *restrict cache_info;
3040 id = GetOpenMPThreadId();
3045 assert(image != (const Image *) NULL);
3046 assert(image->signature == MagickSignature);
3047 assert(image->cache != (Cache) NULL);
3048 cache_info=(CacheInfo *) image->cache;
3049 assert(cache_info->signature == MagickSignature);
3050 if (cache_info->methods.get_virtual_pixel_handler !=
3051 (GetVirtualPixelHandler) NULL)
3052 return(cache_info->methods.get_virtual_pixel_handler(image,
3053 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3054 assert(id < (int) cache_info->number_threads);
3055 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3056 columns,rows,cache_info->nexus_info[id],exception);
3061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3065 + 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 %
3069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3071 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3072 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3074 % The format of the GetVirtualPixelsCache() method is:
3076 % Quantum *GetVirtualPixelsCache(const Image *image)
3078 % A description of each parameter follows:
3080 % o image: the image.
3083 static const Quantum *GetVirtualPixelsCache(const Image *image)
3086 *restrict cache_info;
3089 id = GetOpenMPThreadId();
3091 assert(image != (const Image *) NULL);
3092 assert(image->signature == MagickSignature);
3093 assert(image->cache != (Cache) NULL);
3094 cache_info=(CacheInfo *) image->cache;
3095 assert(cache_info->signature == MagickSignature);
3096 assert(id < (int) cache_info->number_threads);
3097 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3105 + G e t V i r t u a l P i x e l s N e x u s %
3109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3111 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3114 % The format of the GetVirtualPixelsNexus() method is:
3116 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3117 % NexusInfo *nexus_info)
3119 % A description of each parameter follows:
3121 % o cache: the pixel cache.
3123 % o nexus_info: the cache nexus to return the colormap pixels.
3126 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3127 NexusInfo *restrict nexus_info)
3130 *restrict cache_info;
3132 assert(cache != (Cache) NULL);
3133 cache_info=(CacheInfo *) cache;
3134 assert(cache_info->signature == MagickSignature);
3135 if (cache_info->storage_class == UndefinedClass)
3136 return((Quantum *) NULL);
3137 return((const Quantum *) nexus_info->pixels);
3141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3145 + O p e n P i x e l C a c h e %
3149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3151 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3152 % dimensions, allocating space for the image pixels and optionally the
3153 % metacontent, and memory mapping the cache if it is disk based. The cache
3154 % nexus array is initialized as well.
3156 % The format of the OpenPixelCache() method is:
3158 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3159 % ExceptionInfo *exception)
3161 % A description of each parameter follows:
3163 % o image: the image.
3165 % o mode: ReadMode, WriteMode, or IOMode.
3167 % o exception: return any errors or warnings in this structure.
3171 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3173 cache_info->mapped=MagickFalse;
3174 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3175 (size_t) cache_info->length));
3176 if (cache_info->pixels == (Quantum *) NULL)
3178 cache_info->mapped=MagickTrue;
3179 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3180 cache_info->length);
3184 #if defined(__cplusplus) || defined(c_plusplus)
3189 static void CacheSignalHandler(int status)
3191 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3195 #if defined(__cplusplus) || defined(c_plusplus)
3199 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3206 Open pixel cache on disk.
3208 if (cache_info->file != -1)
3209 return(MagickTrue); /* cache already open */
3210 if (*cache_info->cache_filename == '\0')
3211 file=AcquireUniqueFileResource(cache_info->cache_filename);
3217 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3222 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3223 O_BINARY | O_EXCL,S_MODE);
3225 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3231 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3234 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3239 return(MagickFalse);
3240 (void) AcquireMagickResource(FileResource,1);
3241 cache_info->file=file;
3242 cache_info->mode=mode;
3246 static inline MagickOffsetType WritePixelCacheRegion(
3247 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3248 const MagickSizeType length,const unsigned char *restrict buffer)
3250 register MagickOffsetType
3256 #if !defined(MAGICKCORE_HAVE_PWRITE)
3257 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3258 return((MagickOffsetType) -1);
3261 for (i=0; i < (MagickOffsetType) length; i+=count)
3263 #if !defined(MAGICKCORE_HAVE_PWRITE)
3264 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3265 (MagickSizeType) SSIZE_MAX));
3267 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3268 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3280 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3283 *restrict cache_info;
3290 cache_info=(CacheInfo *) image->cache;
3291 if (image->debug != MagickFalse)
3294 format[MaxTextExtent],
3295 message[MaxTextExtent];
3297 (void) FormatMagickSize(length,MagickFalse,format);
3298 (void) FormatLocaleString(message,MaxTextExtent,
3299 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3300 cache_info->cache_filename,cache_info->file,format);
3301 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3303 if (length != (MagickSizeType) ((MagickOffsetType) length))
3304 return(MagickFalse);
3305 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3307 return(MagickFalse);
3308 if ((MagickSizeType) offset >= length)
3310 extent=(MagickOffsetType) length-1;
3311 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3312 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3313 if (cache_info->synchronize != MagickFalse)
3318 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3320 return(MagickFalse);
3324 (void) signal(SIGBUS,CacheSignalHandler);
3326 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3329 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3330 ExceptionInfo *exception)
3333 *restrict cache_info,
3337 format[MaxTextExtent],
3338 message[MaxTextExtent];
3354 assert(image != (const Image *) NULL);
3355 assert(image->signature == MagickSignature);
3356 assert(image->cache != (Cache) NULL);
3357 if (image->debug != MagickFalse)
3358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3359 if ((image->columns == 0) || (image->rows == 0))
3360 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3361 cache_info=(CacheInfo *) image->cache;
3362 assert(cache_info->signature == MagickSignature);
3363 source_info=(*cache_info);
3364 source_info.file=(-1);
3365 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3366 image->filename,(double) GetImageIndexInList(image));
3367 cache_info->storage_class=image->storage_class;
3368 cache_info->colorspace=image->colorspace;
3369 cache_info->alpha_trait=image->alpha_trait;
3370 cache_info->read_mask=image->read_mask;
3371 cache_info->write_mask=image->write_mask;
3372 cache_info->rows=image->rows;
3373 cache_info->columns=image->columns;
3374 InitializePixelChannelMap(image);
3375 cache_info->number_channels=GetPixelChannels(image);
3376 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3377 sizeof(*image->channel_map));
3378 cache_info->metacontent_extent=image->metacontent_extent;
3379 cache_info->mode=mode;
3380 if (image->ping != MagickFalse)
3382 cache_info->type=PingCache;
3383 cache_info->pixels=(Quantum *) NULL;
3384 cache_info->metacontent=(void *) NULL;
3385 cache_info->length=0;
3388 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3389 packet_size=cache_info->number_channels*sizeof(Quantum);
3390 if (image->metacontent_extent != 0)
3391 packet_size+=cache_info->metacontent_extent;
3392 length=number_pixels*packet_size;
3393 columns=(size_t) (length/cache_info->rows/packet_size);
3394 if (cache_info->columns != columns)
3395 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3397 cache_info->length=length;
3398 status=AcquireMagickResource(AreaResource,cache_info->length);
3399 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3400 cache_info->metacontent_extent);
3401 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3403 status=AcquireMagickResource(MemoryResource,cache_info->length);
3404 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3405 (cache_info->type == MemoryCache))
3407 AllocatePixelCachePixels(cache_info);
3408 if (cache_info->pixels == (Quantum *) NULL)
3409 cache_info->pixels=source_info.pixels;
3413 Create memory pixel cache.
3416 cache_info->type=MemoryCache;
3417 cache_info->metacontent=(void *) NULL;
3418 if (cache_info->metacontent_extent != 0)
3419 cache_info->metacontent=(void *) (cache_info->pixels+
3420 number_pixels*cache_info->number_channels);
3421 if ((source_info.storage_class != UndefinedClass) &&
3424 status=ClonePixelCacheRepository(cache_info,&source_info,
3426 RelinquishPixelCachePixels(&source_info);
3428 if (image->debug != MagickFalse)
3430 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3431 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3433 (void) FormatLocaleString(message,MaxTextExtent,
3434 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3435 cache_info->filename,cache_info->mapped != MagickFalse ?
3436 "Anonymous" : "Heap",type,(double) cache_info->columns,
3437 (double) cache_info->rows,(double)
3438 cache_info->number_channels,format);
3439 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3445 RelinquishMagickResource(MemoryResource,cache_info->length);
3448 Create pixel cache on disk.
3450 status=AcquireMagickResource(DiskResource,cache_info->length);
3451 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3456 if (cache_info->type == DistributedCache)
3457 RelinquishMagickResource(DiskResource,cache_info->length);
3458 server_info=AcquireDistributeCacheInfo(exception);
3459 if (server_info != (DistributeCacheInfo *) NULL)
3461 status=OpenDistributePixelCache(server_info,image);
3462 if (status == MagickFalse)
3464 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3465 GetDistributeCacheHostname(server_info));
3466 server_info=DestroyDistributeCacheInfo(server_info);
3471 Create a distributed pixel cache.
3473 cache_info->type=DistributedCache;
3474 cache_info->server_info=server_info;
3475 (void) FormatLocaleString(cache_info->cache_filename,
3476 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3477 (DistributeCacheInfo *) cache_info->server_info),
3478 GetDistributeCachePort((DistributeCacheInfo *)
3479 cache_info->server_info));
3480 if ((source_info.storage_class != UndefinedClass) &&
3483 status=ClonePixelCacheRepository(cache_info,&source_info,
3485 RelinquishPixelCachePixels(&source_info);
3487 if (image->debug != MagickFalse)
3489 (void) FormatMagickSize(cache_info->length,MagickFalse,
3491 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3493 (void) FormatLocaleString(message,MaxTextExtent,
3494 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3495 cache_info->filename,cache_info->cache_filename,
3496 GetDistributeCacheFile((DistributeCacheInfo *)
3497 cache_info->server_info),type,(double) cache_info->columns,
3498 (double) cache_info->rows,(double)
3499 cache_info->number_channels,format);
3500 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3506 RelinquishMagickResource(DiskResource,cache_info->length);
3507 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3508 "CacheResourcesExhausted","`%s'",image->filename);
3509 return(MagickFalse);
3511 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3513 (void) ClosePixelCacheOnDisk(cache_info);
3514 *cache_info->cache_filename='\0';
3516 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3518 RelinquishMagickResource(DiskResource,cache_info->length);
3519 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3521 return(MagickFalse);
3523 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3524 cache_info->length);
3525 if (status == MagickFalse)
3527 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3529 return(MagickFalse);
3531 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3532 cache_info->metacontent_extent);
3533 if (length != (MagickSizeType) ((size_t) length))
3534 cache_info->type=DiskCache;
3537 status=AcquireMagickResource(MapResource,cache_info->length);
3538 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3539 (cache_info->type != MemoryCache))
3540 cache_info->type=DiskCache;
3543 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3544 cache_info->offset,(size_t) cache_info->length);
3545 if (cache_info->pixels == (Quantum *) NULL)
3547 cache_info->type=DiskCache;
3548 cache_info->pixels=source_info.pixels;
3553 Create file-backed memory-mapped pixel cache.
3556 (void) ClosePixelCacheOnDisk(cache_info);
3557 cache_info->type=MapCache;
3558 cache_info->mapped=MagickTrue;
3559 cache_info->metacontent=(void *) NULL;
3560 if (cache_info->metacontent_extent != 0)
3561 cache_info->metacontent=(void *) (cache_info->pixels+
3562 number_pixels*cache_info->number_channels);
3563 if ((source_info.storage_class != UndefinedClass) &&
3566 status=ClonePixelCacheRepository(cache_info,&source_info,
3568 RelinquishPixelCachePixels(&source_info);
3570 if (image->debug != MagickFalse)
3572 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3573 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3575 (void) FormatLocaleString(message,MaxTextExtent,
3576 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3577 cache_info->filename,cache_info->cache_filename,
3578 cache_info->file,type,(double) cache_info->columns,(double)
3579 cache_info->rows,(double) cache_info->number_channels,
3581 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3587 RelinquishMagickResource(MapResource,cache_info->length);
3590 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3592 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3593 RelinquishPixelCachePixels(&source_info);
3595 if (image->debug != MagickFalse)
3597 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3598 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3600 (void) FormatLocaleString(message,MaxTextExtent,
3601 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3602 cache_info->cache_filename,cache_info->file,type,(double)
3603 cache_info->columns,(double) cache_info->rows,(double)
3604 cache_info->number_channels,format);
3605 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3615 + P e r s i s t P i x e l C a c h e %
3619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3621 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3622 % persistent pixel cache is one that resides on disk and is not destroyed
3623 % when the program exits.
3625 % The format of the PersistPixelCache() method is:
3627 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3628 % const MagickBooleanType attach,MagickOffsetType *offset,
3629 % ExceptionInfo *exception)
3631 % A description of each parameter follows:
3633 % o image: the image.
3635 % o filename: the persistent pixel cache filename.
3637 % o attach: A value other than zero initializes the persistent pixel cache.
3639 % o initialize: A value other than zero initializes the persistent pixel
3642 % o offset: the offset in the persistent cache to store pixels.
3644 % o exception: return any errors or warnings in this structure.
3647 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3648 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3649 ExceptionInfo *exception)
3652 *restrict cache_info,
3653 *restrict clone_info;
3664 assert(image != (Image *) NULL);
3665 assert(image->signature == MagickSignature);
3666 if (image->debug != MagickFalse)
3667 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3668 assert(image->cache != (void *) NULL);
3669 assert(filename != (const char *) NULL);
3670 assert(offset != (MagickOffsetType *) NULL);
3671 page_size=GetMagickPageSize();
3672 cache_info=(CacheInfo *) image->cache;
3673 assert(cache_info->signature == MagickSignature);
3674 if (attach != MagickFalse)
3677 Attach existing persistent pixel cache.
3679 if (image->debug != MagickFalse)
3680 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3681 "attach persistent cache");
3682 (void) CopyMagickString(cache_info->cache_filename,filename,
3684 cache_info->type=DiskCache;
3685 cache_info->offset=(*offset);
3686 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3687 return(MagickFalse);
3688 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3691 if ((cache_info->mode != ReadMode) &&
3692 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3693 (cache_info->reference_count == 1))
3695 LockSemaphoreInfo(cache_info->semaphore);
3696 if ((cache_info->mode != ReadMode) &&
3697 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3698 (cache_info->reference_count == 1))
3704 Usurp existing persistent pixel cache.
3706 status=rename_utf8(cache_info->cache_filename,filename);
3709 (void) CopyMagickString(cache_info->cache_filename,filename,
3711 *offset+=cache_info->length+page_size-(cache_info->length %
3713 UnlockSemaphoreInfo(cache_info->semaphore);
3714 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3715 if (image->debug != MagickFalse)
3716 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3717 "Usurp resident persistent cache");
3721 UnlockSemaphoreInfo(cache_info->semaphore);
3724 Clone persistent pixel cache.
3726 clone_image=(*image);
3727 clone_info=(CacheInfo *) clone_image.cache;
3728 image->cache=ClonePixelCache(cache_info);
3729 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3730 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3731 cache_info->type=DiskCache;
3732 cache_info->offset=(*offset);
3733 cache_info=(CacheInfo *) image->cache;
3734 status=OpenPixelCache(image,IOMode,exception);
3735 if (status != MagickFalse)
3736 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3737 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3738 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3747 + 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 %
3751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3753 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3754 % defined by the region rectangle and returns a pointer to the region. This
3755 % region is subsequently transferred from the pixel cache with
3756 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3757 % pixels are transferred, otherwise a NULL is returned.
3759 % The format of the QueueAuthenticPixelCacheNexus() method is:
3761 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3762 % const ssize_t y,const size_t columns,const size_t rows,
3763 % const MagickBooleanType clone,NexusInfo *nexus_info,
3764 % ExceptionInfo *exception)
3766 % A description of each parameter follows:
3768 % o image: the image.
3770 % o x,y,columns,rows: These values define the perimeter of a region of
3773 % o nexus_info: the cache nexus to set.
3775 % o clone: clone the pixel cache.
3777 % o exception: return any errors or warnings in this structure.
3780 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3781 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3782 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3785 *restrict cache_info;
3800 Validate pixel cache geometry.
3802 assert(image != (const Image *) NULL);
3803 assert(image->signature == MagickSignature);
3804 assert(image->cache != (Cache) NULL);
3805 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3806 if (cache_info == (Cache) NULL)
3807 return((Quantum *) NULL);
3808 assert(cache_info->signature == MagickSignature);
3809 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3810 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3811 (y >= (ssize_t) cache_info->rows))
3813 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3814 "PixelsAreNotAuthentic","`%s'",image->filename);
3815 return((Quantum *) NULL);
3817 offset=(MagickOffsetType) y*cache_info->columns+x;
3819 return((Quantum *) NULL);
3820 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3821 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3822 if ((MagickSizeType) offset >= number_pixels)
3823 return((Quantum *) NULL);
3829 region.width=columns;
3831 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3841 + 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 %
3845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3847 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3848 % defined by the region rectangle and returns a pointer to the region. This
3849 % region is subsequently transferred from the pixel cache with
3850 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3851 % pixels are transferred, otherwise a NULL is returned.
3853 % The format of the QueueAuthenticPixelsCache() method is:
3855 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3856 % const ssize_t y,const size_t columns,const size_t rows,
3857 % ExceptionInfo *exception)
3859 % A description of each parameter follows:
3861 % o image: the image.
3863 % o x,y,columns,rows: These values define the perimeter of a region of
3866 % o exception: return any errors or warnings in this structure.
3869 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3870 const ssize_t y,const size_t columns,const size_t rows,
3871 ExceptionInfo *exception)
3874 *restrict cache_info;
3877 id = GetOpenMPThreadId();
3882 assert(image != (const Image *) NULL);
3883 assert(image->signature == MagickSignature);
3884 assert(image->cache != (Cache) NULL);
3885 cache_info=(CacheInfo *) image->cache;
3886 assert(cache_info->signature == MagickSignature);
3887 assert(id < (int) cache_info->number_threads);
3888 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3889 cache_info->nexus_info[id],exception);
3894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3898 % Q u e u e A u t h e n t i c P i x e l s %
3902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3904 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3905 % successfully initialized a pointer to a Quantum array representing the
3906 % region is returned, otherwise NULL is returned. The returned pointer may
3907 % point to a temporary working buffer for the pixels or it may point to the
3908 % final location of the pixels in memory.
3910 % Write-only access means that any existing pixel values corresponding to
3911 % the region are ignored. This is useful if the initial image is being
3912 % created from scratch, or if the existing pixel values are to be
3913 % completely replaced without need to refer to their pre-existing values.
3914 % The application is free to read and write the pixel buffer returned by
3915 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3916 % initialize the pixel array values. Initializing pixel array values is the
3917 % application's responsibility.
3919 % Performance is maximized if the selected region is part of one row, or
3920 % one or more full rows, since then there is opportunity to access the
3921 % pixels in-place (without a copy) if the image is in memory, or in a
3922 % memory-mapped file. The returned pointer must *never* be deallocated
3925 % Pixels accessed via the returned pointer represent a simple array of type
3926 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3927 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3928 % obtain the meta-content (of type void) corresponding to the region.
3929 % Once the Quantum (and/or Quantum) array has been updated, the
3930 % changes must be saved back to the underlying image using
3931 % SyncAuthenticPixels() or they may be lost.
3933 % The format of the QueueAuthenticPixels() method is:
3935 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3936 % const ssize_t y,const size_t columns,const size_t rows,
3937 % ExceptionInfo *exception)
3939 % A description of each parameter follows:
3941 % o image: the image.
3943 % o x,y,columns,rows: These values define the perimeter of a region of
3946 % o exception: return any errors or warnings in this structure.
3949 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3950 const ssize_t y,const size_t columns,const size_t rows,
3951 ExceptionInfo *exception)
3954 *restrict cache_info;
3957 id = GetOpenMPThreadId();
3962 assert(image != (Image *) NULL);
3963 assert(image->signature == MagickSignature);
3964 assert(image->cache != (Cache) NULL);
3965 cache_info=(CacheInfo *) image->cache;
3966 assert(cache_info->signature == MagickSignature);
3967 if (cache_info->methods.queue_authentic_pixels_handler !=
3968 (QueueAuthenticPixelsHandler) NULL)
3970 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3971 columns,rows,exception);
3974 assert(id < (int) cache_info->number_threads);
3975 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3976 cache_info->nexus_info[id],exception);
3981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3985 + 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 %
3989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3991 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3994 % The format of the ReadPixelCacheMetacontent() method is:
3996 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
3997 % NexusInfo *nexus_info,ExceptionInfo *exception)
3999 % A description of each parameter follows:
4001 % o cache_info: the pixel cache.
4003 % o nexus_info: the cache nexus to read the metacontent.
4005 % o exception: return any errors or warnings in this structure.
4009 static inline MagickOffsetType ReadPixelCacheRegion(
4010 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4011 const MagickSizeType length,unsigned char *restrict buffer)
4013 register MagickOffsetType
4019 #if !defined(MAGICKCORE_HAVE_PREAD)
4020 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4021 return((MagickOffsetType) -1);
4024 for (i=0; i < (MagickOffsetType) length; i+=count)
4026 #if !defined(MAGICKCORE_HAVE_PREAD)
4027 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4028 (MagickSizeType) SSIZE_MAX));
4030 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4031 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4043 static MagickBooleanType ReadPixelCacheMetacontent(
4044 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4045 ExceptionInfo *exception)
4058 register unsigned char
4064 if (cache_info->metacontent_extent == 0)
4065 return(MagickFalse);
4066 if (nexus_info->authentic_pixel_cache != MagickFalse)
4068 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4069 nexus_info->region.x;
4070 length=(MagickSizeType) nexus_info->region.width*
4071 cache_info->metacontent_extent;
4072 extent=length*nexus_info->region.height;
4073 rows=nexus_info->region.height;
4075 q=(unsigned char *) nexus_info->metacontent;
4076 switch (cache_info->type)
4081 register unsigned char
4085 Read meta-content from memory.
4087 if ((cache_info->columns == nexus_info->region.width) &&
4088 (extent == (MagickSizeType) ((size_t) extent)))
4093 p=(unsigned char *) cache_info->metacontent+offset*
4094 cache_info->metacontent_extent;
4095 for (y=0; y < (ssize_t) rows; y++)
4097 (void) memcpy(q,p,(size_t) length);
4098 p+=cache_info->metacontent_extent*cache_info->columns;
4099 q+=cache_info->metacontent_extent*nexus_info->region.width;
4106 Read meta content from disk.
4108 LockSemaphoreInfo(cache_info->file_semaphore);
4109 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4111 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4112 cache_info->cache_filename);
4113 UnlockSemaphoreInfo(cache_info->file_semaphore);
4114 return(MagickFalse);
4116 if ((cache_info->columns == nexus_info->region.width) &&
4117 (extent <= MagickMaxBufferExtent))
4122 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4123 for (y=0; y < (ssize_t) rows; y++)
4125 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4126 cache_info->number_channels*sizeof(Quantum)+offset*
4127 cache_info->metacontent_extent,length,(unsigned char *) q);
4128 if (count != (MagickOffsetType) length)
4130 offset+=cache_info->columns;
4131 q+=cache_info->metacontent_extent*nexus_info->region.width;
4133 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4134 (void) ClosePixelCacheOnDisk(cache_info);
4135 UnlockSemaphoreInfo(cache_info->file_semaphore);
4138 case DistributedCache:
4144 Read metacontent from distributed cache.
4146 LockSemaphoreInfo(cache_info->file_semaphore);
4147 region=nexus_info->region;
4148 if ((cache_info->columns != nexus_info->region.width) ||
4149 (extent > MagickMaxBufferExtent))
4156 for (y=0; y < (ssize_t) rows; y++)
4158 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4159 cache_info->server_info,®ion,length,(unsigned char *) q);
4160 if (count != (MagickOffsetType) length)
4162 q+=cache_info->metacontent_extent*nexus_info->region.width;
4165 UnlockSemaphoreInfo(cache_info->file_semaphore);
4171 if (y < (ssize_t) rows)
4173 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4174 cache_info->cache_filename);
4175 return(MagickFalse);
4177 if ((cache_info->debug != MagickFalse) &&
4178 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4179 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4180 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4181 nexus_info->region.width,(double) nexus_info->region.height,(double)
4182 nexus_info->region.x,(double) nexus_info->region.y);
4187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4191 + R e a d P i x e l C a c h e P i x e l s %
4195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4197 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4200 % The format of the ReadPixelCachePixels() method is:
4202 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4203 % NexusInfo *nexus_info,ExceptionInfo *exception)
4205 % A description of each parameter follows:
4207 % o cache_info: the pixel cache.
4209 % o nexus_info: the cache nexus to read the pixels.
4211 % o exception: return any errors or warnings in this structure.
4214 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4215 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4234 if (nexus_info->authentic_pixel_cache != MagickFalse)
4236 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4237 nexus_info->region.x;
4238 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4240 extent=length*nexus_info->region.height;
4241 rows=nexus_info->region.height;
4243 q=nexus_info->pixels;
4244 switch (cache_info->type)
4253 Read pixels from memory.
4255 if ((cache_info->columns == nexus_info->region.width) &&
4256 (extent == (MagickSizeType) ((size_t) extent)))
4261 p=cache_info->pixels+offset*cache_info->number_channels;
4262 for (y=0; y < (ssize_t) rows; y++)
4264 (void) memcpy(q,p,(size_t) length);
4265 p+=cache_info->number_channels*cache_info->columns;
4266 q+=cache_info->number_channels*nexus_info->region.width;
4273 Read pixels from disk.
4275 LockSemaphoreInfo(cache_info->file_semaphore);
4276 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4278 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4279 cache_info->cache_filename);
4280 UnlockSemaphoreInfo(cache_info->file_semaphore);
4281 return(MagickFalse);
4283 if ((cache_info->columns == nexus_info->region.width) &&
4284 (extent <= MagickMaxBufferExtent))
4289 for (y=0; y < (ssize_t) rows; y++)
4291 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4292 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4293 if (count != (MagickOffsetType) length)
4295 offset+=cache_info->columns;
4296 q+=cache_info->number_channels*nexus_info->region.width;
4298 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4299 (void) ClosePixelCacheOnDisk(cache_info);
4300 UnlockSemaphoreInfo(cache_info->file_semaphore);
4303 case DistributedCache:
4309 Read pixels from distributed cache.
4311 LockSemaphoreInfo(cache_info->file_semaphore);
4312 region=nexus_info->region;
4313 if ((cache_info->columns != nexus_info->region.width) ||
4314 (extent > MagickMaxBufferExtent))
4321 for (y=0; y < (ssize_t) rows; y++)
4323 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4324 cache_info->server_info,®ion,length,(unsigned char *) q);
4325 if (count != (MagickOffsetType) length)
4327 q+=cache_info->number_channels*nexus_info->region.width;
4330 UnlockSemaphoreInfo(cache_info->file_semaphore);
4336 if (y < (ssize_t) rows)
4338 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4339 cache_info->cache_filename);
4340 return(MagickFalse);
4342 if ((cache_info->debug != MagickFalse) &&
4343 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4344 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4345 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4346 nexus_info->region.width,(double) nexus_info->region.height,(double)
4347 nexus_info->region.x,(double) nexus_info->region.y);
4352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4356 + R e f e r e n c e P i x e l C a c h e %
4360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4362 % ReferencePixelCache() increments the reference count associated with the
4363 % pixel cache returning a pointer to the cache.
4365 % The format of the ReferencePixelCache method is:
4367 % Cache ReferencePixelCache(Cache cache_info)
4369 % A description of each parameter follows:
4371 % o cache_info: the pixel cache.
4374 MagickPrivate Cache ReferencePixelCache(Cache cache)
4377 *restrict cache_info;
4379 assert(cache != (Cache *) NULL);
4380 cache_info=(CacheInfo *) cache;
4381 assert(cache_info->signature == MagickSignature);
4382 LockSemaphoreInfo(cache_info->semaphore);
4383 cache_info->reference_count++;
4384 UnlockSemaphoreInfo(cache_info->semaphore);
4389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4393 + S e t P i x e l C a c h e M e t h o d s %
4397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4399 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4401 % The format of the SetPixelCacheMethods() method is:
4403 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4405 % A description of each parameter follows:
4407 % o cache: the pixel cache.
4409 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4412 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4415 *restrict cache_info;
4417 GetOneAuthenticPixelFromHandler
4418 get_one_authentic_pixel_from_handler;
4420 GetOneVirtualPixelFromHandler
4421 get_one_virtual_pixel_from_handler;
4424 Set cache pixel methods.
4426 assert(cache != (Cache) NULL);
4427 assert(cache_methods != (CacheMethods *) NULL);
4428 cache_info=(CacheInfo *) cache;
4429 assert(cache_info->signature == MagickSignature);
4430 if (cache_info->debug != MagickFalse)
4431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4432 cache_info->filename);
4433 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4434 cache_info->methods.get_virtual_pixel_handler=
4435 cache_methods->get_virtual_pixel_handler;
4436 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4437 cache_info->methods.destroy_pixel_handler=
4438 cache_methods->destroy_pixel_handler;
4439 if (cache_methods->get_virtual_metacontent_from_handler !=
4440 (GetVirtualMetacontentFromHandler) NULL)
4441 cache_info->methods.get_virtual_metacontent_from_handler=
4442 cache_methods->get_virtual_metacontent_from_handler;
4443 if (cache_methods->get_authentic_pixels_handler !=
4444 (GetAuthenticPixelsHandler) NULL)
4445 cache_info->methods.get_authentic_pixels_handler=
4446 cache_methods->get_authentic_pixels_handler;
4447 if (cache_methods->queue_authentic_pixels_handler !=
4448 (QueueAuthenticPixelsHandler) NULL)
4449 cache_info->methods.queue_authentic_pixels_handler=
4450 cache_methods->queue_authentic_pixels_handler;
4451 if (cache_methods->sync_authentic_pixels_handler !=
4452 (SyncAuthenticPixelsHandler) NULL)
4453 cache_info->methods.sync_authentic_pixels_handler=
4454 cache_methods->sync_authentic_pixels_handler;
4455 if (cache_methods->get_authentic_pixels_from_handler !=
4456 (GetAuthenticPixelsFromHandler) NULL)
4457 cache_info->methods.get_authentic_pixels_from_handler=
4458 cache_methods->get_authentic_pixels_from_handler;
4459 if (cache_methods->get_authentic_metacontent_from_handler !=
4460 (GetAuthenticMetacontentFromHandler) NULL)
4461 cache_info->methods.get_authentic_metacontent_from_handler=
4462 cache_methods->get_authentic_metacontent_from_handler;
4463 get_one_virtual_pixel_from_handler=
4464 cache_info->methods.get_one_virtual_pixel_from_handler;
4465 if (get_one_virtual_pixel_from_handler !=
4466 (GetOneVirtualPixelFromHandler) NULL)
4467 cache_info->methods.get_one_virtual_pixel_from_handler=
4468 cache_methods->get_one_virtual_pixel_from_handler;
4469 get_one_authentic_pixel_from_handler=
4470 cache_methods->get_one_authentic_pixel_from_handler;
4471 if (get_one_authentic_pixel_from_handler !=
4472 (GetOneAuthenticPixelFromHandler) NULL)
4473 cache_info->methods.get_one_authentic_pixel_from_handler=
4474 cache_methods->get_one_authentic_pixel_from_handler;
4478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482 + S e t P i x e l C a c h e N e x u s P i x e l s %
4486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4488 % SetPixelCacheNexusPixels() defines the region of the cache for the
4489 % specified cache nexus.
4491 % The format of the SetPixelCacheNexusPixels() method is:
4493 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4494 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4495 % ExceptionInfo *exception)
4497 % A description of each parameter follows:
4499 % o cache_info: the pixel cache.
4501 % o mode: ReadMode, WriteMode, or IOMode.
4503 % o region: A pointer to the RectangleInfo structure that defines the
4504 % region of this particular cache nexus.
4506 % o nexus_info: the cache nexus to set.
4508 % o exception: return any errors or warnings in this structure.
4512 static inline MagickBooleanType AcquireCacheNexusPixels(
4513 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4514 ExceptionInfo *exception)
4516 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4517 return(MagickFalse);
4518 nexus_info->mapped=MagickFalse;
4519 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4520 (size_t) nexus_info->length));
4521 if (nexus_info->cache == (Quantum *) NULL)
4523 nexus_info->mapped=MagickTrue;
4524 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4525 nexus_info->length);
4527 if (nexus_info->cache == (Quantum *) NULL)
4529 (void) ThrowMagickException(exception,GetMagickModule(),
4530 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4531 cache_info->filename);
4532 return(MagickFalse);
4537 static inline MagickBooleanType IsPixelCacheAuthentic(
4538 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4547 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4549 if (cache_info->type == PingCache)
4551 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4552 nexus_info->region.x;
4553 status=nexus_info->pixels == (cache_info->pixels+offset*
4554 cache_info->number_channels) ? MagickTrue : MagickFalse;
4558 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4561 if (mode == ReadMode)
4563 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4566 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4569 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4570 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4571 ExceptionInfo *exception)
4580 assert(cache_info != (const CacheInfo *) NULL);
4581 assert(cache_info->signature == MagickSignature);
4582 if (cache_info->type == UndefinedCache)
4583 return((Quantum *) NULL);
4584 nexus_info->region=(*region);
4585 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4591 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4592 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4593 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4594 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4595 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4596 ((nexus_info->region.width == cache_info->columns) ||
4597 ((nexus_info->region.width % cache_info->columns) == 0)))))
4603 Pixels are accessed directly from memory.
4605 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4606 nexus_info->region.x;
4607 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4609 nexus_info->metacontent=(void *) NULL;
4610 if (cache_info->metacontent_extent != 0)
4611 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4612 offset*cache_info->metacontent_extent;
4613 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4614 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4616 return(nexus_info->pixels);
4620 Pixels are stored in a staging region until they are synced to the cache.
4622 number_pixels=(MagickSizeType) nexus_info->region.width*
4623 nexus_info->region.height;
4624 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4625 if (cache_info->metacontent_extent != 0)
4626 length+=number_pixels*cache_info->metacontent_extent;
4627 if (nexus_info->cache == (Quantum *) NULL)
4629 nexus_info->length=length;
4630 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4631 if (status == MagickFalse)
4633 nexus_info->length=0;
4634 return((Quantum *) NULL);
4638 if (nexus_info->length < length)
4640 RelinquishCacheNexusPixels(nexus_info);
4641 nexus_info->length=length;
4642 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4643 if (status == MagickFalse)
4645 nexus_info->length=0;
4646 return((Quantum *) NULL);
4649 nexus_info->pixels=nexus_info->cache;
4650 nexus_info->metacontent=(void *) NULL;
4651 if (cache_info->metacontent_extent != 0)
4652 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4653 cache_info->number_channels);
4654 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4655 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4657 return(nexus_info->pixels);
4661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4665 % 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 %
4669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4671 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4672 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4673 % access that is outside the boundaries of the image cache.
4675 % The format of the SetPixelCacheVirtualMethod() method is:
4677 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4678 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4680 % A description of each parameter follows:
4682 % o image: the image.
4684 % o virtual_pixel_method: choose the type of virtual pixel.
4686 % o exception: return any errors or warnings in this structure.
4690 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4691 ExceptionInfo *exception)
4694 *restrict cache_info;
4697 *restrict image_view;
4705 assert(image != (Image *) NULL);
4706 assert(image->signature == MagickSignature);
4707 if (image->debug != MagickFalse)
4708 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4709 assert(image->cache != (Cache) NULL);
4710 cache_info=(CacheInfo *) image->cache;
4711 assert(cache_info->signature == MagickSignature);
4712 image->alpha_trait=BlendPixelTrait;
4714 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4715 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4716 #pragma omp parallel for schedule(static,4) shared(status) \
4717 magick_threads(image,image,1,1)
4719 for (y=0; y < (ssize_t) image->rows; y++)
4727 if (status == MagickFalse)
4729 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4730 if (q == (Quantum *) NULL)
4735 for (x=0; x < (ssize_t) image->columns; x++)
4737 SetPixelAlpha(image,alpha,q);
4738 q+=GetPixelChannels(image);
4740 status=SyncCacheViewAuthenticPixels(image_view,exception);
4742 image_view=DestroyCacheView(image_view);
4746 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4747 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4750 *restrict cache_info;
4755 assert(image != (Image *) NULL);
4756 assert(image->signature == MagickSignature);
4757 if (image->debug != MagickFalse)
4758 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4759 assert(image->cache != (Cache) NULL);
4760 cache_info=(CacheInfo *) image->cache;
4761 assert(cache_info->signature == MagickSignature);
4762 method=cache_info->virtual_pixel_method;
4763 cache_info->virtual_pixel_method=virtual_pixel_method;
4764 if ((image->columns != 0) && (image->rows != 0))
4765 switch (virtual_pixel_method)
4767 case BackgroundVirtualPixelMethod:
4769 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4770 (image->alpha_trait != BlendPixelTrait))
4771 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4772 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4773 (IsGrayColorspace(image->colorspace) != MagickFalse))
4774 (void) SetImageColorspace(image,sRGBColorspace,exception);
4777 case TransparentVirtualPixelMethod:
4779 if (image->alpha_trait != BlendPixelTrait)
4780 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4794 + 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 %
4798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4800 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4801 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4802 % is synced, otherwise MagickFalse.
4804 % The format of the SyncAuthenticPixelCacheNexus() method is:
4806 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4807 % NexusInfo *nexus_info,ExceptionInfo *exception)
4809 % A description of each parameter follows:
4811 % o image: the image.
4813 % o nexus_info: the cache nexus to sync.
4815 % o exception: return any errors or warnings in this structure.
4818 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4819 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4822 *restrict cache_info;
4828 Transfer pixels to the cache.
4830 assert(image != (Image *) NULL);
4831 assert(image->signature == MagickSignature);
4832 if (image->cache == (Cache) NULL)
4833 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4834 cache_info=(CacheInfo *) image->cache;
4835 assert(cache_info->signature == MagickSignature);
4836 if (cache_info->type == UndefinedCache)
4837 return(MagickFalse);
4838 if (nexus_info->authentic_pixel_cache != MagickFalse)
4840 assert(cache_info->signature == MagickSignature);
4841 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4842 if ((cache_info->metacontent_extent != 0) &&
4843 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4844 return(MagickFalse);
4849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4853 + S y n c A u t h e n t i c P i x e l C a c h e %
4857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4859 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4860 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4861 % otherwise MagickFalse.
4863 % The format of the SyncAuthenticPixelsCache() method is:
4865 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4866 % ExceptionInfo *exception)
4868 % A description of each parameter follows:
4870 % o image: the image.
4872 % o exception: return any errors or warnings in this structure.
4875 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4876 ExceptionInfo *exception)
4879 *restrict cache_info;
4882 id = GetOpenMPThreadId();
4887 assert(image != (Image *) NULL);
4888 assert(image->signature == MagickSignature);
4889 assert(image->cache != (Cache) NULL);
4890 cache_info=(CacheInfo *) image->cache;
4891 assert(cache_info->signature == MagickSignature);
4892 assert(id < (int) cache_info->number_threads);
4893 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4903 % S y n c A u t h e n t i c P i x e l s %
4907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4909 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4910 % The method returns MagickTrue if the pixel region is flushed, otherwise
4913 % The format of the SyncAuthenticPixels() method is:
4915 % MagickBooleanType SyncAuthenticPixels(Image *image,
4916 % ExceptionInfo *exception)
4918 % A description of each parameter follows:
4920 % o image: the image.
4922 % o exception: return any errors or warnings in this structure.
4925 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4926 ExceptionInfo *exception)
4929 *restrict cache_info;
4932 id = GetOpenMPThreadId();
4937 assert(image != (Image *) NULL);
4938 assert(image->signature == MagickSignature);
4939 assert(image->cache != (Cache) NULL);
4940 cache_info=(CacheInfo *) image->cache;
4941 assert(cache_info->signature == MagickSignature);
4942 if (cache_info->methods.sync_authentic_pixels_handler !=
4943 (SyncAuthenticPixelsHandler) NULL)
4945 status=cache_info->methods.sync_authentic_pixels_handler(image,
4949 assert(id < (int) cache_info->number_threads);
4950 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4960 + S y n c I m a g e P i x e l C a c h e %
4964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4966 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4967 % The method returns MagickTrue if the pixel region is flushed, otherwise
4970 % The format of the SyncImagePixelCache() method is:
4972 % MagickBooleanType SyncImagePixelCache(Image *image,
4973 % ExceptionInfo *exception)
4975 % A description of each parameter follows:
4977 % o image: the image.
4979 % o exception: return any errors or warnings in this structure.
4982 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4983 ExceptionInfo *exception)
4986 *restrict cache_info;
4988 assert(image != (Image *) NULL);
4989 assert(exception != (ExceptionInfo *) NULL);
4990 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4991 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4999 + 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 %
5003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5005 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5006 % of the pixel cache.
5008 % The format of the WritePixelCacheMetacontent() method is:
5010 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5011 % NexusInfo *nexus_info,ExceptionInfo *exception)
5013 % A description of each parameter follows:
5015 % o cache_info: the pixel cache.
5017 % o nexus_info: the cache nexus to write the meta-content.
5019 % o exception: return any errors or warnings in this structure.
5022 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5023 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5033 register const unsigned char
5042 if (cache_info->metacontent_extent == 0)
5043 return(MagickFalse);
5044 if (nexus_info->authentic_pixel_cache != MagickFalse)
5046 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5047 nexus_info->region.x;
5048 length=(MagickSizeType) nexus_info->region.width*
5049 cache_info->metacontent_extent;
5050 extent=(MagickSizeType) length*nexus_info->region.height;
5051 rows=nexus_info->region.height;
5053 p=(unsigned char *) nexus_info->metacontent;
5054 switch (cache_info->type)
5059 register unsigned char
5063 Write associated pixels to memory.
5065 if ((cache_info->columns == nexus_info->region.width) &&
5066 (extent == (MagickSizeType) ((size_t) extent)))
5071 q=(unsigned char *) cache_info->metacontent+offset*
5072 cache_info->metacontent_extent;
5073 for (y=0; y < (ssize_t) rows; y++)
5075 (void) memcpy(q,p,(size_t) length);
5076 p+=nexus_info->region.width*cache_info->metacontent_extent;
5077 q+=cache_info->columns*cache_info->metacontent_extent;
5084 Write associated pixels to disk.
5086 LockSemaphoreInfo(cache_info->file_semaphore);
5087 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5089 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5090 cache_info->cache_filename);
5091 UnlockSemaphoreInfo(cache_info->file_semaphore);
5092 return(MagickFalse);
5094 if ((cache_info->columns == nexus_info->region.width) &&
5095 (extent <= MagickMaxBufferExtent))
5100 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5101 for (y=0; y < (ssize_t) rows; y++)
5103 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5104 cache_info->number_channels*sizeof(Quantum)+offset*
5105 cache_info->metacontent_extent,length,(const unsigned char *) p);
5106 if (count != (MagickOffsetType) length)
5108 p+=cache_info->metacontent_extent*nexus_info->region.width;
5109 offset+=cache_info->columns;
5111 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5112 (void) ClosePixelCacheOnDisk(cache_info);
5113 UnlockSemaphoreInfo(cache_info->file_semaphore);
5116 case DistributedCache:
5122 Write metacontent to distributed cache.
5124 LockSemaphoreInfo(cache_info->file_semaphore);
5125 region=nexus_info->region;
5126 if ((cache_info->columns != nexus_info->region.width) ||
5127 (extent > MagickMaxBufferExtent))
5134 for (y=0; y < (ssize_t) rows; y++)
5136 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5137 cache_info->server_info,®ion,length,(const unsigned char *) p);
5138 if (count != (MagickOffsetType) length)
5140 p+=cache_info->metacontent_extent*nexus_info->region.width;
5143 UnlockSemaphoreInfo(cache_info->file_semaphore);
5149 if (y < (ssize_t) rows)
5151 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5152 cache_info->cache_filename);
5153 return(MagickFalse);
5155 if ((cache_info->debug != MagickFalse) &&
5156 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5157 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5158 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5159 nexus_info->region.width,(double) nexus_info->region.height,(double)
5160 nexus_info->region.x,(double) nexus_info->region.y);
5165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5169 + W r i t e C a c h e P i x e l s %
5173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175 % WritePixelCachePixels() writes image pixels to the specified region of the
5178 % The format of the WritePixelCachePixels() method is:
5180 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5181 % NexusInfo *nexus_info,ExceptionInfo *exception)
5183 % A description of each parameter follows:
5185 % o cache_info: the pixel cache.
5187 % o nexus_info: the cache nexus to write the pixels.
5189 % o exception: return any errors or warnings in this structure.
5192 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5193 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5203 register const Quantum
5212 if (nexus_info->authentic_pixel_cache != MagickFalse)
5214 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5215 nexus_info->region.x;
5216 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5218 extent=length*nexus_info->region.height;
5219 rows=nexus_info->region.height;
5221 p=nexus_info->pixels;
5222 switch (cache_info->type)
5231 Write pixels to memory.
5233 if ((cache_info->columns == nexus_info->region.width) &&
5234 (extent == (MagickSizeType) ((size_t) extent)))
5239 q=cache_info->pixels+offset*cache_info->number_channels;
5240 for (y=0; y < (ssize_t) rows; y++)
5242 (void) memcpy(q,p,(size_t) length);
5243 p+=cache_info->number_channels*nexus_info->region.width;
5244 q+=cache_info->columns*cache_info->number_channels;
5251 Write pixels to disk.
5253 LockSemaphoreInfo(cache_info->file_semaphore);
5254 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5256 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5257 cache_info->cache_filename);
5258 UnlockSemaphoreInfo(cache_info->file_semaphore);
5259 return(MagickFalse);
5261 if ((cache_info->columns == nexus_info->region.width) &&
5262 (extent <= MagickMaxBufferExtent))
5267 for (y=0; y < (ssize_t) rows; y++)
5269 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5270 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5272 if (count != (MagickOffsetType) length)
5274 p+=cache_info->number_channels*nexus_info->region.width;
5275 offset+=cache_info->columns;
5277 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5278 (void) ClosePixelCacheOnDisk(cache_info);
5279 UnlockSemaphoreInfo(cache_info->file_semaphore);
5282 case DistributedCache:
5288 Write pixels to distributed cache.
5290 LockSemaphoreInfo(cache_info->file_semaphore);
5291 region=nexus_info->region;
5292 if ((cache_info->columns != nexus_info->region.width) ||
5293 (extent > MagickMaxBufferExtent))
5300 for (y=0; y < (ssize_t) rows; y++)
5302 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5303 cache_info->server_info,®ion,length,(const unsigned char *) p);
5304 if (count != (MagickOffsetType) length)
5306 p+=cache_info->number_channels*nexus_info->region.width;
5309 UnlockSemaphoreInfo(cache_info->file_semaphore);
5315 if (y < (ssize_t) rows)
5317 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5318 cache_info->cache_filename);
5319 return(MagickFalse);
5321 if ((cache_info->debug != MagickFalse) &&
5322 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5323 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5324 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5325 nexus_info->region.width,(double) nexus_info->region.height,(double)
5326 nexus_info->region.x,(double) nexus_info->region.y);