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=AcquireSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->file_semaphore=AcquireSemaphoreInfo();
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 cache_semaphore=AcquireSemaphoreInfo();
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 ActivateSemaphoreInfo(&cache_semaphore);
353 LockSemaphoreInfo(cache_semaphore);
354 instantiate_cache=MagickFalse;
355 UnlockSemaphoreInfo(cache_semaphore);
356 RelinquishSemaphoreInfo(&cache_semaphore);
360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 + C l o n e P i x e l C a c h e %
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 % ClonePixelCache() clones a pixel cache.
372 % The format of the ClonePixelCache() method is:
374 % Cache ClonePixelCache(const Cache cache)
376 % A description of each parameter follows:
378 % o cache: the pixel cache.
381 MagickPrivate Cache ClonePixelCache(const Cache cache)
384 *restrict clone_info;
387 *restrict cache_info;
389 assert(cache != NULL);
390 cache_info=(const CacheInfo *) cache;
391 assert(cache_info->signature == MagickSignature);
392 if (cache_info->debug != MagickFalse)
393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
394 cache_info->filename);
395 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
396 if (clone_info == (Cache) NULL)
397 return((Cache) NULL);
398 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
399 return((Cache ) clone_info);
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 + C l o n e P i x e l C a c h e M e t h o d s %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
416 % The format of the ClonePixelCacheMethods() method is:
418 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
420 % A description of each parameter follows:
422 % o clone: Specifies a pointer to a Cache structure.
424 % o cache: the pixel cache.
427 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
430 *restrict cache_info,
431 *restrict source_info;
433 assert(clone != (Cache) NULL);
434 source_info=(CacheInfo *) clone;
435 assert(source_info->signature == MagickSignature);
436 if (source_info->debug != MagickFalse)
437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
438 source_info->filename);
439 assert(cache != (Cache) NULL);
440 cache_info=(CacheInfo *) cache;
441 assert(cache_info->signature == MagickSignature);
442 source_info->methods=cache_info->methods;
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450 + C l o n e P i x e l C a c h e R e p o s i t o r y %
454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
455 % ClonePixelCacheRepository() clones the source pixel cache to the destination
458 % The format of the ClonePixelCacheRepository() method is:
460 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
461 % CacheInfo *source_info,ExceptionInfo *exception)
463 % A description of each parameter follows:
465 % o cache_info: the pixel cache.
467 % o source_info: the source pixel cache.
469 % o exception: return any errors or warnings in this structure.
473 static inline void CopyPixels(Quantum *destination,const Quantum *source,
474 const MagickSizeType number_pixels)
476 #if !defined(MAGICKCORE_OPENMP_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH <= 8)
477 (void) memcpy(destination,source,(size_t) number_pixels*sizeof(*source));
480 register MagickOffsetType
483 if ((number_pixels*sizeof(*source)) < MagickMaxBufferExtent)
485 (void) memcpy(destination,source,(size_t) number_pixels*
489 #pragma omp parallel for
490 for (i=0; i < (MagickOffsetType) number_pixels; i++)
491 destination[i]=source[i];
496 static inline MagickSizeType MagickMin(const MagickSizeType x,
497 const MagickSizeType y)
504 static MagickBooleanType ClonePixelCacheRepository(
505 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
506 ExceptionInfo *exception)
508 #define MaxCacheThreads 2
509 #define cache_threads(source,destination,chunk) \
510 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
511 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
512 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
519 **restrict cache_nexus,
520 **restrict clone_nexus;
528 assert(cache_info != (CacheInfo *) NULL);
529 assert(clone_info != (CacheInfo *) NULL);
530 assert(exception != (ExceptionInfo *) NULL);
531 if (cache_info->type == PingCache)
533 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
534 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
535 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
536 (cache_info->columns == clone_info->columns) &&
537 (cache_info->rows == clone_info->rows) &&
538 (cache_info->number_channels == clone_info->number_channels) &&
539 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
540 (cache_info->metacontent_extent == clone_info->metacontent_extent))
542 CopyPixels(clone_info->pixels,cache_info->pixels,cache_info->columns*
543 cache_info->number_channels*cache_info->rows);
544 if (cache_info->metacontent_extent != 0)
545 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
546 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
547 sizeof(cache_info->metacontent));
551 Mismatched pixel cache morphology.
553 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
554 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
555 if ((cache_nexus == (NexusInfo **) NULL) ||
556 (clone_nexus == (NexusInfo **) NULL))
557 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
558 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
559 optimize=(cache_info->number_channels == clone_info->number_channels) &&
560 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
561 MagickTrue : MagickFalse;
562 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
563 clone_info->columns*clone_info->number_channels);
565 #if defined(MAGICKCORE_OPENMP_SUPPORT)
566 #pragma omp parallel for schedule(static,4) shared(status) \
567 cache_threads(cache_info,clone_info,cache_info->rows)
569 for (y=0; y < (ssize_t) cache_info->rows; y++)
572 id = GetOpenMPThreadId();
583 if (status == MagickFalse)
585 if (y >= (ssize_t) clone_info->rows)
587 region.width=cache_info->columns;
591 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
593 if (pixels == (Quantum *) NULL)
595 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
596 if (status == MagickFalse)
598 region.width=clone_info->columns;
599 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
600 clone_nexus[id],exception);
601 if (pixels == (Quantum *) NULL)
603 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,clone_nexus[id]->length);
604 if (optimize != MagickFalse)
605 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
609 register const Quantum
616 Mismatched pixel channel map.
618 p=cache_nexus[id]->pixels;
619 q=clone_nexus[id]->pixels;
620 for (x=0; x < (ssize_t) cache_info->columns; x++)
625 if (x == (ssize_t) clone_info->columns)
627 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
635 channel=clone_info->channel_map[i].channel;
636 traits=cache_info->channel_map[channel].traits;
637 if (traits != UndefinedPixelTrait)
638 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
642 p+=cache_info->number_channels;
645 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
647 if ((cache_info->metacontent_extent != 0) &&
648 (clone_info->metacontent_extent != 0))
653 length=(size_t) MagickMin(cache_info->metacontent_extent,
654 clone_info->metacontent_extent);
655 #if defined(MAGICKCORE_OPENMP_SUPPORT)
656 #pragma omp parallel for schedule(static,4) shared(status) \
657 cache_threads(cache_info,clone_info,cache_info->rows)
659 for (y=0; y < (ssize_t) cache_info->rows; y++)
662 id = GetOpenMPThreadId();
670 if (status == MagickFalse)
672 if (y >= (ssize_t) clone_info->rows)
674 region.width=cache_info->columns;
678 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
679 cache_nexus[id],exception);
680 if (pixels == (Quantum *) NULL)
682 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
683 if (status == MagickFalse)
685 region.width=clone_info->columns;
686 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
687 clone_nexus[id],exception);
688 if (pixels == (Quantum *) NULL)
690 if (clone_nexus[id]->metacontent != (void *) NULL)
691 (void) memcpy(clone_nexus[id]->metacontent,
692 cache_nexus[id]->metacontent,length*
693 sizeof(cache_nexus[id]->metacontent));
694 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
697 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
698 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
699 if (cache_info->debug != MagickFalse)
702 message[MaxTextExtent];
704 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
705 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
706 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 + D e s t r o y I m a g e P i x e l C a c h e %
721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
725 % The format of the DestroyImagePixelCache() method is:
727 % void DestroyImagePixelCache(Image *image)
729 % A description of each parameter follows:
731 % o image: the image.
734 static void DestroyImagePixelCache(Image *image)
736 assert(image != (Image *) NULL);
737 assert(image->signature == MagickSignature);
738 if (image->debug != MagickFalse)
739 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
740 if (image->cache == (void *) NULL)
742 image->cache=DestroyPixelCache(image->cache);
746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750 + D e s t r o y I m a g e P i x e l s %
754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 % DestroyImagePixels() deallocates memory associated with the pixel cache.
758 % The format of the DestroyImagePixels() method is:
760 % void DestroyImagePixels(Image *image)
762 % A description of each parameter follows:
764 % o image: the image.
767 MagickExport void DestroyImagePixels(Image *image)
770 *restrict cache_info;
772 assert(image != (const Image *) NULL);
773 assert(image->signature == MagickSignature);
774 if (image->debug != MagickFalse)
775 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
776 assert(image->cache != (Cache) NULL);
777 cache_info=(CacheInfo *) image->cache;
778 assert(cache_info->signature == MagickSignature);
779 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
781 cache_info->methods.destroy_pixel_handler(image);
784 image->cache=DestroyPixelCache(image->cache);
788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792 + D e s t r o y P i x e l C a c h e %
796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798 % DestroyPixelCache() deallocates memory associated with the pixel cache.
800 % The format of the DestroyPixelCache() method is:
802 % Cache DestroyPixelCache(Cache cache)
804 % A description of each parameter follows:
806 % o cache: the pixel cache.
810 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
816 if (cache_info->file != -1)
818 status=close(cache_info->file);
819 cache_info->file=(-1);
820 RelinquishMagickResource(FileResource,1);
822 return(status == -1 ? MagickFalse : MagickTrue);
825 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
827 switch (cache_info->type)
831 if (cache_info->mapped == MagickFalse)
832 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
836 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
837 cache_info->pixels=(Quantum *) NULL;
839 RelinquishMagickResource(MemoryResource,cache_info->length);
844 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
845 cache_info->pixels=(Quantum *) NULL;
846 if (cache_info->mode != ReadMode)
847 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
848 *cache_info->cache_filename='\0';
849 RelinquishMagickResource(MapResource,cache_info->length);
853 if (cache_info->file != -1)
854 (void) ClosePixelCacheOnDisk(cache_info);
855 if (cache_info->mode != ReadMode)
856 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
857 *cache_info->cache_filename='\0';
858 RelinquishMagickResource(DiskResource,cache_info->length);
861 case DistributedCache:
863 *cache_info->cache_filename='\0';
864 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
865 cache_info->server_info);
871 cache_info->type=UndefinedCache;
872 cache_info->mapped=MagickFalse;
873 cache_info->metacontent=(void *) NULL;
876 MagickPrivate Cache DestroyPixelCache(Cache cache)
879 *restrict cache_info;
881 assert(cache != (Cache) NULL);
882 cache_info=(CacheInfo *) cache;
883 assert(cache_info->signature == MagickSignature);
884 if (cache_info->debug != MagickFalse)
885 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
886 cache_info->filename);
887 LockSemaphoreInfo(cache_info->semaphore);
888 cache_info->reference_count--;
889 if (cache_info->reference_count != 0)
891 UnlockSemaphoreInfo(cache_info->semaphore);
892 return((Cache) NULL);
894 UnlockSemaphoreInfo(cache_info->semaphore);
895 if (cache_info->debug != MagickFalse)
898 message[MaxTextExtent];
900 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
901 cache_info->filename);
902 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
904 RelinquishPixelCachePixels(cache_info);
905 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
906 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
907 cache_info->server_info);
908 if (cache_info->nexus_info != (NexusInfo **) NULL)
909 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
910 cache_info->number_threads);
911 if (cache_info->random_info != (RandomInfo *) NULL)
912 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
913 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
914 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
915 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
916 RelinquishSemaphoreInfo(&cache_info->semaphore);
917 cache_info->signature=(~MagickSignature);
918 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
924 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928 + D e s t r o y P i x e l C a c h e N e x u s %
932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
934 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
936 % The format of the DestroyPixelCacheNexus() method is:
938 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
939 % const size_t number_threads)
941 % A description of each parameter follows:
943 % o nexus_info: the nexus to destroy.
945 % o number_threads: the number of nexus threads.
949 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
951 if (nexus_info->mapped == MagickFalse)
952 (void) RelinquishAlignedMemory(nexus_info->cache);
954 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
955 nexus_info->cache=(Quantum *) NULL;
956 nexus_info->pixels=(Quantum *) NULL;
957 nexus_info->metacontent=(void *) NULL;
958 nexus_info->length=0;
959 nexus_info->mapped=MagickFalse;
962 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
963 const size_t number_threads)
968 assert(nexus_info != (NexusInfo **) NULL);
969 for (i=0; i < (ssize_t) number_threads; i++)
971 if (nexus_info[i]->cache != (Quantum *) NULL)
972 RelinquishCacheNexusPixels(nexus_info[i]);
973 nexus_info[i]->signature=(~MagickSignature);
975 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
976 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
985 % G e t A u t h e n t i c M e t a c o n t e n t %
989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
991 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
992 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
993 % returned if the associated pixels are not available.
995 % The format of the GetAuthenticMetacontent() method is:
997 % void *GetAuthenticMetacontent(const Image *image)
999 % A description of each parameter follows:
1001 % o image: the image.
1004 MagickExport void *GetAuthenticMetacontent(const Image *image)
1007 *restrict cache_info;
1010 id = GetOpenMPThreadId();
1012 assert(image != (const Image *) NULL);
1013 assert(image->signature == MagickSignature);
1014 assert(image->cache != (Cache) NULL);
1015 cache_info=(CacheInfo *) image->cache;
1016 assert(cache_info->signature == MagickSignature);
1017 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1018 (GetAuthenticMetacontentFromHandler) NULL)
1023 metacontent=cache_info->methods.
1024 get_authentic_metacontent_from_handler(image);
1025 return(metacontent);
1027 assert(id < (int) cache_info->number_threads);
1028 return(cache_info->nexus_info[id]->metacontent);
1032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036 + G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1043 % with the last call to QueueAuthenticPixelsCache() or
1044 % GetAuthenticPixelsCache().
1046 % The format of the GetAuthenticMetacontentFromCache() method is:
1048 % void *GetAuthenticMetacontentFromCache(const Image *image)
1050 % A description of each parameter follows:
1052 % o image: the image.
1055 static void *GetAuthenticMetacontentFromCache(const Image *image)
1058 *restrict cache_info;
1061 id = GetOpenMPThreadId();
1063 assert(image != (const Image *) NULL);
1064 assert(image->signature == MagickSignature);
1065 assert(image->cache != (Cache) NULL);
1066 cache_info=(CacheInfo *) image->cache;
1067 assert(cache_info->signature == MagickSignature);
1068 assert(id < (int) cache_info->number_threads);
1069 return(cache_info->nexus_info[id]->metacontent);
1073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1077 + G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1084 % disk pixel cache as defined by the geometry parameters. A pointer to the
1085 % pixels is returned if the pixels are transferred, otherwise a NULL is
1088 % The format of the GetAuthenticPixelCacheNexus() method is:
1090 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1091 % const ssize_t y,const size_t columns,const size_t rows,
1092 % NexusInfo *nexus_info,ExceptionInfo *exception)
1094 % A description of each parameter follows:
1096 % o image: the image.
1098 % o x,y,columns,rows: These values define the perimeter of a region of
1101 % o nexus_info: the cache nexus to return.
1103 % o exception: return any errors or warnings in this structure.
1107 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1108 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1109 ExceptionInfo *exception)
1112 *restrict cache_info;
1118 Transfer pixels from the cache.
1120 assert(image != (Image *) NULL);
1121 assert(image->signature == MagickSignature);
1122 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1123 nexus_info,exception);
1124 if (pixels == (Quantum *) NULL)
1125 return((Quantum *) NULL);
1126 cache_info=(CacheInfo *) image->cache;
1127 assert(cache_info->signature == MagickSignature);
1128 if (nexus_info->authentic_pixel_cache != MagickFalse)
1130 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1131 return((Quantum *) NULL);
1132 if (cache_info->metacontent_extent != 0)
1133 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1134 return((Quantum *) NULL);
1139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1143 + G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1150 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1152 % The format of the GetAuthenticPixelsFromCache() method is:
1154 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1156 % A description of each parameter follows:
1158 % o image: the image.
1161 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1164 *restrict cache_info;
1167 id = GetOpenMPThreadId();
1169 assert(image != (const Image *) NULL);
1170 assert(image->signature == MagickSignature);
1171 assert(image->cache != (Cache) NULL);
1172 cache_info=(CacheInfo *) image->cache;
1173 assert(cache_info->signature == MagickSignature);
1174 assert(id < (int) cache_info->number_threads);
1175 return(cache_info->nexus_info[id]->pixels);
1179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1183 % G e t A u t h e n t i c P i x e l Q u e u e %
1187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189 % GetAuthenticPixelQueue() returns the authentic pixels associated
1190 % corresponding with the last call to QueueAuthenticPixels() or
1191 % GetAuthenticPixels().
1193 % The format of the GetAuthenticPixelQueue() method is:
1195 % Quantum *GetAuthenticPixelQueue(const Image image)
1197 % A description of each parameter follows:
1199 % o image: the image.
1202 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1205 *restrict cache_info;
1208 id = GetOpenMPThreadId();
1210 assert(image != (const Image *) NULL);
1211 assert(image->signature == MagickSignature);
1212 assert(image->cache != (Cache) NULL);
1213 cache_info=(CacheInfo *) image->cache;
1214 assert(cache_info->signature == MagickSignature);
1215 if (cache_info->methods.get_authentic_pixels_from_handler !=
1216 (GetAuthenticPixelsFromHandler) NULL)
1217 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1218 assert(id < (int) cache_info->number_threads);
1219 return(cache_info->nexus_info[id]->pixels);
1223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1227 % G e t A u t h e n t i c P i x e l s %
1230 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1232 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1233 % region is successfully accessed, a pointer to a Quantum array
1234 % representing the region is returned, otherwise NULL is returned.
1236 % The returned pointer may point to a temporary working copy of the pixels
1237 % or it may point to the original pixels in memory. Performance is maximized
1238 % if the selected region is part of one row, or one or more full rows, since
1239 % then there is opportunity to access the pixels in-place (without a copy)
1240 % if the image is in memory, or in a memory-mapped file. The returned pointer
1241 % must *never* be deallocated by the user.
1243 % Pixels accessed via the returned pointer represent a simple array of type
1244 % Quantum. If the image has corresponding metacontent,call
1245 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1246 % meta-content corresponding to the region. Once the Quantum array has
1247 % been updated, the changes must be saved back to the underlying image using
1248 % SyncAuthenticPixels() or they may be lost.
1250 % The format of the GetAuthenticPixels() method is:
1252 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1253 % const ssize_t y,const size_t columns,const size_t rows,
1254 % ExceptionInfo *exception)
1256 % A description of each parameter follows:
1258 % o image: the image.
1260 % o x,y,columns,rows: These values define the perimeter of a region of
1263 % o exception: return any errors or warnings in this structure.
1266 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1267 const ssize_t y,const size_t columns,const size_t rows,
1268 ExceptionInfo *exception)
1271 *restrict cache_info;
1274 id = GetOpenMPThreadId();
1279 assert(image != (Image *) NULL);
1280 assert(image->signature == MagickSignature);
1281 assert(image->cache != (Cache) NULL);
1282 cache_info=(CacheInfo *) image->cache;
1283 assert(cache_info->signature == MagickSignature);
1284 if (cache_info->methods.get_authentic_pixels_handler !=
1285 (GetAuthenticPixelsHandler) NULL)
1287 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1291 assert(id < (int) cache_info->number_threads);
1292 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1293 cache_info->nexus_info[id],exception);
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 + G e t A u t h e n t i c P i x e l s C a c h e %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1309 % as defined by the geometry parameters. A pointer to the pixels is returned
1310 % if the pixels are transferred, otherwise a NULL is returned.
1312 % The format of the GetAuthenticPixelsCache() method is:
1314 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1315 % const ssize_t y,const size_t columns,const size_t rows,
1316 % ExceptionInfo *exception)
1318 % A description of each parameter follows:
1320 % o image: the image.
1322 % o x,y,columns,rows: These values define the perimeter of a region of
1325 % o exception: return any errors or warnings in this structure.
1328 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1329 const ssize_t y,const size_t columns,const size_t rows,
1330 ExceptionInfo *exception)
1333 *restrict cache_info;
1336 id = GetOpenMPThreadId();
1341 assert(image != (const Image *) NULL);
1342 assert(image->signature == MagickSignature);
1343 assert(image->cache != (Cache) NULL);
1344 cache_info=(CacheInfo *) image->cache;
1345 if (cache_info == (Cache) NULL)
1346 return((Quantum *) NULL);
1347 assert(cache_info->signature == MagickSignature);
1348 assert(id < (int) cache_info->number_threads);
1349 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1350 cache_info->nexus_info[id],exception);
1355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 + G e t I m a g e E x t e n t %
1363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365 % GetImageExtent() returns the extent of the pixels associated corresponding
1366 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1368 % The format of the GetImageExtent() method is:
1370 % MagickSizeType GetImageExtent(const Image *image)
1372 % A description of each parameter follows:
1374 % o image: the image.
1377 MagickExport MagickSizeType GetImageExtent(const Image *image)
1380 *restrict cache_info;
1383 id = GetOpenMPThreadId();
1385 assert(image != (Image *) NULL);
1386 assert(image->signature == MagickSignature);
1387 if (image->debug != MagickFalse)
1388 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1389 assert(image->cache != (Cache) NULL);
1390 cache_info=(CacheInfo *) image->cache;
1391 assert(cache_info->signature == MagickSignature);
1392 assert(id < (int) cache_info->number_threads);
1393 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401 + G e t I m a g e P i x e l C a c h e %
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407 % GetImagePixelCache() ensures that there is only a single reference to the
1408 % pixel cache to be modified, updating the provided cache pointer to point to
1409 % a clone of the original pixel cache if necessary.
1411 % The format of the GetImagePixelCache method is:
1413 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1414 % ExceptionInfo *exception)
1416 % A description of each parameter follows:
1418 % o image: the image.
1420 % o clone: any value other than MagickFalse clones the cache pixels.
1422 % o exception: return any errors or warnings in this structure.
1426 static inline MagickBooleanType ValidatePixelCacheMorphology(
1427 const Image *restrict image)
1430 *restrict cache_info;
1432 const PixelChannelMap
1437 Does the image match the pixel cache morphology?
1439 cache_info=(CacheInfo *) image->cache;
1440 p=image->channel_map;
1441 q=cache_info->channel_map;
1442 if ((image->storage_class != cache_info->storage_class) ||
1443 (image->colorspace != cache_info->colorspace) ||
1444 (image->alpha_trait != cache_info->alpha_trait) ||
1445 (image->read_mask != cache_info->read_mask) ||
1446 (image->write_mask != cache_info->write_mask) ||
1447 (image->columns != cache_info->columns) ||
1448 (image->rows != cache_info->rows) ||
1449 (image->number_channels != cache_info->number_channels) ||
1450 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1451 (image->metacontent_extent != cache_info->metacontent_extent) ||
1452 (cache_info->nexus_info == (NexusInfo **) NULL))
1453 return(MagickFalse);
1457 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1458 ExceptionInfo *exception)
1461 *restrict cache_info;
1467 static MagickSizeType
1473 cache_timestamp = 0;
1476 LockSemaphoreInfo(image->semaphore);
1477 if (cpu_throttle == 0)
1478 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1479 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1480 MagickDelay(cpu_throttle);
1481 if (time_limit == 0)
1484 Set the expire time in seconds.
1486 time_limit=GetMagickResourceLimit(TimeResource);
1487 cache_timestamp=time((time_t *) NULL);
1489 if ((time_limit != MagickResourceInfinity) &&
1490 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1492 #if defined(ECANCELED)
1495 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1497 assert(image->cache != (Cache) NULL);
1498 cache_info=(CacheInfo *) image->cache;
1499 destroy=MagickFalse;
1500 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1502 LockSemaphoreInfo(cache_info->semaphore);
1503 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1514 clone_image=(*image);
1515 clone_image.semaphore=AcquireSemaphoreInfo();
1516 clone_image.reference_count=1;
1517 clone_image.cache=ClonePixelCache(cache_info);
1518 clone_info=(CacheInfo *) clone_image.cache;
1519 status=OpenPixelCache(&clone_image,IOMode,exception);
1520 if (status != MagickFalse)
1522 if (clone != MagickFalse)
1523 status=ClonePixelCacheRepository(clone_info,cache_info,
1525 if (status != MagickFalse)
1527 if (cache_info->reference_count == 1)
1528 cache_info->nexus_info=(NexusInfo **) NULL;
1530 image->cache=clone_image.cache;
1533 RelinquishSemaphoreInfo(&clone_image.semaphore);
1535 UnlockSemaphoreInfo(cache_info->semaphore);
1537 if (destroy != MagickFalse)
1538 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1539 if (status != MagickFalse)
1542 Ensure the image matches the pixel cache morphology.
1544 image->taint=MagickTrue;
1545 image->type=UndefinedType;
1546 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1548 status=OpenPixelCache(image,IOMode,exception);
1549 cache_info=(CacheInfo *) image->cache;
1550 if (cache_info->type == DiskCache)
1551 (void) ClosePixelCacheOnDisk(cache_info);
1554 UnlockSemaphoreInfo(image->semaphore);
1555 if (status == MagickFalse)
1556 return((Cache) NULL);
1557 return(image->cache);
1561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1565 + G e t I m a g e P i x e l C a c h e T y p e %
1569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1571 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1572 % DiskCache, MemoryCache, MapCache, or PingCache.
1574 % The format of the GetImagePixelCacheType() method is:
1576 % CacheType GetImagePixelCacheType(const Image *image)
1578 % A description of each parameter follows:
1580 % o image: the image.
1583 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1586 *restrict cache_info;
1588 assert(image != (Image *) NULL);
1589 assert(image->signature == MagickSignature);
1590 assert(image->cache != (Cache) NULL);
1591 cache_info=(CacheInfo *) image->cache;
1592 assert(cache_info->signature == MagickSignature);
1593 return(cache_info->type);
1597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601 % G e t O n e A u t h e n t i c P i x e l %
1605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1608 % location. The image background color is returned if an error occurs.
1610 % The format of the GetOneAuthenticPixel() method is:
1612 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1613 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1615 % A description of each parameter follows:
1617 % o image: the image.
1619 % o x,y: These values define the location of the pixel to return.
1621 % o pixel: return a pixel at the specified (x,y) location.
1623 % o exception: return any errors or warnings in this structure.
1626 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1627 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1630 *restrict cache_info;
1638 assert(image != (Image *) NULL);
1639 assert(image->signature == MagickSignature);
1640 assert(image->cache != (Cache) NULL);
1641 cache_info=(CacheInfo *) image->cache;
1642 assert(cache_info->signature == MagickSignature);
1643 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1644 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1645 (GetOneAuthenticPixelFromHandler) NULL)
1646 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1648 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1649 if (q == (Quantum *) NULL)
1651 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1652 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1653 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1654 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1655 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1656 return(MagickFalse);
1658 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1660 PixelChannel channel=GetPixelChannelChannel(image,i);
1661 pixel[channel]=q[i];
1667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671 + 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 %
1675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1678 % location. The image background color is returned if an error occurs.
1680 % The format of the GetOneAuthenticPixelFromCache() method is:
1682 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1683 % const ssize_t x,const ssize_t y,Quantum *pixel,
1684 % ExceptionInfo *exception)
1686 % A description of each parameter follows:
1688 % o image: the image.
1690 % o x,y: These values define the location of the pixel to return.
1692 % o pixel: return a pixel at the specified (x,y) location.
1694 % o exception: return any errors or warnings in this structure.
1697 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1698 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1701 *restrict cache_info;
1704 id = GetOpenMPThreadId();
1712 assert(image != (const Image *) NULL);
1713 assert(image->signature == MagickSignature);
1714 assert(image->cache != (Cache) NULL);
1715 cache_info=(CacheInfo *) image->cache;
1716 assert(cache_info->signature == MagickSignature);
1717 assert(id < (int) cache_info->number_threads);
1718 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1719 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1721 if (q == (Quantum *) NULL)
1723 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1724 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1725 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1726 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1727 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1728 return(MagickFalse);
1730 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1732 PixelChannel channel=GetPixelChannelChannel(image,i);
1733 pixel[channel]=q[i];
1739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1743 % G e t O n e V i r t u a l P i x e l %
1747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1749 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1750 % (x,y) location. The image background color is returned if an error occurs.
1751 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1753 % The format of the GetOneVirtualPixel() method is:
1755 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1756 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1758 % A description of each parameter follows:
1760 % o image: the image.
1762 % o x,y: These values define the location of the pixel to return.
1764 % o pixel: return a pixel at the specified (x,y) location.
1766 % o exception: return any errors or warnings in this structure.
1769 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1770 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1773 *restrict cache_info;
1776 id = GetOpenMPThreadId();
1784 assert(image != (const Image *) NULL);
1785 assert(image->signature == MagickSignature);
1786 assert(image->cache != (Cache) NULL);
1787 cache_info=(CacheInfo *) image->cache;
1788 assert(cache_info->signature == MagickSignature);
1789 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1790 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1791 (GetOneVirtualPixelFromHandler) NULL)
1792 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1793 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1794 assert(id < (int) cache_info->number_threads);
1795 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1796 1UL,1UL,cache_info->nexus_info[id],exception);
1797 if (p == (const Quantum *) NULL)
1799 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1800 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1801 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1802 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1803 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1804 return(MagickFalse);
1806 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1808 PixelChannel channel=GetPixelChannelChannel(image,i);
1809 pixel[channel]=p[i];
1815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1819 + 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 %
1823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1825 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1826 % specified (x,y) location. The image background color is returned if an
1829 % The format of the GetOneVirtualPixelFromCache() method is:
1831 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1832 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1833 % Quantum *pixel,ExceptionInfo *exception)
1835 % A description of each parameter follows:
1837 % o image: the image.
1839 % o virtual_pixel_method: the virtual pixel method.
1841 % o x,y: These values define the location of the pixel to return.
1843 % o pixel: return a pixel at the specified (x,y) location.
1845 % o exception: return any errors or warnings in this structure.
1848 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1849 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1850 Quantum *pixel,ExceptionInfo *exception)
1853 *restrict cache_info;
1856 id = GetOpenMPThreadId();
1864 assert(image != (const Image *) NULL);
1865 assert(image->signature == MagickSignature);
1866 assert(image->cache != (Cache) NULL);
1867 cache_info=(CacheInfo *) image->cache;
1868 assert(cache_info->signature == MagickSignature);
1869 assert(id < (int) cache_info->number_threads);
1870 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1871 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1872 cache_info->nexus_info[id],exception);
1873 if (p == (const Quantum *) NULL)
1875 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1876 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1877 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1878 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1879 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1880 return(MagickFalse);
1882 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1884 PixelChannel channel=GetPixelChannelChannel(image,i);
1885 pixel[channel]=p[i];
1891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1895 % G e t O n e V i r t u a l P i x e l I n f o %
1899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1902 % location. The image background color is returned if an error occurs. If
1903 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1905 % The format of the GetOneVirtualPixelInfo() method is:
1907 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1908 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1909 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1911 % A description of each parameter follows:
1913 % o image: the image.
1915 % o virtual_pixel_method: the virtual pixel method.
1917 % o x,y: these values define the location of the pixel to return.
1919 % o pixel: return a pixel at the specified (x,y) location.
1921 % o exception: return any errors or warnings in this structure.
1924 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1925 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1926 PixelInfo *pixel,ExceptionInfo *exception)
1929 *restrict cache_info;
1932 id = GetOpenMPThreadId();
1934 register const Quantum
1937 assert(image != (const Image *) NULL);
1938 assert(image->signature == MagickSignature);
1939 assert(image->cache != (Cache) NULL);
1940 cache_info=(CacheInfo *) image->cache;
1941 assert(cache_info->signature == MagickSignature);
1942 assert(id < (int) cache_info->number_threads);
1943 GetPixelInfo(image,pixel);
1944 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1945 cache_info->nexus_info[id],exception);
1946 if (p == (const Quantum *) NULL)
1947 return(MagickFalse);
1948 GetPixelInfoPixel(image,p,pixel);
1953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1957 + G e t P i x e l C a c h e C o l o r s p a c e %
1961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1963 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1965 % The format of the GetPixelCacheColorspace() method is:
1967 % Colorspace GetPixelCacheColorspace(Cache cache)
1969 % A description of each parameter follows:
1971 % o cache: the pixel cache.
1974 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1977 *restrict cache_info;
1979 assert(cache != (Cache) NULL);
1980 cache_info=(CacheInfo *) cache;
1981 assert(cache_info->signature == MagickSignature);
1982 if (cache_info->debug != MagickFalse)
1983 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1984 cache_info->filename);
1985 return(cache_info->colorspace);
1989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1993 + G e t P i x e l C a c h e M e t h o d s %
1997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999 % GetPixelCacheMethods() initializes the CacheMethods structure.
2001 % The format of the GetPixelCacheMethods() method is:
2003 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2005 % A description of each parameter follows:
2007 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2010 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2012 assert(cache_methods != (CacheMethods *) NULL);
2013 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2014 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2015 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2016 cache_methods->get_virtual_metacontent_from_handler=
2017 GetVirtualMetacontentFromCache;
2018 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2019 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2020 cache_methods->get_authentic_metacontent_from_handler=
2021 GetAuthenticMetacontentFromCache;
2022 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2023 cache_methods->get_one_authentic_pixel_from_handler=
2024 GetOneAuthenticPixelFromCache;
2025 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2026 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2027 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2035 + G e t P i x e l C a c h e N e x u s E x t e n t %
2039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2041 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2042 % corresponding with the last call to SetPixelCacheNexusPixels() or
2043 % GetPixelCacheNexusPixels().
2045 % The format of the GetPixelCacheNexusExtent() method is:
2047 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2048 % NexusInfo *nexus_info)
2050 % A description of each parameter follows:
2052 % o nexus_info: the nexus info.
2055 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2056 NexusInfo *restrict nexus_info)
2059 *restrict cache_info;
2064 assert(cache != NULL);
2065 cache_info=(CacheInfo *) cache;
2066 assert(cache_info->signature == MagickSignature);
2067 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2069 return((MagickSizeType) cache_info->columns*cache_info->rows);
2074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078 + G e t P i x e l C a c h e P i x e l s %
2082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2084 % GetPixelCachePixels() returns the pixels associated with the specified image.
2086 % The format of the GetPixelCachePixels() method is:
2088 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2089 % ExceptionInfo *exception)
2091 % A description of each parameter follows:
2093 % o image: the image.
2095 % o length: the pixel cache length.
2097 % o exception: return any errors or warnings in this structure.
2100 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2101 ExceptionInfo *exception)
2104 *restrict cache_info;
2106 assert(image != (const Image *) NULL);
2107 assert(image->signature == MagickSignature);
2108 assert(image->cache != (Cache) NULL);
2109 assert(length != (MagickSizeType *) NULL);
2110 assert(exception != (ExceptionInfo *) NULL);
2111 assert(exception->signature == MagickSignature);
2112 cache_info=(CacheInfo *) image->cache;
2113 assert(cache_info->signature == MagickSignature);
2115 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2116 return((void *) NULL);
2117 *length=cache_info->length;
2118 return((void *) cache_info->pixels);
2122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2126 + 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 %
2130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2132 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2134 % The format of the GetPixelCacheStorageClass() method is:
2136 % ClassType GetPixelCacheStorageClass(Cache cache)
2138 % A description of each parameter follows:
2140 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2142 % o cache: the pixel cache.
2145 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2148 *restrict cache_info;
2150 assert(cache != (Cache) NULL);
2151 cache_info=(CacheInfo *) cache;
2152 assert(cache_info->signature == MagickSignature);
2153 if (cache_info->debug != MagickFalse)
2154 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2155 cache_info->filename);
2156 return(cache_info->storage_class);
2160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164 + G e t P i x e l C a c h e T i l e S i z e %
2168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2170 % GetPixelCacheTileSize() returns the pixel cache tile size.
2172 % The format of the GetPixelCacheTileSize() method is:
2174 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2177 % A description of each parameter follows:
2179 % o image: the image.
2181 % o width: the optimize cache tile width in pixels.
2183 % o height: the optimize cache tile height in pixels.
2186 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2190 *restrict cache_info;
2192 assert(image != (Image *) NULL);
2193 assert(image->signature == MagickSignature);
2194 if (image->debug != MagickFalse)
2195 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2196 cache_info=(CacheInfo *) image->cache;
2197 assert(cache_info->signature == MagickSignature);
2198 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2199 if (GetImagePixelCacheType(image) == DiskCache)
2200 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2209 + 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 %
2213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2216 % pixel cache. A virtual pixel is any pixel access that is outside the
2217 % boundaries of the image cache.
2219 % The format of the GetPixelCacheVirtualMethod() method is:
2221 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2223 % A description of each parameter follows:
2225 % o image: the image.
2228 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2231 *restrict cache_info;
2233 assert(image != (Image *) NULL);
2234 assert(image->signature == MagickSignature);
2235 assert(image->cache != (Cache) NULL);
2236 cache_info=(CacheInfo *) image->cache;
2237 assert(cache_info->signature == MagickSignature);
2238 return(cache_info->virtual_pixel_method);
2242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2246 + 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 %
2250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2252 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2253 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2255 % The format of the GetVirtualMetacontentFromCache() method is:
2257 % void *GetVirtualMetacontentFromCache(const Image *image)
2259 % A description of each parameter follows:
2261 % o image: the image.
2264 static const void *GetVirtualMetacontentFromCache(const Image *image)
2267 *restrict cache_info;
2270 id = GetOpenMPThreadId();
2273 *restrict metacontent;
2275 assert(image != (const Image *) NULL);
2276 assert(image->signature == MagickSignature);
2277 assert(image->cache != (Cache) NULL);
2278 cache_info=(CacheInfo *) image->cache;
2279 assert(cache_info->signature == MagickSignature);
2280 assert(id < (int) cache_info->number_threads);
2281 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2282 cache_info->nexus_info[id]);
2283 return(metacontent);
2287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2291 + 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 %
2295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2297 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2300 % The format of the GetVirtualMetacontentFromNexus() method is:
2302 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2303 % NexusInfo *nexus_info)
2305 % A description of each parameter follows:
2307 % o cache: the pixel cache.
2309 % o nexus_info: the cache nexus to return the meta-content.
2312 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2313 NexusInfo *restrict nexus_info)
2316 *restrict cache_info;
2318 assert(cache != (Cache) NULL);
2319 cache_info=(CacheInfo *) cache;
2320 assert(cache_info->signature == MagickSignature);
2321 if (cache_info->storage_class == UndefinedClass)
2322 return((void *) NULL);
2323 return(nexus_info->metacontent);
2327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2331 % G e t V i r t u a l M e t a c o n t e n t %
2335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2338 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2339 % returned if the meta-content are not available.
2341 % The format of the GetVirtualMetacontent() method is:
2343 % const void *GetVirtualMetacontent(const Image *image)
2345 % A description of each parameter follows:
2347 % o image: the image.
2350 MagickExport const void *GetVirtualMetacontent(const Image *image)
2353 *restrict cache_info;
2356 id = GetOpenMPThreadId();
2359 *restrict metacontent;
2361 assert(image != (const Image *) NULL);
2362 assert(image->signature == MagickSignature);
2363 assert(image->cache != (Cache) NULL);
2364 cache_info=(CacheInfo *) image->cache;
2365 assert(cache_info->signature == MagickSignature);
2366 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2367 if (metacontent != (void *) NULL)
2368 return(metacontent);
2369 assert(id < (int) cache_info->number_threads);
2370 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2371 cache_info->nexus_info[id]);
2372 return(metacontent);
2376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380 + 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 %
2384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2386 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2387 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2388 % is returned if the pixels are transferred, otherwise a NULL is returned.
2390 % The format of the GetVirtualPixelsFromNexus() method is:
2392 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2393 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2394 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2395 % ExceptionInfo *exception)
2397 % A description of each parameter follows:
2399 % o image: the image.
2401 % o virtual_pixel_method: the virtual pixel method.
2403 % o x,y,columns,rows: These values define the perimeter of a region of
2406 % o nexus_info: the cache nexus to acquire.
2408 % o exception: return any errors or warnings in this structure.
2415 0, 48, 12, 60, 3, 51, 15, 63,
2416 32, 16, 44, 28, 35, 19, 47, 31,
2417 8, 56, 4, 52, 11, 59, 7, 55,
2418 40, 24, 36, 20, 43, 27, 39, 23,
2419 2, 50, 14, 62, 1, 49, 13, 61,
2420 34, 18, 46, 30, 33, 17, 45, 29,
2421 10, 58, 6, 54, 9, 57, 5, 53,
2422 42, 26, 38, 22, 41, 25, 37, 21
2425 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2430 index=x+DitherMatrix[x & 0x07]-32L;
2433 if (index >= (ssize_t) columns)
2434 return((ssize_t) columns-1L);
2438 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2443 index=y+DitherMatrix[y & 0x07]-32L;
2446 if (index >= (ssize_t) rows)
2447 return((ssize_t) rows-1L);
2451 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2455 if (x >= (ssize_t) columns)
2456 return((ssize_t) (columns-1));
2460 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2464 if (y >= (ssize_t) rows)
2465 return((ssize_t) (rows-1));
2469 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2471 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2474 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2476 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2479 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2480 const size_t extent)
2486 Compute the remainder of dividing offset by extent. It returns not only
2487 the quotient (tile the offset falls in) but also the positive remainer
2488 within that tile such that 0 <= remainder < extent. This method is
2489 essentially a ldiv() using a floored modulo division rather than the
2490 normal default truncated modulo division.
2492 modulo.quotient=offset/(ssize_t) extent;
2495 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2499 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2500 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2501 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2502 ExceptionInfo *exception)
2505 *restrict cache_info;
2515 **restrict virtual_nexus;
2519 virtual_pixel[MaxPixelChannels];
2524 register const Quantum
2537 register unsigned char
2544 *restrict virtual_metacontent;
2549 assert(image != (const Image *) NULL);
2550 assert(image->signature == MagickSignature);
2551 assert(image->cache != (Cache) NULL);
2552 cache_info=(CacheInfo *) image->cache;
2553 assert(cache_info->signature == MagickSignature);
2554 if (cache_info->type == UndefinedCache)
2555 return((const Quantum *) NULL);
2558 region.width=columns;
2560 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2562 if (pixels == (Quantum *) NULL)
2563 return((const Quantum *) NULL);
2565 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2566 nexus_info->region.x;
2567 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2568 nexus_info->region.width-1L;
2569 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2570 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2571 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2572 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2578 Pixel request is inside cache extents.
2580 if (nexus_info->authentic_pixel_cache != MagickFalse)
2582 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2583 if (status == MagickFalse)
2584 return((const Quantum *) NULL);
2585 if (cache_info->metacontent_extent != 0)
2587 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2588 if (status == MagickFalse)
2589 return((const Quantum *) NULL);
2594 Pixel request is outside cache extents.
2596 s=(unsigned char *) nexus_info->metacontent;
2597 virtual_nexus=AcquirePixelCacheNexus(1);
2598 if (virtual_nexus == (NexusInfo **) NULL)
2600 if (virtual_nexus != (NexusInfo **) NULL)
2601 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2602 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2603 "UnableToGetCacheNexus","`%s'",image->filename);
2604 return((const Quantum *) NULL);
2606 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2607 sizeof(*virtual_pixel));
2608 virtual_metacontent=(void *) NULL;
2609 switch (virtual_pixel_method)
2611 case BackgroundVirtualPixelMethod:
2612 case BlackVirtualPixelMethod:
2613 case GrayVirtualPixelMethod:
2614 case TransparentVirtualPixelMethod:
2615 case MaskVirtualPixelMethod:
2616 case WhiteVirtualPixelMethod:
2617 case EdgeVirtualPixelMethod:
2618 case CheckerTileVirtualPixelMethod:
2619 case HorizontalTileVirtualPixelMethod:
2620 case VerticalTileVirtualPixelMethod:
2622 if (cache_info->metacontent_extent != 0)
2625 Acquire a metacontent buffer.
2627 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2628 cache_info->metacontent_extent);
2629 if (virtual_metacontent == (void *) NULL)
2631 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2632 (void) ThrowMagickException(exception,GetMagickModule(),
2633 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2634 return((const Quantum *) NULL);
2636 (void) ResetMagickMemory(virtual_metacontent,0,
2637 cache_info->metacontent_extent);
2639 switch (virtual_pixel_method)
2641 case BlackVirtualPixelMethod:
2643 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2644 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2645 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2648 case GrayVirtualPixelMethod:
2650 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2651 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2653 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2656 case TransparentVirtualPixelMethod:
2658 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2659 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2660 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2663 case MaskVirtualPixelMethod:
2664 case WhiteVirtualPixelMethod:
2666 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2667 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2668 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2673 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2675 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2677 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2679 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2681 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2691 for (v=0; v < (ssize_t) rows; v++)
2697 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2698 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2699 y_offset=EdgeY(y_offset,cache_info->rows);
2700 for (u=0; u < (ssize_t) columns; u+=length)
2706 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2707 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2708 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2716 Transfer a single pixel.
2718 length=(MagickSizeType) 1;
2719 switch (virtual_pixel_method)
2721 case EdgeVirtualPixelMethod:
2724 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2725 EdgeX(x_offset,cache_info->columns),
2726 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2728 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2731 case RandomVirtualPixelMethod:
2733 if (cache_info->random_info == (RandomInfo *) NULL)
2734 cache_info->random_info=AcquireRandomInfo();
2735 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2736 RandomX(cache_info->random_info,cache_info->columns),
2737 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2738 *virtual_nexus,exception);
2739 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2742 case DitherVirtualPixelMethod:
2744 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2745 DitherX(x_offset,cache_info->columns),
2746 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2748 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2751 case TileVirtualPixelMethod:
2753 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2754 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2755 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2756 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2758 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2761 case MirrorVirtualPixelMethod:
2763 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2764 if ((x_modulo.quotient & 0x01) == 1L)
2765 x_modulo.remainder=(ssize_t) cache_info->columns-
2766 x_modulo.remainder-1L;
2767 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2768 if ((y_modulo.quotient & 0x01) == 1L)
2769 y_modulo.remainder=(ssize_t) cache_info->rows-
2770 y_modulo.remainder-1L;
2771 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2772 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2774 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2777 case HorizontalTileEdgeVirtualPixelMethod:
2779 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2780 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2781 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2782 *virtual_nexus,exception);
2783 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2786 case VerticalTileEdgeVirtualPixelMethod:
2788 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2789 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2790 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2791 *virtual_nexus,exception);
2792 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2795 case BackgroundVirtualPixelMethod:
2796 case BlackVirtualPixelMethod:
2797 case GrayVirtualPixelMethod:
2798 case TransparentVirtualPixelMethod:
2799 case MaskVirtualPixelMethod:
2800 case WhiteVirtualPixelMethod:
2803 r=virtual_metacontent;
2806 case CheckerTileVirtualPixelMethod:
2808 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2809 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2810 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2813 r=virtual_metacontent;
2816 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2817 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2819 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2822 case HorizontalTileVirtualPixelMethod:
2824 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2827 r=virtual_metacontent;
2830 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2831 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2832 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2833 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2835 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2838 case VerticalTileVirtualPixelMethod:
2840 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2843 r=virtual_metacontent;
2846 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2847 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2848 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2849 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2851 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2855 if (p == (const Quantum *) NULL)
2857 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2859 q+=cache_info->number_channels;
2860 if ((s != (void *) NULL) && (r != (const void *) NULL))
2862 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2863 s+=cache_info->metacontent_extent;
2868 Transfer a run of pixels.
2870 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2871 (size_t) length,1UL,*virtual_nexus,exception);
2872 if (p == (const Quantum *) NULL)
2874 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2875 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2876 q+=length*cache_info->number_channels;
2877 if ((r != (void *) NULL) && (s != (const void *) NULL))
2879 (void) memcpy(s,r,(size_t) length);
2880 s+=length*cache_info->metacontent_extent;
2887 if (virtual_metacontent != (void *) NULL)
2888 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2889 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2898 + G e t V i r t u a l P i x e l C a c h e %
2902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2904 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2905 % cache as defined by the geometry parameters. A pointer to the pixels
2906 % is returned if the pixels are transferred, otherwise a NULL is returned.
2908 % The format of the GetVirtualPixelCache() method is:
2910 % const Quantum *GetVirtualPixelCache(const Image *image,
2911 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2912 % const ssize_t y,const size_t columns,const size_t rows,
2913 % ExceptionInfo *exception)
2915 % A description of each parameter follows:
2917 % o image: the image.
2919 % o virtual_pixel_method: the virtual pixel method.
2921 % o x,y,columns,rows: These values define the perimeter of a region of
2924 % o exception: return any errors or warnings in this structure.
2927 static const Quantum *GetVirtualPixelCache(const Image *image,
2928 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2929 const size_t columns,const size_t rows,ExceptionInfo *exception)
2932 *restrict cache_info;
2935 id = GetOpenMPThreadId();
2940 assert(image != (const Image *) NULL);
2941 assert(image->signature == MagickSignature);
2942 assert(image->cache != (Cache) NULL);
2943 cache_info=(CacheInfo *) image->cache;
2944 assert(cache_info->signature == MagickSignature);
2945 assert(id < (int) cache_info->number_threads);
2946 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2947 cache_info->nexus_info[id],exception);
2952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2956 % G e t V i r t u a l P i x e l Q u e u e %
2960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2963 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2965 % The format of the GetVirtualPixelQueue() method is:
2967 % const Quantum *GetVirtualPixelQueue(const Image image)
2969 % A description of each parameter follows:
2971 % o image: the image.
2974 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2977 *restrict cache_info;
2980 id = GetOpenMPThreadId();
2982 assert(image != (const Image *) NULL);
2983 assert(image->signature == MagickSignature);
2984 assert(image->cache != (Cache) NULL);
2985 cache_info=(CacheInfo *) image->cache;
2986 assert(cache_info->signature == MagickSignature);
2987 if (cache_info->methods.get_virtual_pixels_handler !=
2988 (GetVirtualPixelsHandler) NULL)
2989 return(cache_info->methods.get_virtual_pixels_handler(image));
2990 assert(id < (int) cache_info->number_threads);
2991 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2999 % G e t V i r t u a l P i x e l s %
3003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3005 % GetVirtualPixels() returns an immutable pixel region. If the
3006 % region is successfully accessed, a pointer to it is returned, otherwise
3007 % NULL is returned. The returned pointer may point to a temporary working
3008 % copy of the pixels or it may point to the original pixels in memory.
3009 % Performance is maximized if the selected region is part of one row, or one
3010 % or more full rows, since there is opportunity to access the pixels in-place
3011 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3012 % returned pointer must *never* be deallocated by the user.
3014 % Pixels accessed via the returned pointer represent a simple array of type
3015 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3016 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3017 % access the meta-content (of type void) corresponding to the the
3020 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3022 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3023 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3024 % GetCacheViewAuthenticPixels() instead.
3026 % The format of the GetVirtualPixels() method is:
3028 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3029 % const ssize_t y,const size_t columns,const size_t rows,
3030 % ExceptionInfo *exception)
3032 % A description of each parameter follows:
3034 % o image: the image.
3036 % o x,y,columns,rows: These values define the perimeter of a region of
3039 % o exception: return any errors or warnings in this structure.
3042 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3043 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3044 ExceptionInfo *exception)
3047 *restrict cache_info;
3050 id = GetOpenMPThreadId();
3055 assert(image != (const Image *) NULL);
3056 assert(image->signature == MagickSignature);
3057 assert(image->cache != (Cache) NULL);
3058 cache_info=(CacheInfo *) image->cache;
3059 assert(cache_info->signature == MagickSignature);
3060 if (cache_info->methods.get_virtual_pixel_handler !=
3061 (GetVirtualPixelHandler) NULL)
3062 return(cache_info->methods.get_virtual_pixel_handler(image,
3063 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3064 assert(id < (int) cache_info->number_threads);
3065 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3066 columns,rows,cache_info->nexus_info[id],exception);
3071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3075 + 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 %
3079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3081 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3082 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3084 % The format of the GetVirtualPixelsCache() method is:
3086 % Quantum *GetVirtualPixelsCache(const Image *image)
3088 % A description of each parameter follows:
3090 % o image: the image.
3093 static const Quantum *GetVirtualPixelsCache(const Image *image)
3096 *restrict cache_info;
3099 id = GetOpenMPThreadId();
3101 assert(image != (const Image *) NULL);
3102 assert(image->signature == MagickSignature);
3103 assert(image->cache != (Cache) NULL);
3104 cache_info=(CacheInfo *) image->cache;
3105 assert(cache_info->signature == MagickSignature);
3106 assert(id < (int) cache_info->number_threads);
3107 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3115 + G e t V i r t u a l P i x e l s N e x u s %
3119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3121 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3124 % The format of the GetVirtualPixelsNexus() method is:
3126 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3127 % NexusInfo *nexus_info)
3129 % A description of each parameter follows:
3131 % o cache: the pixel cache.
3133 % o nexus_info: the cache nexus to return the colormap pixels.
3136 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3137 NexusInfo *restrict nexus_info)
3140 *restrict cache_info;
3142 assert(cache != (Cache) NULL);
3143 cache_info=(CacheInfo *) cache;
3144 assert(cache_info->signature == MagickSignature);
3145 if (cache_info->storage_class == UndefinedClass)
3146 return((Quantum *) NULL);
3147 return((const Quantum *) nexus_info->pixels);
3151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3155 + O p e n P i x e l C a c h e %
3159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3161 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3162 % dimensions, allocating space for the image pixels and optionally the
3163 % metacontent, and memory mapping the cache if it is disk based. The cache
3164 % nexus array is initialized as well.
3166 % The format of the OpenPixelCache() method is:
3168 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3169 % ExceptionInfo *exception)
3171 % A description of each parameter follows:
3173 % o image: the image.
3175 % o mode: ReadMode, WriteMode, or IOMode.
3177 % o exception: return any errors or warnings in this structure.
3181 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3183 cache_info->mapped=MagickFalse;
3184 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3185 (size_t) cache_info->length));
3186 if (cache_info->pixels == (Quantum *) NULL)
3188 cache_info->mapped=MagickTrue;
3189 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3190 cache_info->length);
3194 #if defined(__cplusplus) || defined(c_plusplus)
3199 static void CacheSignalHandler(int status)
3201 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3205 #if defined(__cplusplus) || defined(c_plusplus)
3209 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3216 Open pixel cache on disk.
3218 if (cache_info->file != -1)
3219 return(MagickTrue); /* cache already open */
3220 if (*cache_info->cache_filename == '\0')
3221 file=AcquireUniqueFileResource(cache_info->cache_filename);
3227 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3232 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3233 O_BINARY | O_EXCL,S_MODE);
3235 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3241 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3244 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3249 return(MagickFalse);
3250 (void) AcquireMagickResource(FileResource,1);
3251 cache_info->file=file;
3252 cache_info->mode=mode;
3256 static inline MagickOffsetType WritePixelCacheRegion(
3257 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3258 const MagickSizeType length,const unsigned char *restrict buffer)
3260 register MagickOffsetType
3266 #if !defined(MAGICKCORE_HAVE_PWRITE)
3267 LockSemaphoreInfo(cache_info->file_semaphore);
3268 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3270 UnlockSemaphoreInfo(cache_info->file_semaphore);
3271 return((MagickOffsetType) -1);
3275 for (i=0; i < (MagickOffsetType) length; i+=count)
3277 #if !defined(MAGICKCORE_HAVE_PWRITE)
3278 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3279 (MagickSizeType) SSIZE_MAX));
3281 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3282 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3291 #if !defined(MAGICKCORE_HAVE_PREAD)
3292 UnlockSemaphoreInfo(cache_info->file_semaphore);
3297 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3300 *restrict cache_info;
3307 cache_info=(CacheInfo *) image->cache;
3308 if (image->debug != MagickFalse)
3311 format[MaxTextExtent],
3312 message[MaxTextExtent];
3314 (void) FormatMagickSize(length,MagickFalse,format);
3315 (void) FormatLocaleString(message,MaxTextExtent,
3316 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3317 cache_info->cache_filename,cache_info->file,format);
3318 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3320 if (length != (MagickSizeType) ((MagickOffsetType) length))
3321 return(MagickFalse);
3322 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3324 return(MagickFalse);
3325 if ((MagickSizeType) offset >= length)
3327 extent=(MagickOffsetType) length-1;
3328 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3329 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3330 if (cache_info->synchronize != MagickFalse)
3335 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3337 return(MagickFalse);
3341 (void) signal(SIGBUS,CacheSignalHandler);
3343 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3346 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3347 ExceptionInfo *exception)
3350 *restrict cache_info,
3354 format[MaxTextExtent],
3355 message[MaxTextExtent];
3371 assert(image != (const Image *) NULL);
3372 assert(image->signature == MagickSignature);
3373 assert(image->cache != (Cache) NULL);
3374 if (image->debug != MagickFalse)
3375 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3376 if ((image->columns == 0) || (image->rows == 0))
3377 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3378 cache_info=(CacheInfo *) image->cache;
3379 assert(cache_info->signature == MagickSignature);
3380 source_info=(*cache_info);
3381 source_info.file=(-1);
3382 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3383 image->filename,(double) GetImageIndexInList(image));
3384 cache_info->storage_class=image->storage_class;
3385 cache_info->colorspace=image->colorspace;
3386 cache_info->alpha_trait=image->alpha_trait;
3387 cache_info->read_mask=image->read_mask;
3388 cache_info->write_mask=image->write_mask;
3389 cache_info->rows=image->rows;
3390 cache_info->columns=image->columns;
3391 InitializePixelChannelMap(image);
3392 cache_info->number_channels=GetPixelChannels(image);
3393 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3394 sizeof(*image->channel_map));
3395 cache_info->metacontent_extent=image->metacontent_extent;
3396 cache_info->mode=mode;
3397 if (image->ping != MagickFalse)
3399 cache_info->type=PingCache;
3400 cache_info->pixels=(Quantum *) NULL;
3401 cache_info->metacontent=(void *) NULL;
3402 cache_info->length=0;
3405 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3406 packet_size=cache_info->number_channels*sizeof(Quantum);
3407 if (image->metacontent_extent != 0)
3408 packet_size+=cache_info->metacontent_extent;
3409 length=number_pixels*packet_size;
3410 columns=(size_t) (length/cache_info->rows/packet_size);
3411 if (cache_info->columns != columns)
3412 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3414 cache_info->length=length;
3415 status=AcquireMagickResource(AreaResource,cache_info->length);
3416 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3417 cache_info->metacontent_extent);
3418 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3420 status=AcquireMagickResource(MemoryResource,cache_info->length);
3421 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3422 (cache_info->type == MemoryCache))
3424 AllocatePixelCachePixels(cache_info);
3425 if (cache_info->pixels == (Quantum *) NULL)
3426 cache_info->pixels=source_info.pixels;
3430 Create memory pixel cache.
3433 cache_info->type=MemoryCache;
3434 cache_info->metacontent=(void *) NULL;
3435 if (cache_info->metacontent_extent != 0)
3436 cache_info->metacontent=(void *) (cache_info->pixels+
3437 number_pixels*cache_info->number_channels);
3438 if ((source_info.storage_class != UndefinedClass) &&
3441 status=ClonePixelCacheRepository(cache_info,&source_info,
3443 RelinquishPixelCachePixels(&source_info);
3445 if (image->debug != MagickFalse)
3447 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3448 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3450 (void) FormatLocaleString(message,MaxTextExtent,
3451 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3452 cache_info->filename,cache_info->mapped != MagickFalse ?
3453 "Anonymous" : "Heap",type,(double) cache_info->columns,
3454 (double) cache_info->rows,(double)
3455 cache_info->number_channels,format);
3456 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3462 RelinquishMagickResource(MemoryResource,cache_info->length);
3465 Create pixel cache on disk.
3467 status=AcquireMagickResource(DiskResource,cache_info->length);
3468 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3473 if (cache_info->type == DistributedCache)
3474 RelinquishMagickResource(DiskResource,cache_info->length);
3475 server_info=AcquireDistributeCacheInfo(exception);
3476 if (server_info != (DistributeCacheInfo *) NULL)
3478 status=OpenDistributePixelCache(server_info,image);
3479 if (status == MagickFalse)
3481 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3482 GetDistributeCacheHostname(server_info));
3483 server_info=DestroyDistributeCacheInfo(server_info);
3488 Create a distributed pixel cache.
3490 cache_info->type=DistributedCache;
3491 cache_info->server_info=server_info;
3492 (void) FormatLocaleString(cache_info->cache_filename,
3493 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3494 (DistributeCacheInfo *) cache_info->server_info),
3495 GetDistributeCachePort((DistributeCacheInfo *)
3496 cache_info->server_info));
3497 if ((source_info.storage_class != UndefinedClass) &&
3500 status=ClonePixelCacheRepository(cache_info,&source_info,
3502 RelinquishPixelCachePixels(&source_info);
3504 if (image->debug != MagickFalse)
3506 (void) FormatMagickSize(cache_info->length,MagickFalse,
3508 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3510 (void) FormatLocaleString(message,MaxTextExtent,
3511 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3512 cache_info->filename,cache_info->cache_filename,
3513 GetDistributeCacheFile((DistributeCacheInfo *)
3514 cache_info->server_info),type,(double) cache_info->columns,
3515 (double) cache_info->rows,(double)
3516 cache_info->number_channels,format);
3517 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3523 RelinquishMagickResource(DiskResource,cache_info->length);
3524 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3525 "CacheResourcesExhausted","`%s'",image->filename);
3526 return(MagickFalse);
3528 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3530 (void) ClosePixelCacheOnDisk(cache_info);
3531 *cache_info->cache_filename='\0';
3533 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3535 RelinquishMagickResource(DiskResource,cache_info->length);
3536 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3538 return(MagickFalse);
3540 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3541 cache_info->length);
3542 if (status == MagickFalse)
3544 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3546 return(MagickFalse);
3548 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3549 cache_info->metacontent_extent);
3550 if (length != (MagickSizeType) ((size_t) length))
3551 cache_info->type=DiskCache;
3554 status=AcquireMagickResource(MapResource,cache_info->length);
3555 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3556 (cache_info->type != MemoryCache))
3557 cache_info->type=DiskCache;
3560 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3561 cache_info->offset,(size_t) cache_info->length);
3562 if (cache_info->pixels == (Quantum *) NULL)
3564 cache_info->type=DiskCache;
3565 cache_info->pixels=source_info.pixels;
3570 Create file-backed memory-mapped pixel cache.
3573 (void) ClosePixelCacheOnDisk(cache_info);
3574 cache_info->type=MapCache;
3575 cache_info->mapped=MagickTrue;
3576 cache_info->metacontent=(void *) NULL;
3577 if (cache_info->metacontent_extent != 0)
3578 cache_info->metacontent=(void *) (cache_info->pixels+
3579 number_pixels*cache_info->number_channels);
3580 if ((source_info.storage_class != UndefinedClass) &&
3583 status=ClonePixelCacheRepository(cache_info,&source_info,
3585 RelinquishPixelCachePixels(&source_info);
3587 if (image->debug != MagickFalse)
3589 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3590 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3592 (void) FormatLocaleString(message,MaxTextExtent,
3593 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3594 cache_info->filename,cache_info->cache_filename,
3595 cache_info->file,type,(double) cache_info->columns,(double)
3596 cache_info->rows,(double) cache_info->number_channels,
3598 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3604 RelinquishMagickResource(MapResource,cache_info->length);
3607 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3609 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3610 RelinquishPixelCachePixels(&source_info);
3612 if (image->debug != MagickFalse)
3614 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3615 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3617 (void) FormatLocaleString(message,MaxTextExtent,
3618 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3619 cache_info->cache_filename,cache_info->file,type,(double)
3620 cache_info->columns,(double) cache_info->rows,(double)
3621 cache_info->number_channels,format);
3622 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3632 + P e r s i s t P i x e l C a c h e %
3636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3638 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3639 % persistent pixel cache is one that resides on disk and is not destroyed
3640 % when the program exits.
3642 % The format of the PersistPixelCache() method is:
3644 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3645 % const MagickBooleanType attach,MagickOffsetType *offset,
3646 % ExceptionInfo *exception)
3648 % A description of each parameter follows:
3650 % o image: the image.
3652 % o filename: the persistent pixel cache filename.
3654 % o attach: A value other than zero initializes the persistent pixel cache.
3656 % o initialize: A value other than zero initializes the persistent pixel
3659 % o offset: the offset in the persistent cache to store pixels.
3661 % o exception: return any errors or warnings in this structure.
3664 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3665 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3666 ExceptionInfo *exception)
3669 *restrict cache_info,
3670 *restrict clone_info;
3681 assert(image != (Image *) NULL);
3682 assert(image->signature == MagickSignature);
3683 if (image->debug != MagickFalse)
3684 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3685 assert(image->cache != (void *) NULL);
3686 assert(filename != (const char *) NULL);
3687 assert(offset != (MagickOffsetType *) NULL);
3688 page_size=GetMagickPageSize();
3689 cache_info=(CacheInfo *) image->cache;
3690 assert(cache_info->signature == MagickSignature);
3691 if (attach != MagickFalse)
3694 Attach existing persistent pixel cache.
3696 if (image->debug != MagickFalse)
3697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3698 "attach persistent cache");
3699 (void) CopyMagickString(cache_info->cache_filename,filename,
3701 cache_info->type=DiskCache;
3702 cache_info->offset=(*offset);
3703 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3704 return(MagickFalse);
3705 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3708 if ((cache_info->mode != ReadMode) &&
3709 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3710 (cache_info->reference_count == 1))
3712 LockSemaphoreInfo(cache_info->semaphore);
3713 if ((cache_info->mode != ReadMode) &&
3714 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3715 (cache_info->reference_count == 1))
3721 Usurp existing persistent pixel cache.
3723 status=rename_utf8(cache_info->cache_filename,filename);
3726 (void) CopyMagickString(cache_info->cache_filename,filename,
3728 *offset+=cache_info->length+page_size-(cache_info->length %
3730 UnlockSemaphoreInfo(cache_info->semaphore);
3731 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3732 if (image->debug != MagickFalse)
3733 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3734 "Usurp resident persistent cache");
3738 UnlockSemaphoreInfo(cache_info->semaphore);
3741 Clone persistent pixel cache.
3743 clone_image=(*image);
3744 clone_info=(CacheInfo *) clone_image.cache;
3745 image->cache=ClonePixelCache(cache_info);
3746 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3747 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3748 cache_info->type=DiskCache;
3749 cache_info->offset=(*offset);
3750 cache_info=(CacheInfo *) image->cache;
3751 status=OpenPixelCache(image,IOMode,exception);
3752 if (status != MagickFalse)
3753 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3754 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3755 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3764 + 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 %
3768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3770 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3771 % defined by the region rectangle and returns a pointer to the region. This
3772 % region is subsequently transferred from the pixel cache with
3773 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3774 % pixels are transferred, otherwise a NULL is returned.
3776 % The format of the QueueAuthenticPixelCacheNexus() method is:
3778 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3779 % const ssize_t y,const size_t columns,const size_t rows,
3780 % const MagickBooleanType clone,NexusInfo *nexus_info,
3781 % ExceptionInfo *exception)
3783 % A description of each parameter follows:
3785 % o image: the image.
3787 % o x,y,columns,rows: These values define the perimeter of a region of
3790 % o nexus_info: the cache nexus to set.
3792 % o clone: clone the pixel cache.
3794 % o exception: return any errors or warnings in this structure.
3797 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3798 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3799 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3802 *restrict cache_info;
3817 Validate pixel cache geometry.
3819 assert(image != (const Image *) NULL);
3820 assert(image->signature == MagickSignature);
3821 assert(image->cache != (Cache) NULL);
3822 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3823 if (cache_info == (Cache) NULL)
3824 return((Quantum *) NULL);
3825 assert(cache_info->signature == MagickSignature);
3826 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3827 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3828 (y >= (ssize_t) cache_info->rows))
3830 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3831 "PixelsAreNotAuthentic","`%s'",image->filename);
3832 return((Quantum *) NULL);
3834 offset=(MagickOffsetType) y*cache_info->columns+x;
3836 return((Quantum *) NULL);
3837 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3838 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3839 if ((MagickSizeType) offset >= number_pixels)
3840 return((Quantum *) NULL);
3846 region.width=columns;
3848 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3858 + 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 %
3862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3864 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3865 % defined by the region rectangle and returns a pointer to the region. This
3866 % region is subsequently transferred from the pixel cache with
3867 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3868 % pixels are transferred, otherwise a NULL is returned.
3870 % The format of the QueueAuthenticPixelsCache() method is:
3872 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3873 % const ssize_t y,const size_t columns,const size_t rows,
3874 % ExceptionInfo *exception)
3876 % A description of each parameter follows:
3878 % o image: the image.
3880 % o x,y,columns,rows: These values define the perimeter of a region of
3883 % o exception: return any errors or warnings in this structure.
3886 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3887 const ssize_t y,const size_t columns,const size_t rows,
3888 ExceptionInfo *exception)
3891 *restrict cache_info;
3894 id = GetOpenMPThreadId();
3899 assert(image != (const Image *) NULL);
3900 assert(image->signature == MagickSignature);
3901 assert(image->cache != (Cache) NULL);
3902 cache_info=(CacheInfo *) image->cache;
3903 assert(cache_info->signature == MagickSignature);
3904 assert(id < (int) cache_info->number_threads);
3905 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3906 cache_info->nexus_info[id],exception);
3911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3915 % Q u e u e A u t h e n t i c P i x e l s %
3919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3921 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3922 % successfully initialized a pointer to a Quantum array representing the
3923 % region is returned, otherwise NULL is returned. The returned pointer may
3924 % point to a temporary working buffer for the pixels or it may point to the
3925 % final location of the pixels in memory.
3927 % Write-only access means that any existing pixel values corresponding to
3928 % the region are ignored. This is useful if the initial image is being
3929 % created from scratch, or if the existing pixel values are to be
3930 % completely replaced without need to refer to their pre-existing values.
3931 % The application is free to read and write the pixel buffer returned by
3932 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3933 % initialize the pixel array values. Initializing pixel array values is the
3934 % application's responsibility.
3936 % Performance is maximized if the selected region is part of one row, or
3937 % one or more full rows, since then there is opportunity to access the
3938 % pixels in-place (without a copy) if the image is in memory, or in a
3939 % memory-mapped file. The returned pointer must *never* be deallocated
3942 % Pixels accessed via the returned pointer represent a simple array of type
3943 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3944 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3945 % obtain the meta-content (of type void) corresponding to the region.
3946 % Once the Quantum (and/or Quantum) array has been updated, the
3947 % changes must be saved back to the underlying image using
3948 % SyncAuthenticPixels() or they may be lost.
3950 % The format of the QueueAuthenticPixels() method is:
3952 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3953 % const ssize_t y,const size_t columns,const size_t rows,
3954 % ExceptionInfo *exception)
3956 % A description of each parameter follows:
3958 % o image: the image.
3960 % o x,y,columns,rows: These values define the perimeter of a region of
3963 % o exception: return any errors or warnings in this structure.
3966 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3967 const ssize_t y,const size_t columns,const size_t rows,
3968 ExceptionInfo *exception)
3971 *restrict cache_info;
3974 id = GetOpenMPThreadId();
3979 assert(image != (Image *) NULL);
3980 assert(image->signature == MagickSignature);
3981 assert(image->cache != (Cache) NULL);
3982 cache_info=(CacheInfo *) image->cache;
3983 assert(cache_info->signature == MagickSignature);
3984 if (cache_info->methods.queue_authentic_pixels_handler !=
3985 (QueueAuthenticPixelsHandler) NULL)
3987 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3988 columns,rows,exception);
3991 assert(id < (int) cache_info->number_threads);
3992 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3993 cache_info->nexus_info[id],exception);
3998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4002 + 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 %
4006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4008 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4011 % The format of the ReadPixelCacheMetacontent() method is:
4013 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4014 % NexusInfo *nexus_info,ExceptionInfo *exception)
4016 % A description of each parameter follows:
4018 % o cache_info: the pixel cache.
4020 % o nexus_info: the cache nexus to read the metacontent.
4022 % o exception: return any errors or warnings in this structure.
4026 static inline MagickOffsetType ReadPixelCacheRegion(
4027 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4028 const MagickSizeType length,unsigned char *restrict buffer)
4030 register MagickOffsetType
4036 #if !defined(MAGICKCORE_HAVE_PREAD)
4037 LockSemaphoreInfo(cache_info->file_semaphore);
4038 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4040 UnlockSemaphoreInfo(cache_info->file_semaphore);
4041 return((MagickOffsetType) -1);
4045 for (i=0; i < (MagickOffsetType) length; i+=count)
4047 #if !defined(MAGICKCORE_HAVE_PREAD)
4048 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4049 (MagickSizeType) SSIZE_MAX));
4051 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4052 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4061 #if !defined(MAGICKCORE_HAVE_PREAD)
4062 UnlockSemaphoreInfo(cache_info->file_semaphore);
4067 static MagickBooleanType ReadPixelCacheMetacontent(
4068 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4069 ExceptionInfo *exception)
4082 register unsigned char
4088 if (cache_info->metacontent_extent == 0)
4089 return(MagickFalse);
4090 if (nexus_info->authentic_pixel_cache != MagickFalse)
4092 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4093 nexus_info->region.x;
4094 length=(MagickSizeType) nexus_info->region.width*
4095 cache_info->metacontent_extent;
4096 extent=length*nexus_info->region.height;
4097 rows=nexus_info->region.height;
4099 q=(unsigned char *) nexus_info->metacontent;
4100 switch (cache_info->type)
4105 register unsigned char
4109 Read meta-content from memory.
4111 if ((cache_info->columns == nexus_info->region.width) &&
4112 (extent == (MagickSizeType) ((size_t) extent)))
4117 p=(unsigned char *) cache_info->metacontent+offset*
4118 cache_info->metacontent_extent;
4119 for (y=0; y < (ssize_t) rows; y++)
4121 (void) memcpy(q,p,(size_t) length);
4122 p+=cache_info->metacontent_extent*cache_info->columns;
4123 q+=cache_info->metacontent_extent*nexus_info->region.width;
4130 Read meta content from disk.
4132 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4134 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4135 cache_info->cache_filename);
4136 return(MagickFalse);
4138 if ((cache_info->columns == nexus_info->region.width) &&
4139 (extent <= MagickMaxBufferExtent))
4144 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4145 for (y=0; y < (ssize_t) rows; y++)
4147 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4148 cache_info->number_channels*sizeof(Quantum)+offset*
4149 cache_info->metacontent_extent,length,(unsigned char *) q);
4150 if (count != (MagickOffsetType) length)
4152 offset+=cache_info->columns;
4153 q+=cache_info->metacontent_extent*nexus_info->region.width;
4155 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4156 (void) ClosePixelCacheOnDisk(cache_info);
4159 case DistributedCache:
4165 Read metacontent from distributed cache.
4167 LockSemaphoreInfo(cache_info->file_semaphore);
4168 region=nexus_info->region;
4169 if ((cache_info->columns != nexus_info->region.width) ||
4170 (extent > MagickMaxBufferExtent))
4177 for (y=0; y < (ssize_t) rows; y++)
4179 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4180 cache_info->server_info,®ion,length,(unsigned char *) q);
4181 if (count != (MagickOffsetType) length)
4183 q+=cache_info->metacontent_extent*nexus_info->region.width;
4186 UnlockSemaphoreInfo(cache_info->file_semaphore);
4192 if (y < (ssize_t) rows)
4194 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4195 cache_info->cache_filename);
4196 return(MagickFalse);
4198 if ((cache_info->debug != MagickFalse) &&
4199 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4200 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4201 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4202 nexus_info->region.width,(double) nexus_info->region.height,(double)
4203 nexus_info->region.x,(double) nexus_info->region.y);
4208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4212 + R e a d P i x e l C a c h e P i x e l s %
4216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4218 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4221 % The format of the ReadPixelCachePixels() method is:
4223 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4224 % NexusInfo *nexus_info,ExceptionInfo *exception)
4226 % A description of each parameter follows:
4228 % o cache_info: the pixel cache.
4230 % o nexus_info: the cache nexus to read the pixels.
4232 % o exception: return any errors or warnings in this structure.
4235 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4236 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4255 if (nexus_info->authentic_pixel_cache != MagickFalse)
4257 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4258 nexus_info->region.x;
4259 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4261 extent=length*nexus_info->region.height;
4262 rows=nexus_info->region.height;
4264 q=nexus_info->pixels;
4265 switch (cache_info->type)
4274 Read pixels from memory.
4276 if ((cache_info->columns == nexus_info->region.width) &&
4277 (extent == (MagickSizeType) ((size_t) extent)))
4282 p=cache_info->pixels+offset*cache_info->number_channels;
4283 for (y=0; y < (ssize_t) rows; y++)
4285 (void) memcpy(q,p,(size_t) length);
4286 p+=cache_info->number_channels*cache_info->columns;
4287 q+=cache_info->number_channels*nexus_info->region.width;
4294 Read pixels from disk.
4296 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4298 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4299 cache_info->cache_filename);
4300 return(MagickFalse);
4302 if ((cache_info->columns == nexus_info->region.width) &&
4303 (extent <= MagickMaxBufferExtent))
4308 for (y=0; y < (ssize_t) rows; y++)
4310 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4311 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4312 if (count != (MagickOffsetType) length)
4314 offset+=cache_info->columns;
4315 q+=cache_info->number_channels*nexus_info->region.width;
4317 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4318 (void) ClosePixelCacheOnDisk(cache_info);
4321 case DistributedCache:
4327 Read pixels from distributed cache.
4329 LockSemaphoreInfo(cache_info->file_semaphore);
4330 region=nexus_info->region;
4331 if ((cache_info->columns != nexus_info->region.width) ||
4332 (extent > MagickMaxBufferExtent))
4339 for (y=0; y < (ssize_t) rows; y++)
4341 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4342 cache_info->server_info,®ion,length,(unsigned char *) q);
4343 if (count != (MagickOffsetType) length)
4345 q+=cache_info->number_channels*nexus_info->region.width;
4348 UnlockSemaphoreInfo(cache_info->file_semaphore);
4354 if (y < (ssize_t) rows)
4356 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4357 cache_info->cache_filename);
4358 return(MagickFalse);
4360 if ((cache_info->debug != MagickFalse) &&
4361 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4362 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4363 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4364 nexus_info->region.width,(double) nexus_info->region.height,(double)
4365 nexus_info->region.x,(double) nexus_info->region.y);
4370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4374 + R e f e r e n c e P i x e l C a c h e %
4378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4380 % ReferencePixelCache() increments the reference count associated with the
4381 % pixel cache returning a pointer to the cache.
4383 % The format of the ReferencePixelCache method is:
4385 % Cache ReferencePixelCache(Cache cache_info)
4387 % A description of each parameter follows:
4389 % o cache_info: the pixel cache.
4392 MagickPrivate Cache ReferencePixelCache(Cache cache)
4395 *restrict cache_info;
4397 assert(cache != (Cache *) NULL);
4398 cache_info=(CacheInfo *) cache;
4399 assert(cache_info->signature == MagickSignature);
4400 LockSemaphoreInfo(cache_info->semaphore);
4401 cache_info->reference_count++;
4402 UnlockSemaphoreInfo(cache_info->semaphore);
4407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4411 + S e t P i x e l C a c h e M e t h o d s %
4415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4417 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4419 % The format of the SetPixelCacheMethods() method is:
4421 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4423 % A description of each parameter follows:
4425 % o cache: the pixel cache.
4427 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4430 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4433 *restrict cache_info;
4435 GetOneAuthenticPixelFromHandler
4436 get_one_authentic_pixel_from_handler;
4438 GetOneVirtualPixelFromHandler
4439 get_one_virtual_pixel_from_handler;
4442 Set cache pixel methods.
4444 assert(cache != (Cache) NULL);
4445 assert(cache_methods != (CacheMethods *) NULL);
4446 cache_info=(CacheInfo *) cache;
4447 assert(cache_info->signature == MagickSignature);
4448 if (cache_info->debug != MagickFalse)
4449 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4450 cache_info->filename);
4451 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4452 cache_info->methods.get_virtual_pixel_handler=
4453 cache_methods->get_virtual_pixel_handler;
4454 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4455 cache_info->methods.destroy_pixel_handler=
4456 cache_methods->destroy_pixel_handler;
4457 if (cache_methods->get_virtual_metacontent_from_handler !=
4458 (GetVirtualMetacontentFromHandler) NULL)
4459 cache_info->methods.get_virtual_metacontent_from_handler=
4460 cache_methods->get_virtual_metacontent_from_handler;
4461 if (cache_methods->get_authentic_pixels_handler !=
4462 (GetAuthenticPixelsHandler) NULL)
4463 cache_info->methods.get_authentic_pixels_handler=
4464 cache_methods->get_authentic_pixels_handler;
4465 if (cache_methods->queue_authentic_pixels_handler !=
4466 (QueueAuthenticPixelsHandler) NULL)
4467 cache_info->methods.queue_authentic_pixels_handler=
4468 cache_methods->queue_authentic_pixels_handler;
4469 if (cache_methods->sync_authentic_pixels_handler !=
4470 (SyncAuthenticPixelsHandler) NULL)
4471 cache_info->methods.sync_authentic_pixels_handler=
4472 cache_methods->sync_authentic_pixels_handler;
4473 if (cache_methods->get_authentic_pixels_from_handler !=
4474 (GetAuthenticPixelsFromHandler) NULL)
4475 cache_info->methods.get_authentic_pixels_from_handler=
4476 cache_methods->get_authentic_pixels_from_handler;
4477 if (cache_methods->get_authentic_metacontent_from_handler !=
4478 (GetAuthenticMetacontentFromHandler) NULL)
4479 cache_info->methods.get_authentic_metacontent_from_handler=
4480 cache_methods->get_authentic_metacontent_from_handler;
4481 get_one_virtual_pixel_from_handler=
4482 cache_info->methods.get_one_virtual_pixel_from_handler;
4483 if (get_one_virtual_pixel_from_handler !=
4484 (GetOneVirtualPixelFromHandler) NULL)
4485 cache_info->methods.get_one_virtual_pixel_from_handler=
4486 cache_methods->get_one_virtual_pixel_from_handler;
4487 get_one_authentic_pixel_from_handler=
4488 cache_methods->get_one_authentic_pixel_from_handler;
4489 if (get_one_authentic_pixel_from_handler !=
4490 (GetOneAuthenticPixelFromHandler) NULL)
4491 cache_info->methods.get_one_authentic_pixel_from_handler=
4492 cache_methods->get_one_authentic_pixel_from_handler;
4496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4500 + S e t P i x e l C a c h e N e x u s P i x e l s %
4504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4506 % SetPixelCacheNexusPixels() defines the region of the cache for the
4507 % specified cache nexus.
4509 % The format of the SetPixelCacheNexusPixels() method is:
4511 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4512 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4513 % ExceptionInfo *exception)
4515 % A description of each parameter follows:
4517 % o cache_info: the pixel cache.
4519 % o mode: ReadMode, WriteMode, or IOMode.
4521 % o region: A pointer to the RectangleInfo structure that defines the
4522 % region of this particular cache nexus.
4524 % o nexus_info: the cache nexus to set.
4526 % o exception: return any errors or warnings in this structure.
4530 static inline MagickBooleanType AcquireCacheNexusPixels(
4531 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4532 ExceptionInfo *exception)
4534 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4535 return(MagickFalse);
4536 nexus_info->mapped=MagickFalse;
4537 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4538 (size_t) nexus_info->length));
4539 if (nexus_info->cache == (Quantum *) NULL)
4541 nexus_info->mapped=MagickTrue;
4542 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4543 nexus_info->length);
4545 if (nexus_info->cache == (Quantum *) NULL)
4547 (void) ThrowMagickException(exception,GetMagickModule(),
4548 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4549 cache_info->filename);
4550 return(MagickFalse);
4555 static inline MagickBooleanType IsPixelCacheAuthentic(
4556 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4565 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4567 if (cache_info->type == PingCache)
4569 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4570 nexus_info->region.x;
4571 status=nexus_info->pixels == (cache_info->pixels+offset*
4572 cache_info->number_channels) ? MagickTrue : MagickFalse;
4576 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4579 if (mode == ReadMode)
4581 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4584 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4587 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4588 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4589 ExceptionInfo *exception)
4598 assert(cache_info != (const CacheInfo *) NULL);
4599 assert(cache_info->signature == MagickSignature);
4600 if (cache_info->type == UndefinedCache)
4601 return((Quantum *) NULL);
4602 nexus_info->region=(*region);
4603 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4609 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4610 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4611 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4612 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4613 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4614 ((nexus_info->region.width == cache_info->columns) ||
4615 ((nexus_info->region.width % cache_info->columns) == 0)))))
4621 Pixels are accessed directly from memory.
4623 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4624 nexus_info->region.x;
4625 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4627 nexus_info->metacontent=(void *) NULL;
4628 if (cache_info->metacontent_extent != 0)
4629 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4630 offset*cache_info->metacontent_extent;
4631 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4632 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4634 return(nexus_info->pixels);
4638 Pixels are stored in a staging region until they are synced to the cache.
4640 number_pixels=(MagickSizeType) nexus_info->region.width*
4641 nexus_info->region.height;
4642 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4643 if (cache_info->metacontent_extent != 0)
4644 length+=number_pixels*cache_info->metacontent_extent;
4645 if (nexus_info->cache == (Quantum *) NULL)
4647 nexus_info->length=length;
4648 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4649 if (status == MagickFalse)
4651 nexus_info->length=0;
4652 return((Quantum *) NULL);
4656 if (nexus_info->length < length)
4658 RelinquishCacheNexusPixels(nexus_info);
4659 nexus_info->length=length;
4660 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4661 if (status == MagickFalse)
4663 nexus_info->length=0;
4664 return((Quantum *) NULL);
4667 nexus_info->pixels=nexus_info->cache;
4668 nexus_info->metacontent=(void *) NULL;
4669 if (cache_info->metacontent_extent != 0)
4670 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4671 cache_info->number_channels);
4672 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4673 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4675 return(nexus_info->pixels);
4679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4683 % 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 %
4687 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4689 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4690 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4691 % access that is outside the boundaries of the image cache.
4693 % The format of the SetPixelCacheVirtualMethod() method is:
4695 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4696 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4698 % A description of each parameter follows:
4700 % o image: the image.
4702 % o virtual_pixel_method: choose the type of virtual pixel.
4704 % o exception: return any errors or warnings in this structure.
4708 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4709 ExceptionInfo *exception)
4712 *restrict cache_info;
4715 *restrict image_view;
4723 assert(image != (Image *) NULL);
4724 assert(image->signature == MagickSignature);
4725 if (image->debug != MagickFalse)
4726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4727 assert(image->cache != (Cache) NULL);
4728 cache_info=(CacheInfo *) image->cache;
4729 assert(cache_info->signature == MagickSignature);
4730 image->alpha_trait=BlendPixelTrait;
4732 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4733 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4734 #pragma omp parallel for schedule(static,4) shared(status) \
4735 magick_threads(image,image,1,1)
4737 for (y=0; y < (ssize_t) image->rows; y++)
4745 if (status == MagickFalse)
4747 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4748 if (q == (Quantum *) NULL)
4753 for (x=0; x < (ssize_t) image->columns; x++)
4755 SetPixelAlpha(image,alpha,q);
4756 q+=GetPixelChannels(image);
4758 status=SyncCacheViewAuthenticPixels(image_view,exception);
4760 image_view=DestroyCacheView(image_view);
4764 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4765 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4768 *restrict cache_info;
4773 assert(image != (Image *) NULL);
4774 assert(image->signature == MagickSignature);
4775 if (image->debug != MagickFalse)
4776 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4777 assert(image->cache != (Cache) NULL);
4778 cache_info=(CacheInfo *) image->cache;
4779 assert(cache_info->signature == MagickSignature);
4780 method=cache_info->virtual_pixel_method;
4781 cache_info->virtual_pixel_method=virtual_pixel_method;
4782 if ((image->columns != 0) && (image->rows != 0))
4783 switch (virtual_pixel_method)
4785 case BackgroundVirtualPixelMethod:
4787 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4788 (image->alpha_trait != BlendPixelTrait))
4789 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4790 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4791 (IsGrayColorspace(image->colorspace) != MagickFalse))
4792 (void) SetImageColorspace(image,sRGBColorspace,exception);
4795 case TransparentVirtualPixelMethod:
4797 if (image->alpha_trait != BlendPixelTrait)
4798 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4812 + 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 %
4816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4818 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4819 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4820 % is synced, otherwise MagickFalse.
4822 % The format of the SyncAuthenticPixelCacheNexus() method is:
4824 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4825 % NexusInfo *nexus_info,ExceptionInfo *exception)
4827 % A description of each parameter follows:
4829 % o image: the image.
4831 % o nexus_info: the cache nexus to sync.
4833 % o exception: return any errors or warnings in this structure.
4836 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4837 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4840 *restrict cache_info;
4846 Transfer pixels to the cache.
4848 assert(image != (Image *) NULL);
4849 assert(image->signature == MagickSignature);
4850 if (image->cache == (Cache) NULL)
4851 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4852 cache_info=(CacheInfo *) image->cache;
4853 assert(cache_info->signature == MagickSignature);
4854 if (cache_info->type == UndefinedCache)
4855 return(MagickFalse);
4856 if (nexus_info->authentic_pixel_cache != MagickFalse)
4858 assert(cache_info->signature == MagickSignature);
4859 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4860 if ((cache_info->metacontent_extent != 0) &&
4861 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4862 return(MagickFalse);
4867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871 + S y n c A u t h e n t i c P i x e l C a c h e %
4875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4877 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4878 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4879 % otherwise MagickFalse.
4881 % The format of the SyncAuthenticPixelsCache() method is:
4883 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4884 % ExceptionInfo *exception)
4886 % A description of each parameter follows:
4888 % o image: the image.
4890 % o exception: return any errors or warnings in this structure.
4893 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4894 ExceptionInfo *exception)
4897 *restrict cache_info;
4900 id = GetOpenMPThreadId();
4905 assert(image != (Image *) NULL);
4906 assert(image->signature == MagickSignature);
4907 assert(image->cache != (Cache) NULL);
4908 cache_info=(CacheInfo *) image->cache;
4909 assert(cache_info->signature == MagickSignature);
4910 assert(id < (int) cache_info->number_threads);
4911 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4921 % S y n c A u t h e n t i c P i x e l s %
4925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4927 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4928 % The method returns MagickTrue if the pixel region is flushed, otherwise
4931 % The format of the SyncAuthenticPixels() method is:
4933 % MagickBooleanType SyncAuthenticPixels(Image *image,
4934 % ExceptionInfo *exception)
4936 % A description of each parameter follows:
4938 % o image: the image.
4940 % o exception: return any errors or warnings in this structure.
4943 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4944 ExceptionInfo *exception)
4947 *restrict cache_info;
4950 id = GetOpenMPThreadId();
4955 assert(image != (Image *) NULL);
4956 assert(image->signature == MagickSignature);
4957 assert(image->cache != (Cache) NULL);
4958 cache_info=(CacheInfo *) image->cache;
4959 assert(cache_info->signature == MagickSignature);
4960 if (cache_info->methods.sync_authentic_pixels_handler !=
4961 (SyncAuthenticPixelsHandler) NULL)
4963 status=cache_info->methods.sync_authentic_pixels_handler(image,
4967 assert(id < (int) cache_info->number_threads);
4968 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4978 + S y n c I m a g e P i x e l C a c h e %
4982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4984 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4985 % The method returns MagickTrue if the pixel region is flushed, otherwise
4988 % The format of the SyncImagePixelCache() method is:
4990 % MagickBooleanType SyncImagePixelCache(Image *image,
4991 % ExceptionInfo *exception)
4993 % A description of each parameter follows:
4995 % o image: the image.
4997 % o exception: return any errors or warnings in this structure.
5000 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5001 ExceptionInfo *exception)
5004 *restrict cache_info;
5006 assert(image != (Image *) NULL);
5007 assert(exception != (ExceptionInfo *) NULL);
5008 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5009 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5017 + 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 %
5021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5023 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5024 % of the pixel cache.
5026 % The format of the WritePixelCacheMetacontent() method is:
5028 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5029 % NexusInfo *nexus_info,ExceptionInfo *exception)
5031 % A description of each parameter follows:
5033 % o cache_info: the pixel cache.
5035 % o nexus_info: the cache nexus to write the meta-content.
5037 % o exception: return any errors or warnings in this structure.
5040 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5041 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5051 register const unsigned char
5060 if (cache_info->metacontent_extent == 0)
5061 return(MagickFalse);
5062 if (nexus_info->authentic_pixel_cache != MagickFalse)
5064 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5065 nexus_info->region.x;
5066 length=(MagickSizeType) nexus_info->region.width*
5067 cache_info->metacontent_extent;
5068 extent=(MagickSizeType) length*nexus_info->region.height;
5069 rows=nexus_info->region.height;
5071 p=(unsigned char *) nexus_info->metacontent;
5072 switch (cache_info->type)
5077 register unsigned char
5081 Write associated pixels to memory.
5083 if ((cache_info->columns == nexus_info->region.width) &&
5084 (extent == (MagickSizeType) ((size_t) extent)))
5089 q=(unsigned char *) cache_info->metacontent+offset*
5090 cache_info->metacontent_extent;
5091 for (y=0; y < (ssize_t) rows; y++)
5093 (void) memcpy(q,p,(size_t) length);
5094 p+=nexus_info->region.width*cache_info->metacontent_extent;
5095 q+=cache_info->columns*cache_info->metacontent_extent;
5102 Write associated pixels to disk.
5104 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5106 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5107 cache_info->cache_filename);
5108 return(MagickFalse);
5110 if ((cache_info->columns == nexus_info->region.width) &&
5111 (extent <= MagickMaxBufferExtent))
5116 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5117 for (y=0; y < (ssize_t) rows; y++)
5119 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5120 cache_info->number_channels*sizeof(Quantum)+offset*
5121 cache_info->metacontent_extent,length,(const unsigned char *) p);
5122 if (count != (MagickOffsetType) length)
5124 p+=cache_info->metacontent_extent*nexus_info->region.width;
5125 offset+=cache_info->columns;
5127 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5128 (void) ClosePixelCacheOnDisk(cache_info);
5131 case DistributedCache:
5137 Write metacontent to distributed cache.
5139 LockSemaphoreInfo(cache_info->file_semaphore);
5140 region=nexus_info->region;
5141 if ((cache_info->columns != nexus_info->region.width) ||
5142 (extent > MagickMaxBufferExtent))
5149 for (y=0; y < (ssize_t) rows; y++)
5151 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5152 cache_info->server_info,®ion,length,(const unsigned char *) p);
5153 if (count != (MagickOffsetType) length)
5155 p+=cache_info->metacontent_extent*nexus_info->region.width;
5158 UnlockSemaphoreInfo(cache_info->file_semaphore);
5164 if (y < (ssize_t) rows)
5166 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5167 cache_info->cache_filename);
5168 return(MagickFalse);
5170 if ((cache_info->debug != MagickFalse) &&
5171 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5172 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5173 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5174 nexus_info->region.width,(double) nexus_info->region.height,(double)
5175 nexus_info->region.x,(double) nexus_info->region.y);
5180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5184 + W r i t e C a c h e P i x e l s %
5188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5190 % WritePixelCachePixels() writes image pixels to the specified region of the
5193 % The format of the WritePixelCachePixels() method is:
5195 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5196 % NexusInfo *nexus_info,ExceptionInfo *exception)
5198 % A description of each parameter follows:
5200 % o cache_info: the pixel cache.
5202 % o nexus_info: the cache nexus to write the pixels.
5204 % o exception: return any errors or warnings in this structure.
5207 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5208 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5218 register const Quantum
5227 if (nexus_info->authentic_pixel_cache != MagickFalse)
5229 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5230 nexus_info->region.x;
5231 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5233 extent=length*nexus_info->region.height;
5234 rows=nexus_info->region.height;
5236 p=nexus_info->pixels;
5237 switch (cache_info->type)
5246 Write pixels to memory.
5248 if ((cache_info->columns == nexus_info->region.width) &&
5249 (extent == (MagickSizeType) ((size_t) extent)))
5254 q=cache_info->pixels+offset*cache_info->number_channels;
5255 for (y=0; y < (ssize_t) rows; y++)
5257 (void) memcpy(q,p,(size_t) length);
5258 p+=cache_info->number_channels*nexus_info->region.width;
5259 q+=cache_info->columns*cache_info->number_channels;
5266 Write pixels to disk.
5268 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5270 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5271 cache_info->cache_filename);
5272 return(MagickFalse);
5274 if ((cache_info->columns == nexus_info->region.width) &&
5275 (extent <= MagickMaxBufferExtent))
5280 for (y=0; y < (ssize_t) rows; y++)
5282 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5283 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5285 if (count != (MagickOffsetType) length)
5287 p+=cache_info->number_channels*nexus_info->region.width;
5288 offset+=cache_info->columns;
5290 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5291 (void) ClosePixelCacheOnDisk(cache_info);
5294 case DistributedCache:
5300 Write pixels to distributed cache.
5302 LockSemaphoreInfo(cache_info->file_semaphore);
5303 region=nexus_info->region;
5304 if ((cache_info->columns != nexus_info->region.width) ||
5305 (extent > MagickMaxBufferExtent))
5312 for (y=0; y < (ssize_t) rows; y++)
5314 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5315 cache_info->server_info,®ion,length,(const unsigned char *) p);
5316 if (count != (MagickOffsetType) length)
5318 p+=cache_info->number_channels*nexus_info->region.width;
5321 UnlockSemaphoreInfo(cache_info->file_semaphore);
5327 if (y < (ssize_t) rows)
5329 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5330 cache_info->cache_filename);
5331 return(MagickFalse);
5333 if ((cache_info->debug != MagickFalse) &&
5334 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5335 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5336 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5337 nexus_info->region.width,(double) nexus_info->region.height,(double)
5338 nexus_info->region.x,(double) nexus_info->region.y);