2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
100 #if defined(__cplusplus) || defined(c_plusplus)
105 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
109 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
110 const ssize_t,const size_t,const size_t,ExceptionInfo *),
111 *GetVirtualPixelsCache(const Image *);
114 *GetVirtualMetacontentFromCache(const Image *);
116 static MagickBooleanType
117 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
120 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
122 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
123 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
124 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
125 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
129 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
130 const size_t,ExceptionInfo *),
131 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
132 const size_t,ExceptionInfo *),
133 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
134 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
136 #if defined(__cplusplus) || defined(c_plusplus)
143 static volatile MagickBooleanType
144 instantiate_cache = MagickFalse;
147 *cache_semaphore = (SemaphoreInfo *) NULL;
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 + A c q u i r e P i x e l C a c h e %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % AcquirePixelCache() acquires a pixel cache.
162 % The format of the AcquirePixelCache() method is:
164 % Cache AcquirePixelCache(const size_t number_threads)
166 % A description of each parameter follows:
168 % o number_threads: the number of nexus threads.
171 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
174 *restrict cache_info;
179 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
180 if (cache_info == (CacheInfo *) NULL)
181 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
182 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
183 cache_info->type=UndefinedCache;
184 cache_info->mode=IOMode;
185 cache_info->colorspace=sRGBColorspace;
186 cache_info->file=(-1);
187 cache_info->id=GetMagickThreadId();
188 cache_info->number_threads=number_threads;
189 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
190 cache_info->number_threads=GetOpenMPMaximumThreads();
191 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
192 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
193 if (cache_info->number_threads == 0)
194 cache_info->number_threads=1;
195 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
196 if (cache_info->nexus_info == (NexusInfo **) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
199 if (synchronize != (const char *) NULL)
201 cache_info->synchronize=IsStringTrue(synchronize);
202 synchronize=DestroyString(synchronize);
204 cache_info->semaphore=AllocateSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->file_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 return((Cache ) cache_info);
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % A c q u i r e P i x e l C a c h e N e x u s %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
225 % The format of the AcquirePixelCacheNexus method is:
227 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
229 % A description of each parameter follows:
231 % o number_threads: the number of nexus threads.
234 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
237 **restrict nexus_info;
242 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
243 number_threads,sizeof(*nexus_info)));
244 if (nexus_info == (NexusInfo **) NULL)
245 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
246 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
247 sizeof(**nexus_info));
248 if (nexus_info[0] == (NexusInfo *) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
251 for (i=0; i < (ssize_t) number_threads; i++)
253 nexus_info[i]=(&nexus_info[0][i]);
254 nexus_info[i]->signature=MagickSignature;
260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264 + A c q u i r e P i x e l C a c h e P i x e l s %
268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 % AcquirePixelCachePixels() returns the pixels associated with the specified
273 % The format of the AcquirePixelCachePixels() method is:
275 % const void *AcquirePixelCachePixels(const Image *image,
276 % MagickSizeType *length,ExceptionInfo *exception)
278 % A description of each parameter follows:
280 % o image: the image.
282 % o length: the pixel cache length.
284 % o exception: return any errors or warnings in this structure.
287 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
288 MagickSizeType *length,ExceptionInfo *exception)
291 *restrict cache_info;
293 assert(image != (const Image *) NULL);
294 assert(image->signature == MagickSignature);
295 assert(exception != (ExceptionInfo *) NULL);
296 assert(exception->signature == MagickSignature);
297 assert(image->cache != (Cache) NULL);
298 cache_info=(CacheInfo *) image->cache;
299 assert(cache_info->signature == MagickSignature);
301 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
302 return((const void *) NULL);
303 *length=cache_info->length;
304 return((const void *) cache_info->pixels);
308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 + C a c h e C o m p o n e n t G e n e s i s %
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 % CacheComponentGenesis() instantiates the cache component.
320 % The format of the CacheComponentGenesis method is:
322 % MagickBooleanType CacheComponentGenesis(void)
325 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
327 AcquireSemaphoreInfo(&cache_semaphore);
332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 + C a c h e C o m p o n e n t T e r m i n u s %
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 % CacheComponentTerminus() destroys the cache component.
344 % The format of the CacheComponentTerminus() method is:
346 % CacheComponentTerminus(void)
349 MagickPrivate void CacheComponentTerminus(void)
351 if (cache_semaphore == (SemaphoreInfo *) NULL)
352 AcquireSemaphoreInfo(&cache_semaphore);
353 LockSemaphoreInfo(cache_semaphore);
354 instantiate_cache=MagickFalse;
355 UnlockSemaphoreInfo(cache_semaphore);
356 DestroySemaphoreInfo(&cache_semaphore);
360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 + C l o n e P i x e l C a c h e %
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 % ClonePixelCache() clones a pixel cache.
372 % The format of the ClonePixelCache() method is:
374 % Cache ClonePixelCache(const Cache cache)
376 % A description of each parameter follows:
378 % o cache: the pixel cache.
381 MagickPrivate Cache ClonePixelCache(const Cache cache)
384 *restrict clone_info;
387 *restrict cache_info;
389 assert(cache != NULL);
390 cache_info=(const CacheInfo *) cache;
391 assert(cache_info->signature == MagickSignature);
392 if (cache_info->debug != MagickFalse)
393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
394 cache_info->filename);
395 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
396 if (clone_info == (Cache) NULL)
397 return((Cache) NULL);
398 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
399 return((Cache ) clone_info);
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 + C l o n e P i x e l C a c h e M e t h o d s %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
416 % The format of the ClonePixelCacheMethods() method is:
418 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
420 % A description of each parameter follows:
422 % o clone: Specifies a pointer to a Cache structure.
424 % o cache: the pixel cache.
427 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
430 *restrict cache_info,
431 *restrict source_info;
433 assert(clone != (Cache) NULL);
434 source_info=(CacheInfo *) clone;
435 assert(source_info->signature == MagickSignature);
436 if (source_info->debug != MagickFalse)
437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
438 source_info->filename);
439 assert(cache != (Cache) NULL);
440 cache_info=(CacheInfo *) cache;
441 assert(cache_info->signature == MagickSignature);
442 source_info->methods=cache_info->methods;
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450 + C l o n e P i x e l C a c h e R e p o s i t o r y %
454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
455 % ClonePixelCacheRepository() clones the source pixel cache to the destination
458 % The format of the ClonePixelCacheRepository() method is:
460 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
461 % CacheInfo *source_info,ExceptionInfo *exception)
463 % A description of each parameter follows:
465 % o cache_info: the pixel cache.
467 % o source_info: the source pixel cache.
469 % o exception: return any errors or warnings in this structure.
473 static inline void CopyPixels(Quantum *destination,const Quantum *source,
474 const MagickSizeType number_pixels)
476 #if !defined(MAGICKCORE_OPENMP_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH <= 8)
477 (void) memcpy(destination,source,(size_t) number_pixels*sizeof(*source));
480 register MagickOffsetType
483 if ((number_pixels*sizeof(*source)) < MagickMaxBufferExtent)
485 (void) memcpy(destination,source,(size_t) number_pixels*
489 #pragma omp parallel for
490 for (i=0; i < (MagickOffsetType) number_pixels; i++)
491 destination[i]=source[i];
496 static inline MagickSizeType MagickMin(const MagickSizeType x,
497 const MagickSizeType y)
504 static MagickBooleanType ClonePixelCacheRepository(
505 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
506 ExceptionInfo *exception)
508 #define MaxCacheThreads 2
509 #define cache_threads(source,destination,chunk) \
510 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
511 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
512 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
519 **restrict cache_nexus,
520 **restrict clone_nexus;
528 assert(cache_info != (CacheInfo *) NULL);
529 assert(clone_info != (CacheInfo *) NULL);
530 assert(exception != (ExceptionInfo *) NULL);
531 if (cache_info->type == PingCache)
533 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
534 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
535 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
536 (cache_info->columns == clone_info->columns) &&
537 (cache_info->rows == clone_info->rows) &&
538 (cache_info->number_channels == clone_info->number_channels) &&
539 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
540 (cache_info->metacontent_extent == clone_info->metacontent_extent))
542 CopyPixels(clone_info->pixels,cache_info->pixels,cache_info->columns*
543 cache_info->number_channels*cache_info->rows);
544 if (cache_info->metacontent_extent != 0)
545 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
546 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
547 sizeof(cache_info->metacontent));
551 Mismatched pixel cache morphology.
553 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
554 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
555 if ((cache_nexus == (NexusInfo **) NULL) ||
556 (clone_nexus == (NexusInfo **) NULL))
557 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
558 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
559 optimize=(cache_info->number_channels == clone_info->number_channels) &&
560 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
561 MagickTrue : MagickFalse;
562 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
563 clone_info->columns*clone_info->number_channels);
565 #if defined(MAGICKCORE_OPENMP_SUPPORT)
566 #pragma omp parallel for schedule(static,4) shared(status) \
567 cache_threads(cache_info,clone_info,cache_info->rows)
569 for (y=0; y < (ssize_t) cache_info->rows; y++)
572 id = GetOpenMPThreadId();
583 if (status == MagickFalse)
585 if (y >= (ssize_t) clone_info->rows)
587 region.width=cache_info->columns;
591 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
593 if (pixels == (Quantum *) NULL)
595 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
596 if (status == MagickFalse)
598 region.width=clone_info->columns;
599 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
600 clone_nexus[id],exception);
601 if (pixels == (Quantum *) NULL)
603 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 if (clone_nexus[id]->metacontent != (void *) NULL)
690 (void) memcpy(clone_nexus[id]->metacontent,
691 cache_nexus[id]->metacontent,length*
692 sizeof(cache_nexus[id]->metacontent));
693 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
696 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
697 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
698 if (cache_info->debug != MagickFalse)
701 message[MaxTextExtent];
703 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
704 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
705 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 + D e s t r o y I m a g e P i x e l C a c h e %
720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
724 % The format of the DestroyImagePixelCache() method is:
726 % void DestroyImagePixelCache(Image *image)
728 % A description of each parameter follows:
730 % o image: the image.
733 static void DestroyImagePixelCache(Image *image)
735 assert(image != (Image *) NULL);
736 assert(image->signature == MagickSignature);
737 if (image->debug != MagickFalse)
738 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
739 if (image->cache == (void *) NULL)
741 image->cache=DestroyPixelCache(image->cache);
745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749 + D e s t r o y I m a g e P i x e l s %
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755 % DestroyImagePixels() deallocates memory associated with the pixel cache.
757 % The format of the DestroyImagePixels() method is:
759 % void DestroyImagePixels(Image *image)
761 % A description of each parameter follows:
763 % o image: the image.
766 MagickExport void DestroyImagePixels(Image *image)
769 *restrict cache_info;
771 assert(image != (const Image *) NULL);
772 assert(image->signature == MagickSignature);
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
775 assert(image->cache != (Cache) NULL);
776 cache_info=(CacheInfo *) image->cache;
777 assert(cache_info->signature == MagickSignature);
778 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
780 cache_info->methods.destroy_pixel_handler(image);
783 image->cache=DestroyPixelCache(image->cache);
787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
791 + D e s t r o y P i x e l C a c h e %
795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797 % DestroyPixelCache() deallocates memory associated with the pixel cache.
799 % The format of the DestroyPixelCache() method is:
801 % Cache DestroyPixelCache(Cache cache)
803 % A description of each parameter follows:
805 % o cache: the pixel cache.
809 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
815 if (cache_info->file != -1)
817 status=close(cache_info->file);
818 cache_info->file=(-1);
819 RelinquishMagickResource(FileResource,1);
821 return(status == -1 ? MagickFalse : MagickTrue);
824 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
826 switch (cache_info->type)
830 if (cache_info->mapped == MagickFalse)
831 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
835 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
836 cache_info->pixels=(Quantum *) NULL;
838 RelinquishMagickResource(MemoryResource,cache_info->length);
843 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
844 cache_info->pixels=(Quantum *) NULL;
845 if (cache_info->mode != ReadMode)
846 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
847 *cache_info->cache_filename='\0';
848 RelinquishMagickResource(MapResource,cache_info->length);
852 if (cache_info->file != -1)
853 (void) ClosePixelCacheOnDisk(cache_info);
854 if (cache_info->mode != ReadMode)
855 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
856 *cache_info->cache_filename='\0';
857 RelinquishMagickResource(DiskResource,cache_info->length);
860 case DistributedCache:
862 *cache_info->cache_filename='\0';
863 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
864 cache_info->server_info);
870 cache_info->type=UndefinedCache;
871 cache_info->mapped=MagickFalse;
872 cache_info->metacontent=(void *) NULL;
875 MagickPrivate Cache DestroyPixelCache(Cache cache)
878 *restrict cache_info;
880 assert(cache != (Cache) NULL);
881 cache_info=(CacheInfo *) cache;
882 assert(cache_info->signature == MagickSignature);
883 if (cache_info->debug != MagickFalse)
884 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
885 cache_info->filename);
886 LockSemaphoreInfo(cache_info->semaphore);
887 cache_info->reference_count--;
888 if (cache_info->reference_count != 0)
890 UnlockSemaphoreInfo(cache_info->semaphore);
891 return((Cache) NULL);
893 UnlockSemaphoreInfo(cache_info->semaphore);
894 if (cache_info->debug != MagickFalse)
897 message[MaxTextExtent];
899 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
900 cache_info->filename);
901 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
903 RelinquishPixelCachePixels(cache_info);
904 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
905 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
906 cache_info->server_info);
907 if (cache_info->nexus_info != (NexusInfo **) NULL)
908 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
909 cache_info->number_threads);
910 if (cache_info->random_info != (RandomInfo *) NULL)
911 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
912 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
913 DestroySemaphoreInfo(&cache_info->file_semaphore);
914 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
915 DestroySemaphoreInfo(&cache_info->semaphore);
916 cache_info->signature=(~MagickSignature);
917 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
927 + D e s t r o y P i x e l C a c h e N e x u s %
931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
933 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
935 % The format of the DestroyPixelCacheNexus() method is:
937 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
938 % const size_t number_threads)
940 % A description of each parameter follows:
942 % o nexus_info: the nexus to destroy.
944 % o number_threads: the number of nexus threads.
948 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
950 if (nexus_info->mapped == MagickFalse)
951 (void) RelinquishAlignedMemory(nexus_info->cache);
953 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
954 nexus_info->cache=(Quantum *) NULL;
955 nexus_info->pixels=(Quantum *) NULL;
956 nexus_info->metacontent=(void *) NULL;
957 nexus_info->length=0;
958 nexus_info->mapped=MagickFalse;
961 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
962 const size_t number_threads)
967 assert(nexus_info != (NexusInfo **) NULL);
968 for (i=0; i < (ssize_t) number_threads; i++)
970 if (nexus_info[i]->cache != (Quantum *) NULL)
971 RelinquishCacheNexusPixels(nexus_info[i]);
972 nexus_info[i]->signature=(~MagickSignature);
974 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
975 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984 % G e t A u t h e n t i c M e t a c o n t e n t %
988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
991 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
992 % returned if the associated pixels are not available.
994 % The format of the GetAuthenticMetacontent() method is:
996 % void *GetAuthenticMetacontent(const Image *image)
998 % A description of each parameter follows:
1000 % o image: the image.
1003 MagickExport void *GetAuthenticMetacontent(const Image *image)
1006 *restrict cache_info;
1009 id = GetOpenMPThreadId();
1011 assert(image != (const Image *) NULL);
1012 assert(image->signature == MagickSignature);
1013 assert(image->cache != (Cache) NULL);
1014 cache_info=(CacheInfo *) image->cache;
1015 assert(cache_info->signature == MagickSignature);
1016 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1017 (GetAuthenticMetacontentFromHandler) NULL)
1022 metacontent=cache_info->methods.
1023 get_authentic_metacontent_from_handler(image);
1024 return(metacontent);
1026 assert(id < (int) cache_info->number_threads);
1027 return(cache_info->nexus_info[id]->metacontent);
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 + G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
1039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1042 % with the last call to QueueAuthenticPixelsCache() or
1043 % GetAuthenticPixelsCache().
1045 % The format of the GetAuthenticMetacontentFromCache() method is:
1047 % void *GetAuthenticMetacontentFromCache(const Image *image)
1049 % A description of each parameter follows:
1051 % o image: the image.
1054 static void *GetAuthenticMetacontentFromCache(const Image *image)
1057 *restrict cache_info;
1060 id = GetOpenMPThreadId();
1062 assert(image != (const Image *) NULL);
1063 assert(image->signature == MagickSignature);
1064 assert(image->cache != (Cache) NULL);
1065 cache_info=(CacheInfo *) image->cache;
1066 assert(cache_info->signature == MagickSignature);
1067 assert(id < (int) cache_info->number_threads);
1068 return(cache_info->nexus_info[id]->metacontent);
1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076 + 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 %
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1082 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1083 % disk pixel cache as defined by the geometry parameters. A pointer to the
1084 % pixels is returned if the pixels are transferred, otherwise a NULL is
1087 % The format of the GetAuthenticPixelCacheNexus() method is:
1089 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1090 % const ssize_t y,const size_t columns,const size_t rows,
1091 % NexusInfo *nexus_info,ExceptionInfo *exception)
1093 % A description of each parameter follows:
1095 % o image: the image.
1097 % o x,y,columns,rows: These values define the perimeter of a region of
1100 % o nexus_info: the cache nexus to return.
1102 % o exception: return any errors or warnings in this structure.
1106 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1107 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1108 ExceptionInfo *exception)
1111 *restrict cache_info;
1117 Transfer pixels from the cache.
1119 assert(image != (Image *) NULL);
1120 assert(image->signature == MagickSignature);
1121 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1122 nexus_info,exception);
1123 if (pixels == (Quantum *) NULL)
1124 return((Quantum *) NULL);
1125 cache_info=(CacheInfo *) image->cache;
1126 assert(cache_info->signature == MagickSignature);
1127 if (nexus_info->authentic_pixel_cache != MagickFalse)
1129 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1130 return((Quantum *) NULL);
1131 if (cache_info->metacontent_extent != 0)
1132 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1133 return((Quantum *) NULL);
1138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1142 + 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 %
1146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1148 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1149 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1151 % The format of the GetAuthenticPixelsFromCache() method is:
1153 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1155 % A description of each parameter follows:
1157 % o image: the image.
1160 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1163 *restrict cache_info;
1166 id = GetOpenMPThreadId();
1168 assert(image != (const Image *) NULL);
1169 assert(image->signature == MagickSignature);
1170 assert(image->cache != (Cache) NULL);
1171 cache_info=(CacheInfo *) image->cache;
1172 assert(cache_info->signature == MagickSignature);
1173 assert(id < (int) cache_info->number_threads);
1174 return(cache_info->nexus_info[id]->pixels);
1178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1182 % G e t A u t h e n t i c P i x e l Q u e u e %
1186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1188 % GetAuthenticPixelQueue() returns the authentic pixels associated
1189 % corresponding with the last call to QueueAuthenticPixels() or
1190 % GetAuthenticPixels().
1192 % The format of the GetAuthenticPixelQueue() method is:
1194 % Quantum *GetAuthenticPixelQueue(const Image image)
1196 % A description of each parameter follows:
1198 % o image: the image.
1201 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1204 *restrict cache_info;
1207 id = GetOpenMPThreadId();
1209 assert(image != (const Image *) NULL);
1210 assert(image->signature == MagickSignature);
1211 assert(image->cache != (Cache) NULL);
1212 cache_info=(CacheInfo *) image->cache;
1213 assert(cache_info->signature == MagickSignature);
1214 if (cache_info->methods.get_authentic_pixels_from_handler !=
1215 (GetAuthenticPixelsFromHandler) NULL)
1216 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1217 assert(id < (int) cache_info->number_threads);
1218 return(cache_info->nexus_info[id]->pixels);
1222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1226 % G e t A u t h e n t i c P i x e l s %
1229 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1231 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1232 % region is successfully accessed, a pointer to a Quantum array
1233 % representing the region is returned, otherwise NULL is returned.
1235 % The returned pointer may point to a temporary working copy of the pixels
1236 % or it may point to the original pixels in memory. Performance is maximized
1237 % if the selected region is part of one row, or one or more full rows, since
1238 % then there is opportunity to access the pixels in-place (without a copy)
1239 % if the image is in memory, or in a memory-mapped file. The returned pointer
1240 % must *never* be deallocated by the user.
1242 % Pixels accessed via the returned pointer represent a simple array of type
1243 % Quantum. If the image has corresponding metacontent,call
1244 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1245 % meta-content corresponding to the region. Once the Quantum array has
1246 % been updated, the changes must be saved back to the underlying image using
1247 % SyncAuthenticPixels() or they may be lost.
1249 % The format of the GetAuthenticPixels() method is:
1251 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1252 % const ssize_t y,const size_t columns,const size_t rows,
1253 % ExceptionInfo *exception)
1255 % A description of each parameter follows:
1257 % o image: the image.
1259 % o x,y,columns,rows: These values define the perimeter of a region of
1262 % o exception: return any errors or warnings in this structure.
1265 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1266 const ssize_t y,const size_t columns,const size_t rows,
1267 ExceptionInfo *exception)
1270 *restrict cache_info;
1273 id = GetOpenMPThreadId();
1278 assert(image != (Image *) NULL);
1279 assert(image->signature == MagickSignature);
1280 assert(image->cache != (Cache) NULL);
1281 cache_info=(CacheInfo *) image->cache;
1282 assert(cache_info->signature == MagickSignature);
1283 if (cache_info->methods.get_authentic_pixels_handler !=
1284 (GetAuthenticPixelsHandler) NULL)
1286 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1290 assert(id < (int) cache_info->number_threads);
1291 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1292 cache_info->nexus_info[id],exception);
1297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301 + G e t A u t h e n t i c P i x e l s C a c h e %
1305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1308 % as defined by the geometry parameters. A pointer to the pixels is returned
1309 % if the pixels are transferred, otherwise a NULL is returned.
1311 % The format of the GetAuthenticPixelsCache() method is:
1313 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1314 % const ssize_t y,const size_t columns,const size_t rows,
1315 % ExceptionInfo *exception)
1317 % A description of each parameter follows:
1319 % o image: the image.
1321 % o x,y,columns,rows: These values define the perimeter of a region of
1324 % o exception: return any errors or warnings in this structure.
1327 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1328 const ssize_t y,const size_t columns,const size_t rows,
1329 ExceptionInfo *exception)
1332 *restrict cache_info;
1335 id = GetOpenMPThreadId();
1340 assert(image != (const Image *) NULL);
1341 assert(image->signature == MagickSignature);
1342 assert(image->cache != (Cache) NULL);
1343 cache_info=(CacheInfo *) image->cache;
1344 if (cache_info == (Cache) NULL)
1345 return((Quantum *) NULL);
1346 assert(cache_info->signature == MagickSignature);
1347 assert(id < (int) cache_info->number_threads);
1348 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1349 cache_info->nexus_info[id],exception);
1354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1358 + G e t I m a g e E x t e n t %
1362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364 % GetImageExtent() returns the extent of the pixels associated corresponding
1365 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1367 % The format of the GetImageExtent() method is:
1369 % MagickSizeType GetImageExtent(const Image *image)
1371 % A description of each parameter follows:
1373 % o image: the image.
1376 MagickExport MagickSizeType GetImageExtent(const Image *image)
1379 *restrict cache_info;
1382 id = GetOpenMPThreadId();
1384 assert(image != (Image *) NULL);
1385 assert(image->signature == MagickSignature);
1386 if (image->debug != MagickFalse)
1387 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1388 assert(image->cache != (Cache) NULL);
1389 cache_info=(CacheInfo *) image->cache;
1390 assert(cache_info->signature == MagickSignature);
1391 assert(id < (int) cache_info->number_threads);
1392 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1400 + G e t I m a g e P i x e l C a c h e %
1404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406 % GetImagePixelCache() ensures that there is only a single reference to the
1407 % pixel cache to be modified, updating the provided cache pointer to point to
1408 % a clone of the original pixel cache if necessary.
1410 % The format of the GetImagePixelCache method is:
1412 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1413 % ExceptionInfo *exception)
1415 % A description of each parameter follows:
1417 % o image: the image.
1419 % o clone: any value other than MagickFalse clones the cache pixels.
1421 % o exception: return any errors or warnings in this structure.
1425 static inline MagickBooleanType ValidatePixelCacheMorphology(
1426 const Image *restrict image)
1429 *restrict cache_info;
1431 const PixelChannelMap
1436 Does the image match the pixel cache morphology?
1438 cache_info=(CacheInfo *) image->cache;
1439 p=image->channel_map;
1440 q=cache_info->channel_map;
1441 if ((image->storage_class != cache_info->storage_class) ||
1442 (image->colorspace != cache_info->colorspace) ||
1443 (image->alpha_trait != cache_info->alpha_trait) ||
1444 (image->read_mask != cache_info->read_mask) ||
1445 (image->write_mask != cache_info->write_mask) ||
1446 (image->columns != cache_info->columns) ||
1447 (image->rows != cache_info->rows) ||
1448 (image->number_channels != cache_info->number_channels) ||
1449 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1450 (image->metacontent_extent != cache_info->metacontent_extent) ||
1451 (cache_info->nexus_info == (NexusInfo **) NULL))
1452 return(MagickFalse);
1456 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1457 ExceptionInfo *exception)
1460 *restrict cache_info;
1466 static MagickSizeType
1472 cache_timestamp = 0;
1475 LockSemaphoreInfo(image->semaphore);
1476 if (cpu_throttle == 0)
1477 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1478 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1479 MagickDelay(cpu_throttle);
1480 if (time_limit == 0)
1483 Set the expire time in seconds.
1485 time_limit=GetMagickResourceLimit(TimeResource);
1486 cache_timestamp=time((time_t *) NULL);
1488 if ((time_limit != MagickResourceInfinity) &&
1489 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1490 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1491 assert(image->cache != (Cache) NULL);
1492 cache_info=(CacheInfo *) image->cache;
1493 destroy=MagickFalse;
1494 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1496 LockSemaphoreInfo(cache_info->semaphore);
1497 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1508 clone_image=(*image);
1509 clone_image.semaphore=AllocateSemaphoreInfo();
1510 clone_image.reference_count=1;
1511 clone_image.cache=ClonePixelCache(cache_info);
1512 clone_info=(CacheInfo *) clone_image.cache;
1513 status=OpenPixelCache(&clone_image,IOMode,exception);
1514 if (status != MagickFalse)
1516 if (clone != MagickFalse)
1517 status=ClonePixelCacheRepository(clone_info,cache_info,
1519 if (status != MagickFalse)
1521 if (cache_info->reference_count == 1)
1522 cache_info->nexus_info=(NexusInfo **) NULL;
1524 image->cache=clone_image.cache;
1527 DestroySemaphoreInfo(&clone_image.semaphore);
1529 UnlockSemaphoreInfo(cache_info->semaphore);
1531 if (destroy != MagickFalse)
1532 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1533 if (status != MagickFalse)
1536 Ensure the image matches the pixel cache morphology.
1538 image->taint=MagickTrue;
1539 image->type=UndefinedType;
1540 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1542 status=OpenPixelCache(image,IOMode,exception);
1543 cache_info=(CacheInfo *) image->cache;
1544 if (cache_info->type == DiskCache)
1545 (void) ClosePixelCacheOnDisk(cache_info);
1548 UnlockSemaphoreInfo(image->semaphore);
1549 if (status == MagickFalse)
1550 return((Cache) NULL);
1551 return(image->cache);
1555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559 + G e t I m a g e P i x e l C a c h e T y p e %
1563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1565 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1566 % DiskCache, MemoryCache, MapCache, or PingCache.
1568 % The format of the GetImagePixelCacheType() method is:
1570 % CacheType GetImagePixelCacheType(const Image *image)
1572 % A description of each parameter follows:
1574 % o image: the image.
1577 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1580 *restrict cache_info;
1582 assert(image != (Image *) NULL);
1583 assert(image->signature == MagickSignature);
1584 assert(image->cache != (Cache) NULL);
1585 cache_info=(CacheInfo *) image->cache;
1586 assert(cache_info->signature == MagickSignature);
1587 return(cache_info->type);
1591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595 % G e t O n e A u t h e n t i c P i x e l %
1599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1602 % location. The image background color is returned if an error occurs.
1604 % The format of the GetOneAuthenticPixel() method is:
1606 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1607 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1609 % A description of each parameter follows:
1611 % o image: the image.
1613 % o x,y: These values define the location of the pixel to return.
1615 % o pixel: return a pixel at the specified (x,y) location.
1617 % o exception: return any errors or warnings in this structure.
1620 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1621 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1624 *restrict cache_info;
1632 assert(image != (Image *) NULL);
1633 assert(image->signature == MagickSignature);
1634 assert(image->cache != (Cache) NULL);
1635 cache_info=(CacheInfo *) image->cache;
1636 assert(cache_info->signature == MagickSignature);
1637 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1638 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1639 (GetOneAuthenticPixelFromHandler) NULL)
1640 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1642 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1643 if (q == (Quantum *) NULL)
1645 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1646 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1647 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1648 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1649 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1650 return(MagickFalse);
1652 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1654 PixelChannel channel=GetPixelChannelChannel(image,i);
1655 pixel[channel]=q[i];
1661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1665 + 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 %
1669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1672 % location. The image background color is returned if an error occurs.
1674 % The format of the GetOneAuthenticPixelFromCache() method is:
1676 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1677 % const ssize_t x,const ssize_t y,Quantum *pixel,
1678 % ExceptionInfo *exception)
1680 % A description of each parameter follows:
1682 % o image: the image.
1684 % o x,y: These values define the location of the pixel to return.
1686 % o pixel: return a pixel at the specified (x,y) location.
1688 % o exception: return any errors or warnings in this structure.
1691 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1692 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1695 *restrict cache_info;
1698 id = GetOpenMPThreadId();
1706 assert(image != (const Image *) NULL);
1707 assert(image->signature == MagickSignature);
1708 assert(image->cache != (Cache) NULL);
1709 cache_info=(CacheInfo *) image->cache;
1710 assert(cache_info->signature == MagickSignature);
1711 assert(id < (int) cache_info->number_threads);
1712 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1713 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1715 if (q == (Quantum *) NULL)
1717 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1718 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1719 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1720 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1721 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1722 return(MagickFalse);
1724 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1726 PixelChannel channel=GetPixelChannelChannel(image,i);
1727 pixel[channel]=q[i];
1733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1737 % G e t O n e V i r t u a l P i x e l %
1741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1743 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1744 % (x,y) location. The image background color is returned if an error occurs.
1745 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1747 % The format of the GetOneVirtualPixel() method is:
1749 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1750 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1752 % A description of each parameter follows:
1754 % o image: the image.
1756 % o x,y: These values define the location of the pixel to return.
1758 % o pixel: return a pixel at the specified (x,y) location.
1760 % o exception: return any errors or warnings in this structure.
1763 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1764 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1767 *restrict cache_info;
1770 id = GetOpenMPThreadId();
1778 assert(image != (const Image *) NULL);
1779 assert(image->signature == MagickSignature);
1780 assert(image->cache != (Cache) NULL);
1781 cache_info=(CacheInfo *) image->cache;
1782 assert(cache_info->signature == MagickSignature);
1783 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1784 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1785 (GetOneVirtualPixelFromHandler) NULL)
1786 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1787 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1788 assert(id < (int) cache_info->number_threads);
1789 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1790 1UL,1UL,cache_info->nexus_info[id],exception);
1791 if (p == (const Quantum *) NULL)
1793 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1794 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1795 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1796 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1797 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1798 return(MagickFalse);
1800 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1802 PixelChannel channel=GetPixelChannelChannel(image,i);
1803 pixel[channel]=p[i];
1809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1813 + 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 %
1817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1819 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1820 % specified (x,y) location. The image background color is returned if an
1823 % The format of the GetOneVirtualPixelFromCache() method is:
1825 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1826 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1827 % Quantum *pixel,ExceptionInfo *exception)
1829 % A description of each parameter follows:
1831 % o image: the image.
1833 % o virtual_pixel_method: the virtual pixel method.
1835 % o x,y: These values define the location of the pixel to return.
1837 % o pixel: return a pixel at the specified (x,y) location.
1839 % o exception: return any errors or warnings in this structure.
1842 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1843 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1844 Quantum *pixel,ExceptionInfo *exception)
1847 *restrict cache_info;
1850 id = GetOpenMPThreadId();
1858 assert(image != (const Image *) NULL);
1859 assert(image->signature == MagickSignature);
1860 assert(image->cache != (Cache) NULL);
1861 cache_info=(CacheInfo *) image->cache;
1862 assert(cache_info->signature == MagickSignature);
1863 assert(id < (int) cache_info->number_threads);
1864 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1865 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1866 cache_info->nexus_info[id],exception);
1867 if (p == (const Quantum *) NULL)
1869 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1870 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1871 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1872 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1873 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1874 return(MagickFalse);
1876 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1878 PixelChannel channel=GetPixelChannelChannel(image,i);
1879 pixel[channel]=p[i];
1885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1889 % G e t O n e V i r t u a l P i x e l I n f o %
1893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1895 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1896 % location. The image background color is returned if an error occurs. If
1897 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1899 % The format of the GetOneVirtualPixelInfo() method is:
1901 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1902 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1903 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1905 % A description of each parameter follows:
1907 % o image: the image.
1909 % o virtual_pixel_method: the virtual pixel method.
1911 % o x,y: these values define the location of the pixel to return.
1913 % o pixel: return a pixel at the specified (x,y) location.
1915 % o exception: return any errors or warnings in this structure.
1918 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1919 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1920 PixelInfo *pixel,ExceptionInfo *exception)
1923 *restrict cache_info;
1926 id = GetOpenMPThreadId();
1928 register const Quantum
1931 assert(image != (const Image *) NULL);
1932 assert(image->signature == MagickSignature);
1933 assert(image->cache != (Cache) NULL);
1934 cache_info=(CacheInfo *) image->cache;
1935 assert(cache_info->signature == MagickSignature);
1936 assert(id < (int) cache_info->number_threads);
1937 GetPixelInfo(image,pixel);
1938 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1939 cache_info->nexus_info[id],exception);
1940 if (p == (const Quantum *) NULL)
1941 return(MagickFalse);
1942 GetPixelInfoPixel(image,p,pixel);
1947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951 + G e t P i x e l C a c h e C o l o r s p a c e %
1955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1957 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1959 % The format of the GetPixelCacheColorspace() method is:
1961 % Colorspace GetPixelCacheColorspace(Cache cache)
1963 % A description of each parameter follows:
1965 % o cache: the pixel cache.
1968 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1971 *restrict cache_info;
1973 assert(cache != (Cache) NULL);
1974 cache_info=(CacheInfo *) cache;
1975 assert(cache_info->signature == MagickSignature);
1976 if (cache_info->debug != MagickFalse)
1977 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1978 cache_info->filename);
1979 return(cache_info->colorspace);
1983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987 + G e t P i x e l C a c h e M e t h o d s %
1991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1993 % GetPixelCacheMethods() initializes the CacheMethods structure.
1995 % The format of the GetPixelCacheMethods() method is:
1997 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1999 % A description of each parameter follows:
2001 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2004 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2006 assert(cache_methods != (CacheMethods *) NULL);
2007 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2008 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2009 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2010 cache_methods->get_virtual_metacontent_from_handler=
2011 GetVirtualMetacontentFromCache;
2012 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2013 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2014 cache_methods->get_authentic_metacontent_from_handler=
2015 GetAuthenticMetacontentFromCache;
2016 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2017 cache_methods->get_one_authentic_pixel_from_handler=
2018 GetOneAuthenticPixelFromCache;
2019 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2020 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2021 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2029 + G e t P i x e l C a c h e N e x u s E x t e n t %
2033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2035 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2036 % corresponding with the last call to SetPixelCacheNexusPixels() or
2037 % GetPixelCacheNexusPixels().
2039 % The format of the GetPixelCacheNexusExtent() method is:
2041 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2042 % NexusInfo *nexus_info)
2044 % A description of each parameter follows:
2046 % o nexus_info: the nexus info.
2049 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2050 NexusInfo *restrict nexus_info)
2053 *restrict cache_info;
2058 assert(cache != NULL);
2059 cache_info=(CacheInfo *) cache;
2060 assert(cache_info->signature == MagickSignature);
2061 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2063 return((MagickSizeType) cache_info->columns*cache_info->rows);
2068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072 + G e t P i x e l C a c h e P i x e l s %
2076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078 % GetPixelCachePixels() returns the pixels associated with the specified image.
2080 % The format of the GetPixelCachePixels() method is:
2082 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2083 % ExceptionInfo *exception)
2085 % A description of each parameter follows:
2087 % o image: the image.
2089 % o length: the pixel cache length.
2091 % o exception: return any errors or warnings in this structure.
2094 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2095 ExceptionInfo *exception)
2098 *restrict cache_info;
2100 assert(image != (const Image *) NULL);
2101 assert(image->signature == MagickSignature);
2102 assert(image->cache != (Cache) NULL);
2103 assert(length != (MagickSizeType *) NULL);
2104 assert(exception != (ExceptionInfo *) NULL);
2105 assert(exception->signature == MagickSignature);
2106 cache_info=(CacheInfo *) image->cache;
2107 assert(cache_info->signature == MagickSignature);
2109 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2110 return((void *) NULL);
2111 *length=cache_info->length;
2112 return((void *) cache_info->pixels);
2116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2120 + 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 %
2124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2126 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2128 % The format of the GetPixelCacheStorageClass() method is:
2130 % ClassType GetPixelCacheStorageClass(Cache cache)
2132 % A description of each parameter follows:
2134 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2136 % o cache: the pixel cache.
2139 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2142 *restrict cache_info;
2144 assert(cache != (Cache) NULL);
2145 cache_info=(CacheInfo *) cache;
2146 assert(cache_info->signature == MagickSignature);
2147 if (cache_info->debug != MagickFalse)
2148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2149 cache_info->filename);
2150 return(cache_info->storage_class);
2154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158 + G e t P i x e l C a c h e T i l e S i z e %
2162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164 % GetPixelCacheTileSize() returns the pixel cache tile size.
2166 % The format of the GetPixelCacheTileSize() method is:
2168 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2171 % A description of each parameter follows:
2173 % o image: the image.
2175 % o width: the optimize cache tile width in pixels.
2177 % o height: the optimize cache tile height in pixels.
2180 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2184 *restrict cache_info;
2186 assert(image != (Image *) NULL);
2187 assert(image->signature == MagickSignature);
2188 if (image->debug != MagickFalse)
2189 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2190 cache_info=(CacheInfo *) image->cache;
2191 assert(cache_info->signature == MagickSignature);
2192 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2193 if (GetImagePixelCacheType(image) == DiskCache)
2194 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2203 + 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 %
2207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2209 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2210 % pixel cache. A virtual pixel is any pixel access that is outside the
2211 % boundaries of the image cache.
2213 % The format of the GetPixelCacheVirtualMethod() method is:
2215 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2217 % A description of each parameter follows:
2219 % o image: the image.
2222 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2225 *restrict cache_info;
2227 assert(image != (Image *) NULL);
2228 assert(image->signature == MagickSignature);
2229 assert(image->cache != (Cache) NULL);
2230 cache_info=(CacheInfo *) image->cache;
2231 assert(cache_info->signature == MagickSignature);
2232 return(cache_info->virtual_pixel_method);
2236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240 + 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 %
2244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2246 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2247 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2249 % The format of the GetVirtualMetacontentFromCache() method is:
2251 % void *GetVirtualMetacontentFromCache(const Image *image)
2253 % A description of each parameter follows:
2255 % o image: the image.
2258 static const void *GetVirtualMetacontentFromCache(const Image *image)
2261 *restrict cache_info;
2264 id = GetOpenMPThreadId();
2267 *restrict metacontent;
2269 assert(image != (const Image *) NULL);
2270 assert(image->signature == MagickSignature);
2271 assert(image->cache != (Cache) NULL);
2272 cache_info=(CacheInfo *) image->cache;
2273 assert(cache_info->signature == MagickSignature);
2274 assert(id < (int) cache_info->number_threads);
2275 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2276 cache_info->nexus_info[id]);
2277 return(metacontent);
2281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285 + 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 %
2289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2291 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2294 % The format of the GetVirtualMetacontentFromNexus() method is:
2296 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2297 % NexusInfo *nexus_info)
2299 % A description of each parameter follows:
2301 % o cache: the pixel cache.
2303 % o nexus_info: the cache nexus to return the meta-content.
2306 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2307 NexusInfo *restrict nexus_info)
2310 *restrict cache_info;
2312 assert(cache != (Cache) NULL);
2313 cache_info=(CacheInfo *) cache;
2314 assert(cache_info->signature == MagickSignature);
2315 if (cache_info->storage_class == UndefinedClass)
2316 return((void *) NULL);
2317 return(nexus_info->metacontent);
2321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2325 % G e t V i r t u a l M e t a c o n t e n t %
2329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2331 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2332 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2333 % returned if the meta-content are not available.
2335 % The format of the GetVirtualMetacontent() method is:
2337 % const void *GetVirtualMetacontent(const Image *image)
2339 % A description of each parameter follows:
2341 % o image: the image.
2344 MagickExport const void *GetVirtualMetacontent(const Image *image)
2347 *restrict cache_info;
2350 id = GetOpenMPThreadId();
2353 *restrict metacontent;
2355 assert(image != (const Image *) NULL);
2356 assert(image->signature == MagickSignature);
2357 assert(image->cache != (Cache) NULL);
2358 cache_info=(CacheInfo *) image->cache;
2359 assert(cache_info->signature == MagickSignature);
2360 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2361 if (metacontent != (void *) NULL)
2362 return(metacontent);
2363 assert(id < (int) cache_info->number_threads);
2364 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2365 cache_info->nexus_info[id]);
2366 return(metacontent);
2370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2374 + 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 %
2378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2381 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2382 % is returned if the pixels are transferred, otherwise a NULL is returned.
2384 % The format of the GetVirtualPixelsFromNexus() method is:
2386 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2387 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2388 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2389 % ExceptionInfo *exception)
2391 % A description of each parameter follows:
2393 % o image: the image.
2395 % o virtual_pixel_method: the virtual pixel method.
2397 % o x,y,columns,rows: These values define the perimeter of a region of
2400 % o nexus_info: the cache nexus to acquire.
2402 % o exception: return any errors or warnings in this structure.
2409 0, 48, 12, 60, 3, 51, 15, 63,
2410 32, 16, 44, 28, 35, 19, 47, 31,
2411 8, 56, 4, 52, 11, 59, 7, 55,
2412 40, 24, 36, 20, 43, 27, 39, 23,
2413 2, 50, 14, 62, 1, 49, 13, 61,
2414 34, 18, 46, 30, 33, 17, 45, 29,
2415 10, 58, 6, 54, 9, 57, 5, 53,
2416 42, 26, 38, 22, 41, 25, 37, 21
2419 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2424 index=x+DitherMatrix[x & 0x07]-32L;
2427 if (index >= (ssize_t) columns)
2428 return((ssize_t) columns-1L);
2432 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2437 index=y+DitherMatrix[y & 0x07]-32L;
2440 if (index >= (ssize_t) rows)
2441 return((ssize_t) rows-1L);
2445 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2449 if (x >= (ssize_t) columns)
2450 return((ssize_t) (columns-1));
2454 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2458 if (y >= (ssize_t) rows)
2459 return((ssize_t) (rows-1));
2463 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2465 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2468 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2470 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2473 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2474 const size_t extent)
2480 Compute the remainder of dividing offset by extent. It returns not only
2481 the quotient (tile the offset falls in) but also the positive remainer
2482 within that tile such that 0 <= remainder < extent. This method is
2483 essentially a ldiv() using a floored modulo division rather than the
2484 normal default truncated modulo division.
2486 modulo.quotient=offset/(ssize_t) extent;
2489 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2493 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2494 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2495 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2496 ExceptionInfo *exception)
2499 *restrict cache_info;
2509 **restrict virtual_nexus;
2513 virtual_pixel[MaxPixelChannels];
2518 register const Quantum
2531 register unsigned char
2538 *restrict virtual_metacontent;
2543 assert(image != (const Image *) NULL);
2544 assert(image->signature == MagickSignature);
2545 assert(image->cache != (Cache) NULL);
2546 cache_info=(CacheInfo *) image->cache;
2547 assert(cache_info->signature == MagickSignature);
2548 if (cache_info->type == UndefinedCache)
2549 return((const Quantum *) NULL);
2552 region.width=columns;
2554 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2556 if (pixels == (Quantum *) NULL)
2557 return((const Quantum *) NULL);
2559 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2560 nexus_info->region.x;
2561 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2562 nexus_info->region.width-1L;
2563 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2564 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2565 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2566 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2572 Pixel request is inside cache extents.
2574 if (nexus_info->authentic_pixel_cache != MagickFalse)
2576 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2577 if (status == MagickFalse)
2578 return((const Quantum *) NULL);
2579 if (cache_info->metacontent_extent != 0)
2581 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2582 if (status == MagickFalse)
2583 return((const Quantum *) NULL);
2588 Pixel request is outside cache extents.
2590 s=(unsigned char *) nexus_info->metacontent;
2591 virtual_nexus=AcquirePixelCacheNexus(1);
2592 if (virtual_nexus == (NexusInfo **) NULL)
2594 if (virtual_nexus != (NexusInfo **) NULL)
2595 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2596 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2597 "UnableToGetCacheNexus","`%s'",image->filename);
2598 return((const Quantum *) NULL);
2600 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2601 sizeof(*virtual_pixel));
2602 virtual_metacontent=(void *) NULL;
2603 switch (virtual_pixel_method)
2605 case BackgroundVirtualPixelMethod:
2606 case BlackVirtualPixelMethod:
2607 case GrayVirtualPixelMethod:
2608 case TransparentVirtualPixelMethod:
2609 case MaskVirtualPixelMethod:
2610 case WhiteVirtualPixelMethod:
2611 case EdgeVirtualPixelMethod:
2612 case CheckerTileVirtualPixelMethod:
2613 case HorizontalTileVirtualPixelMethod:
2614 case VerticalTileVirtualPixelMethod:
2616 if (cache_info->metacontent_extent != 0)
2619 Acquire a metacontent buffer.
2621 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2622 cache_info->metacontent_extent);
2623 if (virtual_metacontent == (void *) NULL)
2625 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2626 (void) ThrowMagickException(exception,GetMagickModule(),
2627 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2628 return((const Quantum *) NULL);
2630 (void) ResetMagickMemory(virtual_metacontent,0,
2631 cache_info->metacontent_extent);
2633 switch (virtual_pixel_method)
2635 case BlackVirtualPixelMethod:
2637 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2638 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2639 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2642 case GrayVirtualPixelMethod:
2644 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2645 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2647 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2650 case TransparentVirtualPixelMethod:
2652 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2653 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2654 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2657 case MaskVirtualPixelMethod:
2658 case WhiteVirtualPixelMethod:
2660 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2661 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2662 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2667 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2669 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2671 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2673 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2675 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2685 for (v=0; v < (ssize_t) rows; v++)
2691 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2692 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2693 y_offset=EdgeY(y_offset,cache_info->rows);
2694 for (u=0; u < (ssize_t) columns; u+=length)
2700 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2701 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2702 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2710 Transfer a single pixel.
2712 length=(MagickSizeType) 1;
2713 switch (virtual_pixel_method)
2715 case EdgeVirtualPixelMethod:
2718 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2719 EdgeX(x_offset,cache_info->columns),
2720 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2722 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2725 case RandomVirtualPixelMethod:
2727 if (cache_info->random_info == (RandomInfo *) NULL)
2728 cache_info->random_info=AcquireRandomInfo();
2729 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2730 RandomX(cache_info->random_info,cache_info->columns),
2731 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2732 *virtual_nexus,exception);
2733 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2736 case DitherVirtualPixelMethod:
2738 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2739 DitherX(x_offset,cache_info->columns),
2740 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2742 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2745 case TileVirtualPixelMethod:
2747 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2748 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2749 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2750 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2752 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2755 case MirrorVirtualPixelMethod:
2757 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2758 if ((x_modulo.quotient & 0x01) == 1L)
2759 x_modulo.remainder=(ssize_t) cache_info->columns-
2760 x_modulo.remainder-1L;
2761 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2762 if ((y_modulo.quotient & 0x01) == 1L)
2763 y_modulo.remainder=(ssize_t) cache_info->rows-
2764 y_modulo.remainder-1L;
2765 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2766 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2768 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2771 case HorizontalTileEdgeVirtualPixelMethod:
2773 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2774 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2775 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2776 *virtual_nexus,exception);
2777 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2780 case VerticalTileEdgeVirtualPixelMethod:
2782 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2783 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2784 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2785 *virtual_nexus,exception);
2786 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2789 case BackgroundVirtualPixelMethod:
2790 case BlackVirtualPixelMethod:
2791 case GrayVirtualPixelMethod:
2792 case TransparentVirtualPixelMethod:
2793 case MaskVirtualPixelMethod:
2794 case WhiteVirtualPixelMethod:
2797 r=virtual_metacontent;
2800 case CheckerTileVirtualPixelMethod:
2802 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2803 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2804 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2807 r=virtual_metacontent;
2810 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2811 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2813 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2816 case HorizontalTileVirtualPixelMethod:
2818 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2821 r=virtual_metacontent;
2824 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2825 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2826 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2827 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2829 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2832 case VerticalTileVirtualPixelMethod:
2834 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2837 r=virtual_metacontent;
2840 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2841 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2842 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2843 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2845 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2849 if (p == (const Quantum *) NULL)
2851 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2853 q+=cache_info->number_channels;
2854 if ((s != (void *) NULL) && (r != (const void *) NULL))
2856 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2857 s+=cache_info->metacontent_extent;
2862 Transfer a run of pixels.
2864 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2865 (size_t) length,1UL,*virtual_nexus,exception);
2866 if (p == (const Quantum *) NULL)
2868 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2869 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2870 q+=length*cache_info->number_channels;
2871 if ((r != (void *) NULL) && (s != (const void *) NULL))
2873 (void) memcpy(s,r,(size_t) length);
2874 s+=length*cache_info->metacontent_extent;
2881 if (virtual_metacontent != (void *) NULL)
2882 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2883 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892 + G e t V i r t u a l P i x e l C a c h e %
2896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2898 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2899 % cache as defined by the geometry parameters. A pointer to the pixels
2900 % is returned if the pixels are transferred, otherwise a NULL is returned.
2902 % The format of the GetVirtualPixelCache() method is:
2904 % const Quantum *GetVirtualPixelCache(const Image *image,
2905 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2906 % const ssize_t y,const size_t columns,const size_t rows,
2907 % ExceptionInfo *exception)
2909 % A description of each parameter follows:
2911 % o image: the image.
2913 % o virtual_pixel_method: the virtual pixel method.
2915 % o x,y,columns,rows: These values define the perimeter of a region of
2918 % o exception: return any errors or warnings in this structure.
2921 static const Quantum *GetVirtualPixelCache(const Image *image,
2922 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2923 const size_t columns,const size_t rows,ExceptionInfo *exception)
2926 *restrict cache_info;
2929 id = GetOpenMPThreadId();
2934 assert(image != (const Image *) NULL);
2935 assert(image->signature == MagickSignature);
2936 assert(image->cache != (Cache) NULL);
2937 cache_info=(CacheInfo *) image->cache;
2938 assert(cache_info->signature == MagickSignature);
2939 assert(id < (int) cache_info->number_threads);
2940 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2941 cache_info->nexus_info[id],exception);
2946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2950 % G e t V i r t u a l P i x e l Q u e u e %
2954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2956 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2957 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2959 % The format of the GetVirtualPixelQueue() method is:
2961 % const Quantum *GetVirtualPixelQueue(const Image image)
2963 % A description of each parameter follows:
2965 % o image: the image.
2968 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2971 *restrict cache_info;
2974 id = GetOpenMPThreadId();
2976 assert(image != (const Image *) NULL);
2977 assert(image->signature == MagickSignature);
2978 assert(image->cache != (Cache) NULL);
2979 cache_info=(CacheInfo *) image->cache;
2980 assert(cache_info->signature == MagickSignature);
2981 if (cache_info->methods.get_virtual_pixels_handler !=
2982 (GetVirtualPixelsHandler) NULL)
2983 return(cache_info->methods.get_virtual_pixels_handler(image));
2984 assert(id < (int) cache_info->number_threads);
2985 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2993 % G e t V i r t u a l P i x e l s %
2997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2999 % GetVirtualPixels() returns an immutable pixel region. If the
3000 % region is successfully accessed, a pointer to it is returned, otherwise
3001 % NULL is returned. The returned pointer may point to a temporary working
3002 % copy of the pixels or it may point to the original pixels in memory.
3003 % Performance is maximized if the selected region is part of one row, or one
3004 % or more full rows, since there is opportunity to access the pixels in-place
3005 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3006 % returned pointer must *never* be deallocated by the user.
3008 % Pixels accessed via the returned pointer represent a simple array of type
3009 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3010 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3011 % access the meta-content (of type void) corresponding to the the
3014 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3016 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3017 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3018 % GetCacheViewAuthenticPixels() instead.
3020 % The format of the GetVirtualPixels() method is:
3022 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3023 % const ssize_t y,const size_t columns,const size_t rows,
3024 % ExceptionInfo *exception)
3026 % A description of each parameter follows:
3028 % o image: the image.
3030 % o x,y,columns,rows: These values define the perimeter of a region of
3033 % o exception: return any errors or warnings in this structure.
3036 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3037 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3038 ExceptionInfo *exception)
3041 *restrict cache_info;
3044 id = GetOpenMPThreadId();
3049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
3051 assert(image->cache != (Cache) NULL);
3052 cache_info=(CacheInfo *) image->cache;
3053 assert(cache_info->signature == MagickSignature);
3054 if (cache_info->methods.get_virtual_pixel_handler !=
3055 (GetVirtualPixelHandler) NULL)
3056 return(cache_info->methods.get_virtual_pixel_handler(image,
3057 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3058 assert(id < (int) cache_info->number_threads);
3059 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3060 columns,rows,cache_info->nexus_info[id],exception);
3065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3069 + 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 %
3073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3075 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3076 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3078 % The format of the GetVirtualPixelsCache() method is:
3080 % Quantum *GetVirtualPixelsCache(const Image *image)
3082 % A description of each parameter follows:
3084 % o image: the image.
3087 static const Quantum *GetVirtualPixelsCache(const Image *image)
3090 *restrict cache_info;
3093 id = GetOpenMPThreadId();
3095 assert(image != (const Image *) NULL);
3096 assert(image->signature == MagickSignature);
3097 assert(image->cache != (Cache) NULL);
3098 cache_info=(CacheInfo *) image->cache;
3099 assert(cache_info->signature == MagickSignature);
3100 assert(id < (int) cache_info->number_threads);
3101 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3109 + G e t V i r t u a l P i x e l s N e x u s %
3113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3115 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3118 % The format of the GetVirtualPixelsNexus() method is:
3120 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3121 % NexusInfo *nexus_info)
3123 % A description of each parameter follows:
3125 % o cache: the pixel cache.
3127 % o nexus_info: the cache nexus to return the colormap pixels.
3130 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3131 NexusInfo *restrict nexus_info)
3134 *restrict cache_info;
3136 assert(cache != (Cache) NULL);
3137 cache_info=(CacheInfo *) cache;
3138 assert(cache_info->signature == MagickSignature);
3139 if (cache_info->storage_class == UndefinedClass)
3140 return((Quantum *) NULL);
3141 return((const Quantum *) nexus_info->pixels);
3145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3149 + O p e n P i x e l C a c h e %
3153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3155 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3156 % dimensions, allocating space for the image pixels and optionally the
3157 % metacontent, and memory mapping the cache if it is disk based. The cache
3158 % nexus array is initialized as well.
3160 % The format of the OpenPixelCache() method is:
3162 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3163 % ExceptionInfo *exception)
3165 % A description of each parameter follows:
3167 % o image: the image.
3169 % o mode: ReadMode, WriteMode, or IOMode.
3171 % o exception: return any errors or warnings in this structure.
3175 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3177 cache_info->mapped=MagickFalse;
3178 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3179 (size_t) cache_info->length));
3180 if (cache_info->pixels == (Quantum *) NULL)
3182 cache_info->mapped=MagickTrue;
3183 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3184 cache_info->length);
3188 #if defined(__cplusplus) || defined(c_plusplus)
3193 static void CacheSignalHandler(int status)
3195 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3199 #if defined(__cplusplus) || defined(c_plusplus)
3203 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3210 Open pixel cache on disk.
3212 if (cache_info->file != -1)
3213 return(MagickTrue); /* cache already open */
3214 if (*cache_info->cache_filename == '\0')
3215 file=AcquireUniqueFileResource(cache_info->cache_filename);
3221 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3226 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3227 O_BINARY | O_EXCL,S_MODE);
3229 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3235 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3238 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3243 return(MagickFalse);
3244 (void) AcquireMagickResource(FileResource,1);
3245 cache_info->file=file;
3246 cache_info->mode=mode;
3250 static inline MagickOffsetType WritePixelCacheRegion(
3251 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3252 const MagickSizeType length,const unsigned char *restrict buffer)
3254 register MagickOffsetType
3260 #if !defined(MAGICKCORE_HAVE_PWRITE)
3261 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3262 return((MagickOffsetType) -1);
3265 for (i=0; i < (MagickOffsetType) length; i+=count)
3267 #if !defined(MAGICKCORE_HAVE_PWRITE)
3268 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3269 (MagickSizeType) SSIZE_MAX));
3271 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3272 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3284 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3287 *restrict cache_info;
3294 cache_info=(CacheInfo *) image->cache;
3295 if (image->debug != MagickFalse)
3298 format[MaxTextExtent],
3299 message[MaxTextExtent];
3301 (void) FormatMagickSize(length,MagickFalse,format);
3302 (void) FormatLocaleString(message,MaxTextExtent,
3303 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3304 cache_info->cache_filename,cache_info->file,format);
3305 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3307 if (length != (MagickSizeType) ((MagickOffsetType) length))
3308 return(MagickFalse);
3309 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3311 return(MagickFalse);
3312 if ((MagickSizeType) offset >= length)
3314 extent=(MagickOffsetType) length-1;
3315 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3316 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3317 if (cache_info->synchronize != MagickFalse)
3322 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3324 return(MagickFalse);
3328 (void) signal(SIGBUS,CacheSignalHandler);
3330 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3333 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3334 ExceptionInfo *exception)
3337 *restrict cache_info,
3341 format[MaxTextExtent],
3342 message[MaxTextExtent];
3358 assert(image != (const Image *) NULL);
3359 assert(image->signature == MagickSignature);
3360 assert(image->cache != (Cache) NULL);
3361 if (image->debug != MagickFalse)
3362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3363 if ((image->columns == 0) || (image->rows == 0))
3364 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3365 cache_info=(CacheInfo *) image->cache;
3366 assert(cache_info->signature == MagickSignature);
3367 source_info=(*cache_info);
3368 source_info.file=(-1);
3369 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3370 image->filename,(double) GetImageIndexInList(image));
3371 cache_info->storage_class=image->storage_class;
3372 cache_info->colorspace=image->colorspace;
3373 cache_info->alpha_trait=image->alpha_trait;
3374 cache_info->read_mask=image->read_mask;
3375 cache_info->write_mask=image->write_mask;
3376 cache_info->rows=image->rows;
3377 cache_info->columns=image->columns;
3378 InitializePixelChannelMap(image);
3379 cache_info->number_channels=GetPixelChannels(image);
3380 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3381 sizeof(*image->channel_map));
3382 cache_info->metacontent_extent=image->metacontent_extent;
3383 cache_info->mode=mode;
3384 if (image->ping != MagickFalse)
3386 cache_info->type=PingCache;
3387 cache_info->pixels=(Quantum *) NULL;
3388 cache_info->metacontent=(void *) NULL;
3389 cache_info->length=0;
3392 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3393 packet_size=cache_info->number_channels*sizeof(Quantum);
3394 if (image->metacontent_extent != 0)
3395 packet_size+=cache_info->metacontent_extent;
3396 length=number_pixels*packet_size;
3397 columns=(size_t) (length/cache_info->rows/packet_size);
3398 if (cache_info->columns != columns)
3399 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3401 cache_info->length=length;
3402 status=AcquireMagickResource(AreaResource,cache_info->length);
3403 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3404 cache_info->metacontent_extent);
3405 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3407 status=AcquireMagickResource(MemoryResource,cache_info->length);
3408 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3409 (cache_info->type == MemoryCache))
3411 AllocatePixelCachePixels(cache_info);
3412 if (cache_info->pixels == (Quantum *) NULL)
3413 cache_info->pixels=source_info.pixels;
3417 Create memory pixel cache.
3420 cache_info->type=MemoryCache;
3421 cache_info->metacontent=(void *) NULL;
3422 if (cache_info->metacontent_extent != 0)
3423 cache_info->metacontent=(void *) (cache_info->pixels+
3424 number_pixels*cache_info->number_channels);
3425 if ((source_info.storage_class != UndefinedClass) &&
3428 status=ClonePixelCacheRepository(cache_info,&source_info,
3430 RelinquishPixelCachePixels(&source_info);
3432 if (image->debug != MagickFalse)
3434 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3435 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3437 (void) FormatLocaleString(message,MaxTextExtent,
3438 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3439 cache_info->filename,cache_info->mapped != MagickFalse ?
3440 "Anonymous" : "Heap",type,(double) cache_info->columns,
3441 (double) cache_info->rows,(double)
3442 cache_info->number_channels,format);
3443 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3449 RelinquishMagickResource(MemoryResource,cache_info->length);
3452 Create pixel cache on disk.
3454 status=AcquireMagickResource(DiskResource,cache_info->length);
3455 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3460 if (cache_info->type == DistributedCache)
3461 RelinquishMagickResource(DiskResource,cache_info->length);
3462 server_info=AcquireDistributeCacheInfo(exception);
3463 if (server_info != (DistributeCacheInfo *) NULL)
3465 status=OpenDistributePixelCache(server_info,image);
3466 if (status == MagickFalse)
3468 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3469 GetDistributeCacheHostname(server_info));
3470 server_info=DestroyDistributeCacheInfo(server_info);
3475 Create a distributed pixel cache.
3477 cache_info->type=DistributedCache;
3478 cache_info->server_info=server_info;
3479 (void) FormatLocaleString(cache_info->cache_filename,
3480 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3481 (DistributeCacheInfo *) cache_info->server_info),
3482 GetDistributeCachePort((DistributeCacheInfo *)
3483 cache_info->server_info));
3484 if ((source_info.storage_class != UndefinedClass) &&
3487 status=ClonePixelCacheRepository(cache_info,&source_info,
3489 RelinquishPixelCachePixels(&source_info);
3491 if (image->debug != MagickFalse)
3493 (void) FormatMagickSize(cache_info->length,MagickFalse,
3495 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3497 (void) FormatLocaleString(message,MaxTextExtent,
3498 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3499 cache_info->filename,cache_info->cache_filename,
3500 GetDistributeCacheFile((DistributeCacheInfo *)
3501 cache_info->server_info),type,(double) cache_info->columns,
3502 (double) cache_info->rows,(double)
3503 cache_info->number_channels,format);
3504 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3510 RelinquishMagickResource(DiskResource,cache_info->length);
3511 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3512 "CacheResourcesExhausted","`%s'",image->filename);
3513 return(MagickFalse);
3515 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3517 (void) ClosePixelCacheOnDisk(cache_info);
3518 *cache_info->cache_filename='\0';
3520 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3522 RelinquishMagickResource(DiskResource,cache_info->length);
3523 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3525 return(MagickFalse);
3527 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3528 cache_info->length);
3529 if (status == MagickFalse)
3531 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3533 return(MagickFalse);
3535 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3536 cache_info->metacontent_extent);
3537 if (length != (MagickSizeType) ((size_t) length))
3538 cache_info->type=DiskCache;
3541 status=AcquireMagickResource(MapResource,cache_info->length);
3542 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3543 (cache_info->type != MemoryCache))
3544 cache_info->type=DiskCache;
3547 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3548 cache_info->offset,(size_t) cache_info->length);
3549 if (cache_info->pixels == (Quantum *) NULL)
3551 cache_info->type=DiskCache;
3552 cache_info->pixels=source_info.pixels;
3557 Create file-backed memory-mapped pixel cache.
3560 (void) ClosePixelCacheOnDisk(cache_info);
3561 cache_info->type=MapCache;
3562 cache_info->mapped=MagickTrue;
3563 cache_info->metacontent=(void *) NULL;
3564 if (cache_info->metacontent_extent != 0)
3565 cache_info->metacontent=(void *) (cache_info->pixels+
3566 number_pixels*cache_info->number_channels);
3567 if ((source_info.storage_class != UndefinedClass) &&
3570 status=ClonePixelCacheRepository(cache_info,&source_info,
3572 RelinquishPixelCachePixels(&source_info);
3574 if (image->debug != MagickFalse)
3576 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3577 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3579 (void) FormatLocaleString(message,MaxTextExtent,
3580 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3581 cache_info->filename,cache_info->cache_filename,
3582 cache_info->file,type,(double) cache_info->columns,(double)
3583 cache_info->rows,(double) cache_info->number_channels,
3585 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3591 RelinquishMagickResource(MapResource,cache_info->length);
3594 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3596 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3597 RelinquishPixelCachePixels(&source_info);
3599 if (image->debug != MagickFalse)
3601 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3602 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3604 (void) FormatLocaleString(message,MaxTextExtent,
3605 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3606 cache_info->cache_filename,cache_info->file,type,(double)
3607 cache_info->columns,(double) cache_info->rows,(double)
3608 cache_info->number_channels,format);
3609 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3619 + P e r s i s t P i x e l C a c h e %
3623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3625 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3626 % persistent pixel cache is one that resides on disk and is not destroyed
3627 % when the program exits.
3629 % The format of the PersistPixelCache() method is:
3631 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3632 % const MagickBooleanType attach,MagickOffsetType *offset,
3633 % ExceptionInfo *exception)
3635 % A description of each parameter follows:
3637 % o image: the image.
3639 % o filename: the persistent pixel cache filename.
3641 % o attach: A value other than zero initializes the persistent pixel cache.
3643 % o initialize: A value other than zero initializes the persistent pixel
3646 % o offset: the offset in the persistent cache to store pixels.
3648 % o exception: return any errors or warnings in this structure.
3651 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3652 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3653 ExceptionInfo *exception)
3656 *restrict cache_info,
3657 *restrict clone_info;
3668 assert(image != (Image *) NULL);
3669 assert(image->signature == MagickSignature);
3670 if (image->debug != MagickFalse)
3671 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3672 assert(image->cache != (void *) NULL);
3673 assert(filename != (const char *) NULL);
3674 assert(offset != (MagickOffsetType *) NULL);
3675 page_size=GetMagickPageSize();
3676 cache_info=(CacheInfo *) image->cache;
3677 assert(cache_info->signature == MagickSignature);
3678 if (attach != MagickFalse)
3681 Attach existing persistent pixel cache.
3683 if (image->debug != MagickFalse)
3684 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3685 "attach persistent cache");
3686 (void) CopyMagickString(cache_info->cache_filename,filename,
3688 cache_info->type=DiskCache;
3689 cache_info->offset=(*offset);
3690 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3691 return(MagickFalse);
3692 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3695 if ((cache_info->mode != ReadMode) &&
3696 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3697 (cache_info->reference_count == 1))
3699 LockSemaphoreInfo(cache_info->semaphore);
3700 if ((cache_info->mode != ReadMode) &&
3701 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3702 (cache_info->reference_count == 1))
3708 Usurp existing persistent pixel cache.
3710 status=rename_utf8(cache_info->cache_filename,filename);
3713 (void) CopyMagickString(cache_info->cache_filename,filename,
3715 *offset+=cache_info->length+page_size-(cache_info->length %
3717 UnlockSemaphoreInfo(cache_info->semaphore);
3718 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3719 if (image->debug != MagickFalse)
3720 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3721 "Usurp resident persistent cache");
3725 UnlockSemaphoreInfo(cache_info->semaphore);
3728 Clone persistent pixel cache.
3730 clone_image=(*image);
3731 clone_info=(CacheInfo *) clone_image.cache;
3732 image->cache=ClonePixelCache(cache_info);
3733 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3734 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3735 cache_info->type=DiskCache;
3736 cache_info->offset=(*offset);
3737 cache_info=(CacheInfo *) image->cache;
3738 status=OpenPixelCache(image,IOMode,exception);
3739 if (status != MagickFalse)
3740 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3741 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3742 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3751 + 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 %
3755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3757 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3758 % defined by the region rectangle and returns a pointer to the region. This
3759 % region is subsequently transferred from the pixel cache with
3760 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3761 % pixels are transferred, otherwise a NULL is returned.
3763 % The format of the QueueAuthenticPixelCacheNexus() method is:
3765 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3766 % const ssize_t y,const size_t columns,const size_t rows,
3767 % const MagickBooleanType clone,NexusInfo *nexus_info,
3768 % ExceptionInfo *exception)
3770 % A description of each parameter follows:
3772 % o image: the image.
3774 % o x,y,columns,rows: These values define the perimeter of a region of
3777 % o nexus_info: the cache nexus to set.
3779 % o clone: clone the pixel cache.
3781 % o exception: return any errors or warnings in this structure.
3784 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3785 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3786 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3789 *restrict cache_info;
3804 Validate pixel cache geometry.
3806 assert(image != (const Image *) NULL);
3807 assert(image->signature == MagickSignature);
3808 assert(image->cache != (Cache) NULL);
3809 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3810 if (cache_info == (Cache) NULL)
3811 return((Quantum *) NULL);
3812 assert(cache_info->signature == MagickSignature);
3813 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3814 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3815 (y >= (ssize_t) cache_info->rows))
3817 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3818 "PixelsAreNotAuthentic","`%s'",image->filename);
3819 return((Quantum *) NULL);
3821 offset=(MagickOffsetType) y*cache_info->columns+x;
3823 return((Quantum *) NULL);
3824 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3825 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3826 if ((MagickSizeType) offset >= number_pixels)
3827 return((Quantum *) NULL);
3833 region.width=columns;
3835 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3845 + 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 %
3849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3851 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3852 % defined by the region rectangle and returns a pointer to the region. This
3853 % region is subsequently transferred from the pixel cache with
3854 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3855 % pixels are transferred, otherwise a NULL is returned.
3857 % The format of the QueueAuthenticPixelsCache() method is:
3859 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3860 % const ssize_t y,const size_t columns,const size_t rows,
3861 % ExceptionInfo *exception)
3863 % A description of each parameter follows:
3865 % o image: the image.
3867 % o x,y,columns,rows: These values define the perimeter of a region of
3870 % o exception: return any errors or warnings in this structure.
3873 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3874 const ssize_t y,const size_t columns,const size_t rows,
3875 ExceptionInfo *exception)
3878 *restrict cache_info;
3881 id = GetOpenMPThreadId();
3886 assert(image != (const Image *) NULL);
3887 assert(image->signature == MagickSignature);
3888 assert(image->cache != (Cache) NULL);
3889 cache_info=(CacheInfo *) image->cache;
3890 assert(cache_info->signature == MagickSignature);
3891 assert(id < (int) cache_info->number_threads);
3892 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3893 cache_info->nexus_info[id],exception);
3898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3902 % Q u e u e A u t h e n t i c P i x e l s %
3906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3908 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3909 % successfully initialized a pointer to a Quantum array representing the
3910 % region is returned, otherwise NULL is returned. The returned pointer may
3911 % point to a temporary working buffer for the pixels or it may point to the
3912 % final location of the pixels in memory.
3914 % Write-only access means that any existing pixel values corresponding to
3915 % the region are ignored. This is useful if the initial image is being
3916 % created from scratch, or if the existing pixel values are to be
3917 % completely replaced without need to refer to their pre-existing values.
3918 % The application is free to read and write the pixel buffer returned by
3919 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3920 % initialize the pixel array values. Initializing pixel array values is the
3921 % application's responsibility.
3923 % Performance is maximized if the selected region is part of one row, or
3924 % one or more full rows, since then there is opportunity to access the
3925 % pixels in-place (without a copy) if the image is in memory, or in a
3926 % memory-mapped file. The returned pointer must *never* be deallocated
3929 % Pixels accessed via the returned pointer represent a simple array of type
3930 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3931 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3932 % obtain the meta-content (of type void) corresponding to the region.
3933 % Once the Quantum (and/or Quantum) array has been updated, the
3934 % changes must be saved back to the underlying image using
3935 % SyncAuthenticPixels() or they may be lost.
3937 % The format of the QueueAuthenticPixels() method is:
3939 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3940 % const ssize_t y,const size_t columns,const size_t rows,
3941 % ExceptionInfo *exception)
3943 % A description of each parameter follows:
3945 % o image: the image.
3947 % o x,y,columns,rows: These values define the perimeter of a region of
3950 % o exception: return any errors or warnings in this structure.
3953 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3954 const ssize_t y,const size_t columns,const size_t rows,
3955 ExceptionInfo *exception)
3958 *restrict cache_info;
3961 id = GetOpenMPThreadId();
3966 assert(image != (Image *) NULL);
3967 assert(image->signature == MagickSignature);
3968 assert(image->cache != (Cache) NULL);
3969 cache_info=(CacheInfo *) image->cache;
3970 assert(cache_info->signature == MagickSignature);
3971 if (cache_info->methods.queue_authentic_pixels_handler !=
3972 (QueueAuthenticPixelsHandler) NULL)
3974 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3975 columns,rows,exception);
3978 assert(id < (int) cache_info->number_threads);
3979 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3980 cache_info->nexus_info[id],exception);
3985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3989 + 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 %
3993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3995 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3998 % The format of the ReadPixelCacheMetacontent() method is:
4000 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4001 % NexusInfo *nexus_info,ExceptionInfo *exception)
4003 % A description of each parameter follows:
4005 % o cache_info: the pixel cache.
4007 % o nexus_info: the cache nexus to read the metacontent.
4009 % o exception: return any errors or warnings in this structure.
4013 static inline MagickOffsetType ReadPixelCacheRegion(
4014 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4015 const MagickSizeType length,unsigned char *restrict buffer)
4017 register MagickOffsetType
4023 #if !defined(MAGICKCORE_HAVE_PREAD)
4024 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4025 return((MagickOffsetType) -1);
4028 for (i=0; i < (MagickOffsetType) length; i+=count)
4030 #if !defined(MAGICKCORE_HAVE_PREAD)
4031 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4032 (MagickSizeType) SSIZE_MAX));
4034 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4035 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4047 static MagickBooleanType ReadPixelCacheMetacontent(
4048 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4049 ExceptionInfo *exception)
4062 register unsigned char
4068 if (cache_info->metacontent_extent == 0)
4069 return(MagickFalse);
4070 if (nexus_info->authentic_pixel_cache != MagickFalse)
4072 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4073 nexus_info->region.x;
4074 length=(MagickSizeType) nexus_info->region.width*
4075 cache_info->metacontent_extent;
4076 extent=length*nexus_info->region.height;
4077 rows=nexus_info->region.height;
4079 q=(unsigned char *) nexus_info->metacontent;
4080 switch (cache_info->type)
4085 register unsigned char
4089 Read meta-content from memory.
4091 if ((cache_info->columns == nexus_info->region.width) &&
4092 (extent == (MagickSizeType) ((size_t) extent)))
4097 p=(unsigned char *) cache_info->metacontent+offset*
4098 cache_info->metacontent_extent;
4099 for (y=0; y < (ssize_t) rows; y++)
4101 (void) memcpy(q,p,(size_t) length);
4102 p+=cache_info->metacontent_extent*cache_info->columns;
4103 q+=cache_info->metacontent_extent*nexus_info->region.width;
4110 Read meta content from disk.
4112 LockSemaphoreInfo(cache_info->file_semaphore);
4113 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4115 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4116 cache_info->cache_filename);
4117 UnlockSemaphoreInfo(cache_info->file_semaphore);
4118 return(MagickFalse);
4120 if ((cache_info->columns == nexus_info->region.width) &&
4121 (extent <= MagickMaxBufferExtent))
4126 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4127 for (y=0; y < (ssize_t) rows; y++)
4129 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4130 cache_info->number_channels*sizeof(Quantum)+offset*
4131 cache_info->metacontent_extent,length,(unsigned char *) q);
4132 if (count != (MagickOffsetType) length)
4134 offset+=cache_info->columns;
4135 q+=cache_info->metacontent_extent*nexus_info->region.width;
4137 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4138 (void) ClosePixelCacheOnDisk(cache_info);
4139 UnlockSemaphoreInfo(cache_info->file_semaphore);
4142 case DistributedCache:
4148 Read metacontent from distributed cache.
4150 LockSemaphoreInfo(cache_info->file_semaphore);
4151 region=nexus_info->region;
4152 if ((cache_info->columns != nexus_info->region.width) ||
4153 (extent > MagickMaxBufferExtent))
4160 for (y=0; y < (ssize_t) rows; y++)
4162 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4163 cache_info->server_info,®ion,length,(unsigned char *) q);
4164 if (count != (MagickOffsetType) length)
4166 q+=cache_info->metacontent_extent*nexus_info->region.width;
4169 UnlockSemaphoreInfo(cache_info->file_semaphore);
4175 if (y < (ssize_t) rows)
4177 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4178 cache_info->cache_filename);
4179 return(MagickFalse);
4181 if ((cache_info->debug != MagickFalse) &&
4182 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4183 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4184 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4185 nexus_info->region.width,(double) nexus_info->region.height,(double)
4186 nexus_info->region.x,(double) nexus_info->region.y);
4191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4195 + R e a d P i x e l C a c h e P i x e l s %
4199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4201 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4204 % The format of the ReadPixelCachePixels() method is:
4206 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4207 % NexusInfo *nexus_info,ExceptionInfo *exception)
4209 % A description of each parameter follows:
4211 % o cache_info: the pixel cache.
4213 % o nexus_info: the cache nexus to read the pixels.
4215 % o exception: return any errors or warnings in this structure.
4218 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4219 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4238 if (nexus_info->authentic_pixel_cache != MagickFalse)
4240 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4241 nexus_info->region.x;
4242 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4244 extent=length*nexus_info->region.height;
4245 rows=nexus_info->region.height;
4247 q=nexus_info->pixels;
4248 switch (cache_info->type)
4257 Read pixels from memory.
4259 if ((cache_info->columns == nexus_info->region.width) &&
4260 (extent == (MagickSizeType) ((size_t) extent)))
4265 p=cache_info->pixels+offset*cache_info->number_channels;
4266 for (y=0; y < (ssize_t) rows; y++)
4268 (void) memcpy(q,p,(size_t) length);
4269 p+=cache_info->number_channels*cache_info->columns;
4270 q+=cache_info->number_channels*nexus_info->region.width;
4277 Read pixels from disk.
4279 LockSemaphoreInfo(cache_info->file_semaphore);
4280 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4282 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4283 cache_info->cache_filename);
4284 UnlockSemaphoreInfo(cache_info->file_semaphore);
4285 return(MagickFalse);
4287 if ((cache_info->columns == nexus_info->region.width) &&
4288 (extent <= MagickMaxBufferExtent))
4293 for (y=0; y < (ssize_t) rows; y++)
4295 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4296 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4297 if (count != (MagickOffsetType) length)
4299 offset+=cache_info->columns;
4300 q+=cache_info->number_channels*nexus_info->region.width;
4302 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4303 (void) ClosePixelCacheOnDisk(cache_info);
4304 UnlockSemaphoreInfo(cache_info->file_semaphore);
4307 case DistributedCache:
4313 Read pixels from distributed cache.
4315 LockSemaphoreInfo(cache_info->file_semaphore);
4316 region=nexus_info->region;
4317 if ((cache_info->columns != nexus_info->region.width) ||
4318 (extent > MagickMaxBufferExtent))
4325 for (y=0; y < (ssize_t) rows; y++)
4327 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4328 cache_info->server_info,®ion,length,(unsigned char *) q);
4329 if (count != (MagickOffsetType) length)
4331 q+=cache_info->number_channels*nexus_info->region.width;
4334 UnlockSemaphoreInfo(cache_info->file_semaphore);
4340 if (y < (ssize_t) rows)
4342 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4343 cache_info->cache_filename);
4344 return(MagickFalse);
4346 if ((cache_info->debug != MagickFalse) &&
4347 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4348 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4349 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4350 nexus_info->region.width,(double) nexus_info->region.height,(double)
4351 nexus_info->region.x,(double) nexus_info->region.y);
4356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4360 + R e f e r e n c e P i x e l C a c h e %
4364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4366 % ReferencePixelCache() increments the reference count associated with the
4367 % pixel cache returning a pointer to the cache.
4369 % The format of the ReferencePixelCache method is:
4371 % Cache ReferencePixelCache(Cache cache_info)
4373 % A description of each parameter follows:
4375 % o cache_info: the pixel cache.
4378 MagickPrivate Cache ReferencePixelCache(Cache cache)
4381 *restrict cache_info;
4383 assert(cache != (Cache *) NULL);
4384 cache_info=(CacheInfo *) cache;
4385 assert(cache_info->signature == MagickSignature);
4386 LockSemaphoreInfo(cache_info->semaphore);
4387 cache_info->reference_count++;
4388 UnlockSemaphoreInfo(cache_info->semaphore);
4393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4397 + S e t P i x e l C a c h e M e t h o d s %
4401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4403 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4405 % The format of the SetPixelCacheMethods() method is:
4407 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4409 % A description of each parameter follows:
4411 % o cache: the pixel cache.
4413 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4416 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4419 *restrict cache_info;
4421 GetOneAuthenticPixelFromHandler
4422 get_one_authentic_pixel_from_handler;
4424 GetOneVirtualPixelFromHandler
4425 get_one_virtual_pixel_from_handler;
4428 Set cache pixel methods.
4430 assert(cache != (Cache) NULL);
4431 assert(cache_methods != (CacheMethods *) NULL);
4432 cache_info=(CacheInfo *) cache;
4433 assert(cache_info->signature == MagickSignature);
4434 if (cache_info->debug != MagickFalse)
4435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4436 cache_info->filename);
4437 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4438 cache_info->methods.get_virtual_pixel_handler=
4439 cache_methods->get_virtual_pixel_handler;
4440 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4441 cache_info->methods.destroy_pixel_handler=
4442 cache_methods->destroy_pixel_handler;
4443 if (cache_methods->get_virtual_metacontent_from_handler !=
4444 (GetVirtualMetacontentFromHandler) NULL)
4445 cache_info->methods.get_virtual_metacontent_from_handler=
4446 cache_methods->get_virtual_metacontent_from_handler;
4447 if (cache_methods->get_authentic_pixels_handler !=
4448 (GetAuthenticPixelsHandler) NULL)
4449 cache_info->methods.get_authentic_pixels_handler=
4450 cache_methods->get_authentic_pixels_handler;
4451 if (cache_methods->queue_authentic_pixels_handler !=
4452 (QueueAuthenticPixelsHandler) NULL)
4453 cache_info->methods.queue_authentic_pixels_handler=
4454 cache_methods->queue_authentic_pixels_handler;
4455 if (cache_methods->sync_authentic_pixels_handler !=
4456 (SyncAuthenticPixelsHandler) NULL)
4457 cache_info->methods.sync_authentic_pixels_handler=
4458 cache_methods->sync_authentic_pixels_handler;
4459 if (cache_methods->get_authentic_pixels_from_handler !=
4460 (GetAuthenticPixelsFromHandler) NULL)
4461 cache_info->methods.get_authentic_pixels_from_handler=
4462 cache_methods->get_authentic_pixels_from_handler;
4463 if (cache_methods->get_authentic_metacontent_from_handler !=
4464 (GetAuthenticMetacontentFromHandler) NULL)
4465 cache_info->methods.get_authentic_metacontent_from_handler=
4466 cache_methods->get_authentic_metacontent_from_handler;
4467 get_one_virtual_pixel_from_handler=
4468 cache_info->methods.get_one_virtual_pixel_from_handler;
4469 if (get_one_virtual_pixel_from_handler !=
4470 (GetOneVirtualPixelFromHandler) NULL)
4471 cache_info->methods.get_one_virtual_pixel_from_handler=
4472 cache_methods->get_one_virtual_pixel_from_handler;
4473 get_one_authentic_pixel_from_handler=
4474 cache_methods->get_one_authentic_pixel_from_handler;
4475 if (get_one_authentic_pixel_from_handler !=
4476 (GetOneAuthenticPixelFromHandler) NULL)
4477 cache_info->methods.get_one_authentic_pixel_from_handler=
4478 cache_methods->get_one_authentic_pixel_from_handler;
4482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4486 + S e t P i x e l C a c h e N e x u s P i x e l s %
4490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4492 % SetPixelCacheNexusPixels() defines the region of the cache for the
4493 % specified cache nexus.
4495 % The format of the SetPixelCacheNexusPixels() method is:
4497 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4498 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4499 % ExceptionInfo *exception)
4501 % A description of each parameter follows:
4503 % o cache_info: the pixel cache.
4505 % o mode: ReadMode, WriteMode, or IOMode.
4507 % o region: A pointer to the RectangleInfo structure that defines the
4508 % region of this particular cache nexus.
4510 % o nexus_info: the cache nexus to set.
4512 % o exception: return any errors or warnings in this structure.
4516 static inline MagickBooleanType AcquireCacheNexusPixels(
4517 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4518 ExceptionInfo *exception)
4520 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4521 return(MagickFalse);
4522 nexus_info->mapped=MagickFalse;
4523 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4524 (size_t) nexus_info->length));
4525 if (nexus_info->cache == (Quantum *) NULL)
4527 nexus_info->mapped=MagickTrue;
4528 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4529 nexus_info->length);
4531 if (nexus_info->cache == (Quantum *) NULL)
4533 (void) ThrowMagickException(exception,GetMagickModule(),
4534 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4535 cache_info->filename);
4536 return(MagickFalse);
4541 static inline MagickBooleanType IsPixelCacheAuthentic(
4542 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4551 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4553 if (cache_info->type == PingCache)
4555 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4556 nexus_info->region.x;
4557 status=nexus_info->pixels == (cache_info->pixels+offset*
4558 cache_info->number_channels) ? MagickTrue : MagickFalse;
4562 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4565 if (mode == ReadMode)
4567 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4570 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4573 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4574 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4575 ExceptionInfo *exception)
4584 assert(cache_info != (const CacheInfo *) NULL);
4585 assert(cache_info->signature == MagickSignature);
4586 if (cache_info->type == UndefinedCache)
4587 return((Quantum *) NULL);
4588 nexus_info->region=(*region);
4589 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4595 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4596 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4597 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4598 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4599 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4600 ((nexus_info->region.width == cache_info->columns) ||
4601 ((nexus_info->region.width % cache_info->columns) == 0)))))
4607 Pixels are accessed directly from memory.
4609 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4610 nexus_info->region.x;
4611 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4613 nexus_info->metacontent=(void *) NULL;
4614 if (cache_info->metacontent_extent != 0)
4615 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4616 offset*cache_info->metacontent_extent;
4617 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4618 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4620 return(nexus_info->pixels);
4624 Pixels are stored in a staging region until they are synced to the cache.
4626 number_pixels=(MagickSizeType) nexus_info->region.width*
4627 nexus_info->region.height;
4628 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4629 if (cache_info->metacontent_extent != 0)
4630 length+=number_pixels*cache_info->metacontent_extent;
4631 if (nexus_info->cache == (Quantum *) NULL)
4633 nexus_info->length=length;
4634 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4635 if (status == MagickFalse)
4637 nexus_info->length=0;
4638 return((Quantum *) NULL);
4642 if (nexus_info->length < length)
4644 RelinquishCacheNexusPixels(nexus_info);
4645 nexus_info->length=length;
4646 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4647 if (status == MagickFalse)
4649 nexus_info->length=0;
4650 return((Quantum *) NULL);
4653 nexus_info->pixels=nexus_info->cache;
4654 nexus_info->metacontent=(void *) NULL;
4655 if (cache_info->metacontent_extent != 0)
4656 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4657 cache_info->number_channels);
4658 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4659 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4661 return(nexus_info->pixels);
4665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4669 % 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 %
4673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4675 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4676 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4677 % access that is outside the boundaries of the image cache.
4679 % The format of the SetPixelCacheVirtualMethod() method is:
4681 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4682 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4684 % A description of each parameter follows:
4686 % o image: the image.
4688 % o virtual_pixel_method: choose the type of virtual pixel.
4690 % o exception: return any errors or warnings in this structure.
4694 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4695 ExceptionInfo *exception)
4698 *restrict cache_info;
4701 *restrict image_view;
4709 assert(image != (Image *) NULL);
4710 assert(image->signature == MagickSignature);
4711 if (image->debug != MagickFalse)
4712 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4713 assert(image->cache != (Cache) NULL);
4714 cache_info=(CacheInfo *) image->cache;
4715 assert(cache_info->signature == MagickSignature);
4716 image->alpha_trait=BlendPixelTrait;
4718 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4719 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4720 #pragma omp parallel for schedule(static,4) shared(status) \
4721 magick_threads(image,image,1,1)
4723 for (y=0; y < (ssize_t) image->rows; y++)
4731 if (status == MagickFalse)
4733 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4734 if (q == (Quantum *) NULL)
4739 for (x=0; x < (ssize_t) image->columns; x++)
4741 SetPixelAlpha(image,alpha,q);
4742 q+=GetPixelChannels(image);
4744 status=SyncCacheViewAuthenticPixels(image_view,exception);
4746 image_view=DestroyCacheView(image_view);
4750 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4751 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4754 *restrict cache_info;
4759 assert(image != (Image *) NULL);
4760 assert(image->signature == MagickSignature);
4761 if (image->debug != MagickFalse)
4762 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4763 assert(image->cache != (Cache) NULL);
4764 cache_info=(CacheInfo *) image->cache;
4765 assert(cache_info->signature == MagickSignature);
4766 method=cache_info->virtual_pixel_method;
4767 cache_info->virtual_pixel_method=virtual_pixel_method;
4768 if ((image->columns != 0) && (image->rows != 0))
4769 switch (virtual_pixel_method)
4771 case BackgroundVirtualPixelMethod:
4773 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4774 (image->alpha_trait != BlendPixelTrait))
4775 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4776 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4777 (IsGrayColorspace(image->colorspace) != MagickFalse))
4778 (void) SetImageColorspace(image,sRGBColorspace,exception);
4781 case TransparentVirtualPixelMethod:
4783 if (image->alpha_trait != BlendPixelTrait)
4784 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4798 + 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 %
4802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4804 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4805 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4806 % is synced, otherwise MagickFalse.
4808 % The format of the SyncAuthenticPixelCacheNexus() method is:
4810 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4811 % NexusInfo *nexus_info,ExceptionInfo *exception)
4813 % A description of each parameter follows:
4815 % o image: the image.
4817 % o nexus_info: the cache nexus to sync.
4819 % o exception: return any errors or warnings in this structure.
4822 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4823 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4826 *restrict cache_info;
4832 Transfer pixels to the cache.
4834 assert(image != (Image *) NULL);
4835 assert(image->signature == MagickSignature);
4836 if (image->cache == (Cache) NULL)
4837 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4838 cache_info=(CacheInfo *) image->cache;
4839 assert(cache_info->signature == MagickSignature);
4840 if (cache_info->type == UndefinedCache)
4841 return(MagickFalse);
4842 if (nexus_info->authentic_pixel_cache != MagickFalse)
4844 assert(cache_info->signature == MagickSignature);
4845 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4846 if ((cache_info->metacontent_extent != 0) &&
4847 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4848 return(MagickFalse);
4853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4857 + S y n c A u t h e n t i c P i x e l C a c h e %
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4863 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4864 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4865 % otherwise MagickFalse.
4867 % The format of the SyncAuthenticPixelsCache() method is:
4869 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4870 % ExceptionInfo *exception)
4872 % A description of each parameter follows:
4874 % o image: the image.
4876 % o exception: return any errors or warnings in this structure.
4879 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4880 ExceptionInfo *exception)
4883 *restrict cache_info;
4886 id = GetOpenMPThreadId();
4891 assert(image != (Image *) NULL);
4892 assert(image->signature == MagickSignature);
4893 assert(image->cache != (Cache) NULL);
4894 cache_info=(CacheInfo *) image->cache;
4895 assert(cache_info->signature == MagickSignature);
4896 assert(id < (int) cache_info->number_threads);
4897 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4907 % S y n c A u t h e n t i c P i x e l s %
4911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4913 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4914 % The method returns MagickTrue if the pixel region is flushed, otherwise
4917 % The format of the SyncAuthenticPixels() method is:
4919 % MagickBooleanType SyncAuthenticPixels(Image *image,
4920 % ExceptionInfo *exception)
4922 % A description of each parameter follows:
4924 % o image: the image.
4926 % o exception: return any errors or warnings in this structure.
4929 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4930 ExceptionInfo *exception)
4933 *restrict cache_info;
4936 id = GetOpenMPThreadId();
4941 assert(image != (Image *) NULL);
4942 assert(image->signature == MagickSignature);
4943 assert(image->cache != (Cache) NULL);
4944 cache_info=(CacheInfo *) image->cache;
4945 assert(cache_info->signature == MagickSignature);
4946 if (cache_info->methods.sync_authentic_pixels_handler !=
4947 (SyncAuthenticPixelsHandler) NULL)
4949 status=cache_info->methods.sync_authentic_pixels_handler(image,
4953 assert(id < (int) cache_info->number_threads);
4954 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4964 + S y n c I m a g e P i x e l C a c h e %
4968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4970 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4971 % The method returns MagickTrue if the pixel region is flushed, otherwise
4974 % The format of the SyncImagePixelCache() method is:
4976 % MagickBooleanType SyncImagePixelCache(Image *image,
4977 % ExceptionInfo *exception)
4979 % A description of each parameter follows:
4981 % o image: the image.
4983 % o exception: return any errors or warnings in this structure.
4986 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4987 ExceptionInfo *exception)
4990 *restrict cache_info;
4992 assert(image != (Image *) NULL);
4993 assert(exception != (ExceptionInfo *) NULL);
4994 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4995 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5003 + 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 %
5007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5010 % of the pixel cache.
5012 % The format of the WritePixelCacheMetacontent() method is:
5014 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5015 % NexusInfo *nexus_info,ExceptionInfo *exception)
5017 % A description of each parameter follows:
5019 % o cache_info: the pixel cache.
5021 % o nexus_info: the cache nexus to write the meta-content.
5023 % o exception: return any errors or warnings in this structure.
5026 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5027 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5037 register const unsigned char
5046 if (cache_info->metacontent_extent == 0)
5047 return(MagickFalse);
5048 if (nexus_info->authentic_pixel_cache != MagickFalse)
5050 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5051 nexus_info->region.x;
5052 length=(MagickSizeType) nexus_info->region.width*
5053 cache_info->metacontent_extent;
5054 extent=(MagickSizeType) length*nexus_info->region.height;
5055 rows=nexus_info->region.height;
5057 p=(unsigned char *) nexus_info->metacontent;
5058 switch (cache_info->type)
5063 register unsigned char
5067 Write associated pixels to memory.
5069 if ((cache_info->columns == nexus_info->region.width) &&
5070 (extent == (MagickSizeType) ((size_t) extent)))
5075 q=(unsigned char *) cache_info->metacontent+offset*
5076 cache_info->metacontent_extent;
5077 for (y=0; y < (ssize_t) rows; y++)
5079 (void) memcpy(q,p,(size_t) length);
5080 p+=nexus_info->region.width*cache_info->metacontent_extent;
5081 q+=cache_info->columns*cache_info->metacontent_extent;
5088 Write associated pixels to disk.
5090 LockSemaphoreInfo(cache_info->file_semaphore);
5091 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5093 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5094 cache_info->cache_filename);
5095 UnlockSemaphoreInfo(cache_info->file_semaphore);
5096 return(MagickFalse);
5098 if ((cache_info->columns == nexus_info->region.width) &&
5099 (extent <= MagickMaxBufferExtent))
5104 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5105 for (y=0; y < (ssize_t) rows; y++)
5107 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5108 cache_info->number_channels*sizeof(Quantum)+offset*
5109 cache_info->metacontent_extent,length,(const unsigned char *) p);
5110 if (count != (MagickOffsetType) length)
5112 p+=cache_info->metacontent_extent*nexus_info->region.width;
5113 offset+=cache_info->columns;
5115 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5116 (void) ClosePixelCacheOnDisk(cache_info);
5117 UnlockSemaphoreInfo(cache_info->file_semaphore);
5120 case DistributedCache:
5126 Write metacontent to distributed cache.
5128 LockSemaphoreInfo(cache_info->file_semaphore);
5129 region=nexus_info->region;
5130 if ((cache_info->columns != nexus_info->region.width) ||
5131 (extent > MagickMaxBufferExtent))
5138 for (y=0; y < (ssize_t) rows; y++)
5140 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5141 cache_info->server_info,®ion,length,(const unsigned char *) p);
5142 if (count != (MagickOffsetType) length)
5144 p+=cache_info->metacontent_extent*nexus_info->region.width;
5147 UnlockSemaphoreInfo(cache_info->file_semaphore);
5153 if (y < (ssize_t) rows)
5155 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5156 cache_info->cache_filename);
5157 return(MagickFalse);
5159 if ((cache_info->debug != MagickFalse) &&
5160 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5161 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5162 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5163 nexus_info->region.width,(double) nexus_info->region.height,(double)
5164 nexus_info->region.x,(double) nexus_info->region.y);
5169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173 + W r i t e C a c h e P i x e l s %
5177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179 % WritePixelCachePixels() writes image pixels to the specified region of the
5182 % The format of the WritePixelCachePixels() method is:
5184 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5185 % NexusInfo *nexus_info,ExceptionInfo *exception)
5187 % A description of each parameter follows:
5189 % o cache_info: the pixel cache.
5191 % o nexus_info: the cache nexus to write the pixels.
5193 % o exception: return any errors or warnings in this structure.
5196 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5197 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5207 register const Quantum
5216 if (nexus_info->authentic_pixel_cache != MagickFalse)
5218 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5219 nexus_info->region.x;
5220 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5222 extent=length*nexus_info->region.height;
5223 rows=nexus_info->region.height;
5225 p=nexus_info->pixels;
5226 switch (cache_info->type)
5235 Write pixels to memory.
5237 if ((cache_info->columns == nexus_info->region.width) &&
5238 (extent == (MagickSizeType) ((size_t) extent)))
5243 q=cache_info->pixels+offset*cache_info->number_channels;
5244 for (y=0; y < (ssize_t) rows; y++)
5246 (void) memcpy(q,p,(size_t) length);
5247 p+=cache_info->number_channels*nexus_info->region.width;
5248 q+=cache_info->columns*cache_info->number_channels;
5255 Write pixels to disk.
5257 LockSemaphoreInfo(cache_info->file_semaphore);
5258 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5260 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5261 cache_info->cache_filename);
5262 UnlockSemaphoreInfo(cache_info->file_semaphore);
5263 return(MagickFalse);
5265 if ((cache_info->columns == nexus_info->region.width) &&
5266 (extent <= MagickMaxBufferExtent))
5271 for (y=0; y < (ssize_t) rows; y++)
5273 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5274 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5276 if (count != (MagickOffsetType) length)
5278 p+=cache_info->number_channels*nexus_info->region.width;
5279 offset+=cache_info->columns;
5281 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5282 (void) ClosePixelCacheOnDisk(cache_info);
5283 UnlockSemaphoreInfo(cache_info->file_semaphore);
5286 case DistributedCache:
5292 Write pixels to distributed cache.
5294 LockSemaphoreInfo(cache_info->file_semaphore);
5295 region=nexus_info->region;
5296 if ((cache_info->columns != nexus_info->region.width) ||
5297 (extent > MagickMaxBufferExtent))
5304 for (y=0; y < (ssize_t) rows; y++)
5306 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5307 cache_info->server_info,®ion,length,(const unsigned char *) p);
5308 if (count != (MagickOffsetType) length)
5310 p+=cache_info->number_channels*nexus_info->region.width;
5313 UnlockSemaphoreInfo(cache_info->file_semaphore);
5319 if (y < (ssize_t) rows)
5321 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5322 cache_info->cache_filename);
5323 return(MagickFalse);
5325 if ((cache_info->debug != MagickFalse) &&
5326 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5327 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5328 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5329 nexus_info->region.width,(double) nexus_info->region.height,(double)
5330 nexus_info->region.x,(double) nexus_info->region.y);