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-2016 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 OpenPixelCacheOnDisk(CacheInfo *,const MapMode),
123 ReadPixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
125 ReadPixelCacheMetacontent(CacheInfo *magick_restrict,
126 NexusInfo *magick_restrict,ExceptionInfo *),
127 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
128 WritePixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
130 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *magick_restrict,
134 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
135 const size_t,ExceptionInfo *),
136 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
137 const size_t,ExceptionInfo *),
138 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
139 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
141 #if defined(MAGICKCORE_OPENCL_SUPPORT)
143 CopyOpenCLBuffer(CacheInfo *magick_restrict);
146 #if defined(__cplusplus) || defined(c_plusplus)
153 static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
157 *cache_semaphore = (SemaphoreInfo *) NULL;
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 + A c q u i r e P i x e l C a c h e %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 % AcquirePixelCache() acquires a pixel cache.
175 % The format of the AcquirePixelCache() method is:
177 % Cache AcquirePixelCache(const size_t number_threads)
179 % A description of each parameter follows:
181 % o number_threads: the number of nexus threads.
184 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
187 *magick_restrict cache_info;
192 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
193 if (cache_info == (CacheInfo *) NULL)
194 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
195 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
196 cache_info->type=UndefinedCache;
197 cache_info->mode=IOMode;
198 cache_info->colorspace=sRGBColorspace;
199 cache_info->file=(-1);
200 cache_info->id=GetMagickThreadId();
201 cache_info->number_threads=number_threads;
202 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
203 cache_info->number_threads=GetOpenMPMaximumThreads();
204 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
205 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
206 if (cache_info->number_threads == 0)
207 cache_info->number_threads=1;
208 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
209 if (cache_info->nexus_info == (NexusInfo **) NULL)
210 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
211 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
212 if (synchronize != (const char *) NULL)
214 cache_info->synchronize=IsStringTrue(synchronize);
215 synchronize=DestroyString(synchronize);
217 cache_info->semaphore=AcquireSemaphoreInfo();
218 cache_info->reference_count=1;
219 cache_info->file_semaphore=AcquireSemaphoreInfo();
220 cache_info->debug=IsEventLogging();
221 cache_info->signature=MagickCoreSignature;
222 return((Cache ) cache_info);
226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230 % A c q u i r e P i x e l C a c h e N e x u s %
234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
238 % The format of the AcquirePixelCacheNexus method is:
240 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
242 % A description of each parameter follows:
244 % o number_threads: the number of nexus threads.
247 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
250 **magick_restrict nexus_info;
255 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
256 number_threads,sizeof(*nexus_info)));
257 if (nexus_info == (NexusInfo **) NULL)
258 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
259 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
260 sizeof(**nexus_info));
261 if (nexus_info[0] == (NexusInfo *) NULL)
262 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
263 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
264 for (i=0; i < (ssize_t) number_threads; i++)
266 nexus_info[i]=(&nexus_info[0][i]);
267 nexus_info[i]->signature=MagickCoreSignature;
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 + A c q u i r e P i x e l C a c h e P i x e l s %
281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 % AcquirePixelCachePixels() returns the pixels associated with the specified
286 % The format of the AcquirePixelCachePixels() method is:
288 % const void *AcquirePixelCachePixels(const Image *image,
289 % MagickSizeType *length,ExceptionInfo *exception)
291 % A description of each parameter follows:
293 % o image: the image.
295 % o length: the pixel cache length.
297 % o exception: return any errors or warnings in this structure.
300 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
304 *magick_restrict cache_info;
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickCoreSignature);
308 assert(exception != (ExceptionInfo *) NULL);
309 assert(exception->signature == MagickCoreSignature);
310 assert(image->cache != (Cache) NULL);
311 cache_info=(CacheInfo *) image->cache;
312 assert(cache_info->signature == MagickCoreSignature);
314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315 return((const void *) NULL);
316 *length=cache_info->length;
317 return((const void *) cache_info->pixels);
321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 + C a c h e C o m p o n e n t G e n e s i s %
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331 % CacheComponentGenesis() instantiates the cache component.
333 % The format of the CacheComponentGenesis method is:
335 % MagickBooleanType CacheComponentGenesis(void)
338 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
340 if (cache_semaphore == (SemaphoreInfo *) NULL)
341 cache_semaphore=AcquireSemaphoreInfo();
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 + C a c h e C o m p o n e n t T e r m i n u s %
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 % CacheComponentTerminus() destroys the cache component.
358 % The format of the CacheComponentTerminus() method is:
360 % CacheComponentTerminus(void)
363 MagickPrivate void CacheComponentTerminus(void)
365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 ActivateSemaphoreInfo(&cache_semaphore);
367 LockSemaphoreInfo(cache_semaphore);
368 instantiate_cache=MagickFalse;
369 UnlockSemaphoreInfo(cache_semaphore);
370 RelinquishSemaphoreInfo(&cache_semaphore);
374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378 + C l o n e P i x e l C a c h e %
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 % ClonePixelCache() clones a pixel cache.
386 % The format of the ClonePixelCache() method is:
388 % Cache ClonePixelCache(const Cache cache)
390 % A description of each parameter follows:
392 % o cache: the pixel cache.
395 MagickPrivate Cache ClonePixelCache(const Cache cache)
398 *magick_restrict clone_info;
401 *magick_restrict cache_info;
403 assert(cache != NULL);
404 cache_info=(const CacheInfo *) cache;
405 assert(cache_info->signature == MagickCoreSignature);
406 if (cache_info->debug != MagickFalse)
407 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
408 cache_info->filename);
409 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
410 if (clone_info == (Cache) NULL)
411 return((Cache) NULL);
412 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
413 return((Cache ) clone_info);
417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421 + C l o n e P i x e l C a c h e M e t h o d s %
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
430 % The format of the ClonePixelCacheMethods() method is:
432 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
434 % A description of each parameter follows:
436 % o clone: Specifies a pointer to a Cache structure.
438 % o cache: the pixel cache.
441 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
444 *magick_restrict cache_info,
445 *magick_restrict source_info;
447 assert(clone != (Cache) NULL);
448 source_info=(CacheInfo *) clone;
449 assert(source_info->signature == MagickCoreSignature);
450 if (source_info->debug != MagickFalse)
451 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
452 source_info->filename);
453 assert(cache != (Cache) NULL);
454 cache_info=(CacheInfo *) cache;
455 assert(cache_info->signature == MagickCoreSignature);
456 source_info->methods=cache_info->methods;
460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464 + 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 %
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469 % ClonePixelCacheRepository() clones the source pixel cache to the destination
472 % The format of the ClonePixelCacheRepository() method is:
474 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
475 % CacheInfo *source_info,ExceptionInfo *exception)
477 % A description of each parameter follows:
479 % o cache_info: the pixel cache.
481 % o source_info: the source pixel cache.
483 % o exception: return any errors or warnings in this structure.
487 static MagickBooleanType ClonePixelCacheOnDisk(
488 CacheInfo *magick_restrict cache_info,CacheInfo *magick_restrict clone_info)
506 Clone pixel cache on disk with identifcal morphology.
508 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
509 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
511 quantum=(size_t) MagickMaxBufferExtent;
512 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
513 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
514 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
515 if (buffer == (unsigned char *) NULL)
516 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
518 while ((count=read(cache_info->file,buffer,quantum)) > 0)
523 number_bytes=write(clone_info->file,buffer,(size_t) count);
524 if (number_bytes != count)
526 extent+=number_bytes;
528 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
529 if (extent != cache_info->length)
534 static MagickBooleanType ClonePixelCacheRepository(
535 CacheInfo *magick_restrict clone_info,CacheInfo *magick_restrict cache_info,
536 ExceptionInfo *exception)
538 #define MaxCacheThreads 2
539 #define cache_threads(source,destination) \
540 num_threads(((source)->type == DiskCache) || \
541 ((destination)->type == DiskCache) || (((source)->rows) < \
542 (16*GetMagickResourceLimit(ThreadResource))) ? 1 : \
543 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
544 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
551 **magick_restrict cache_nexus,
552 **magick_restrict clone_nexus;
560 assert(cache_info != (CacheInfo *) NULL);
561 assert(clone_info != (CacheInfo *) NULL);
562 assert(exception != (ExceptionInfo *) NULL);
563 if (cache_info->type == PingCache)
565 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
566 if ((cache_info->columns == clone_info->columns) &&
567 (cache_info->rows == clone_info->rows) &&
568 (cache_info->number_channels == clone_info->number_channels) &&
569 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
570 (cache_info->metacontent_extent == clone_info->metacontent_extent))
573 Identical pixel cache morphology.
575 if (((cache_info->type == MemoryCache) ||
576 (cache_info->type == MapCache)) &&
577 ((clone_info->type == MemoryCache) ||
578 (clone_info->type == MapCache)))
580 (void) memcpy(clone_info->pixels,cache_info->pixels,
581 cache_info->columns*cache_info->number_channels*cache_info->rows*
582 sizeof(*cache_info->pixels));
583 if ((cache_info->metacontent_extent != 0) &&
584 (clone_info->metacontent_extent != 0))
585 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
586 cache_info->columns*cache_info->rows*
587 clone_info->metacontent_extent*sizeof(unsigned char));
590 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
591 return(ClonePixelCacheOnDisk(cache_info,clone_info));
594 Mismatched pixel cache morphology.
596 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
597 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
598 if ((cache_nexus == (NexusInfo **) NULL) ||
599 (clone_nexus == (NexusInfo **) NULL))
600 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
601 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
602 optimize=(cache_info->number_channels == clone_info->number_channels) &&
603 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
604 MagickTrue : MagickFalse;
605 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
606 clone_info->columns*clone_info->number_channels);
608 #if defined(MAGICKCORE_OPENMP_SUPPORT)
609 #pragma omp parallel for schedule(static,4) shared(status) \
610 cache_threads(cache_info,clone_info)
612 for (y=0; y < (ssize_t) cache_info->rows; y++)
615 id = GetOpenMPThreadId();
626 if (status == MagickFalse)
628 if (y >= (ssize_t) clone_info->rows)
630 region.width=cache_info->columns;
634 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
635 cache_nexus[id],exception);
636 if (pixels == (Quantum *) NULL)
638 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
639 if (status == MagickFalse)
641 region.width=clone_info->columns;
642 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
643 clone_nexus[id],exception);
644 if (pixels == (Quantum *) NULL)
646 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
647 clone_nexus[id]->length);
648 if (optimize != MagickFalse)
649 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
653 register const Quantum
660 Mismatched pixel channel map.
662 p=cache_nexus[id]->pixels;
663 q=clone_nexus[id]->pixels;
664 for (x=0; x < (ssize_t) cache_info->columns; x++)
669 if (x == (ssize_t) clone_info->columns)
671 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
679 channel=clone_info->channel_map[i].channel;
680 traits=cache_info->channel_map[channel].traits;
681 if (traits != UndefinedPixelTrait)
682 *q=*(p+cache_info->channel_map[channel].offset);
685 p+=cache_info->number_channels;
688 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
690 if ((cache_info->metacontent_extent != 0) &&
691 (clone_info->metacontent_extent != 0))
696 length=(size_t) MagickMin(cache_info->metacontent_extent,
697 clone_info->metacontent_extent);
698 #if defined(MAGICKCORE_OPENMP_SUPPORT)
699 #pragma omp parallel for schedule(static,4) shared(status) \
700 cache_threads(cache_info,clone_info)
702 for (y=0; y < (ssize_t) cache_info->rows; y++)
705 id = GetOpenMPThreadId();
713 if (status == MagickFalse)
715 if (y >= (ssize_t) clone_info->rows)
717 region.width=cache_info->columns;
721 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
722 cache_nexus[id],exception);
723 if (pixels == (Quantum *) NULL)
725 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
726 if (status == MagickFalse)
728 region.width=clone_info->columns;
729 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
730 clone_nexus[id],exception);
731 if (pixels == (Quantum *) NULL)
733 if ((clone_nexus[id]->metacontent != (void *) NULL) &&
734 (cache_nexus[id]->metacontent != (void *) NULL))
735 (void) memcpy(clone_nexus[id]->metacontent,
736 cache_nexus[id]->metacontent,length*sizeof(unsigned char));
737 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
740 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
741 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
742 if (cache_info->debug != MagickFalse)
745 message[MagickPathExtent];
747 (void) FormatLocaleString(message,MagickPathExtent,"%s => %s",
748 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
749 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
750 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760 + D e s t r o y I m a g e P i x e l C a c h e %
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
768 % The format of the DestroyImagePixelCache() method is:
770 % void DestroyImagePixelCache(Image *image)
772 % A description of each parameter follows:
774 % o image: the image.
777 static void DestroyImagePixelCache(Image *image)
779 assert(image != (Image *) NULL);
780 assert(image->signature == MagickCoreSignature);
781 if (image->debug != MagickFalse)
782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
783 if (image->cache == (void *) NULL)
785 image->cache=DestroyPixelCache(image->cache);
789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793 + D e s t r o y I m a g e P i x e l s %
797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799 % DestroyImagePixels() deallocates memory associated with the pixel cache.
801 % The format of the DestroyImagePixels() method is:
803 % void DestroyImagePixels(Image *image)
805 % A description of each parameter follows:
807 % o image: the image.
810 MagickExport void DestroyImagePixels(Image *image)
813 *magick_restrict cache_info;
815 assert(image != (const Image *) NULL);
816 assert(image->signature == MagickCoreSignature);
817 if (image->debug != MagickFalse)
818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
819 assert(image->cache != (Cache) NULL);
820 cache_info=(CacheInfo *) image->cache;
821 assert(cache_info->signature == MagickCoreSignature);
822 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
824 cache_info->methods.destroy_pixel_handler(image);
827 image->cache=DestroyPixelCache(image->cache);
831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835 + D e s t r o y P i x e l C a c h e %
839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
841 % DestroyPixelCache() deallocates memory associated with the pixel cache.
843 % The format of the DestroyPixelCache() method is:
845 % Cache DestroyPixelCache(Cache cache)
847 % A description of each parameter follows:
849 % o cache: the pixel cache.
853 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
859 if (cache_info->file != -1)
861 status=close(cache_info->file);
862 cache_info->file=(-1);
863 RelinquishMagickResource(FileResource,1);
865 return(status == -1 ? MagickFalse : MagickTrue);
868 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
870 switch (cache_info->type)
874 #if defined(MAGICKCORE_OPENCL_SUPPORT)
875 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
877 cache_info->opencl=RelinquishMagickCLCacheInfo(cache_info->opencl,
879 cache_info->pixels=(Quantum *) NULL;
883 if (cache_info->mapped == MagickFalse)
884 cache_info->pixels=RelinquishAlignedMemory(cache_info->pixels);
886 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
887 RelinquishMagickResource(MemoryResource,cache_info->length);
892 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
893 cache_info->pixels=(Quantum *) NULL;
894 if (cache_info->mode != ReadMode)
895 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
896 *cache_info->cache_filename='\0';
897 RelinquishMagickResource(MapResource,cache_info->length);
901 if (cache_info->file != -1)
902 (void) ClosePixelCacheOnDisk(cache_info);
903 if (cache_info->mode != ReadMode)
904 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
905 *cache_info->cache_filename='\0';
906 RelinquishMagickResource(DiskResource,cache_info->length);
909 case DistributedCache:
911 *cache_info->cache_filename='\0';
912 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
913 cache_info->server_info);
919 cache_info->type=UndefinedCache;
920 cache_info->mapped=MagickFalse;
921 cache_info->metacontent=(void *) NULL;
924 MagickPrivate Cache DestroyPixelCache(Cache cache)
927 *magick_restrict cache_info;
929 assert(cache != (Cache) NULL);
930 cache_info=(CacheInfo *) cache;
931 assert(cache_info->signature == MagickCoreSignature);
932 if (cache_info->debug != MagickFalse)
933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
934 cache_info->filename);
935 LockSemaphoreInfo(cache_info->semaphore);
936 cache_info->reference_count--;
937 if (cache_info->reference_count != 0)
939 UnlockSemaphoreInfo(cache_info->semaphore);
940 return((Cache) NULL);
942 UnlockSemaphoreInfo(cache_info->semaphore);
943 if (cache_info->debug != MagickFalse)
946 message[MagickPathExtent];
948 (void) FormatLocaleString(message,MagickPathExtent,"destroy %s",
949 cache_info->filename);
950 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
952 RelinquishPixelCachePixels(cache_info);
953 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
954 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
955 cache_info->server_info);
956 if (cache_info->nexus_info != (NexusInfo **) NULL)
957 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
958 cache_info->number_threads);
959 if (cache_info->random_info != (RandomInfo *) NULL)
960 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
961 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
962 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
963 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
964 RelinquishSemaphoreInfo(&cache_info->semaphore);
965 cache_info->signature=(~MagickCoreSignature);
966 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
972 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976 + D e s t r o y P i x e l C a c h e N e x u s %
980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
984 % The format of the DestroyPixelCacheNexus() method is:
986 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
987 % const size_t number_threads)
989 % A description of each parameter follows:
991 % o nexus_info: the nexus to destroy.
993 % o number_threads: the number of nexus threads.
997 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
999 if (nexus_info->mapped == MagickFalse)
1000 (void) RelinquishAlignedMemory(nexus_info->cache);
1002 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1003 nexus_info->cache=(Quantum *) NULL;
1004 nexus_info->pixels=(Quantum *) NULL;
1005 nexus_info->metacontent=(void *) NULL;
1006 nexus_info->length=0;
1007 nexus_info->mapped=MagickFalse;
1010 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1011 const size_t number_threads)
1016 assert(nexus_info != (NexusInfo **) NULL);
1017 for (i=0; i < (ssize_t) number_threads; i++)
1019 if (nexus_info[i]->cache != (Quantum *) NULL)
1020 RelinquishCacheNexusPixels(nexus_info[i]);
1021 nexus_info[i]->signature=(~MagickCoreSignature);
1023 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1024 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 % G e t A u t h e n t i c M e t a c o n t e n t %
1037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1039 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1040 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1041 % returned if the associated pixels are not available.
1043 % The format of the GetAuthenticMetacontent() method is:
1045 % void *GetAuthenticMetacontent(const Image *image)
1047 % A description of each parameter follows:
1049 % o image: the image.
1052 MagickExport void *GetAuthenticMetacontent(const Image *image)
1055 *magick_restrict cache_info;
1058 id = GetOpenMPThreadId();
1060 assert(image != (const Image *) NULL);
1061 assert(image->signature == MagickCoreSignature);
1062 assert(image->cache != (Cache) NULL);
1063 cache_info=(CacheInfo *) image->cache;
1064 assert(cache_info->signature == MagickCoreSignature);
1065 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1066 (GetAuthenticMetacontentFromHandler) NULL)
1071 metacontent=cache_info->methods.
1072 get_authentic_metacontent_from_handler(image);
1073 return(metacontent);
1075 assert(id < (int) cache_info->number_threads);
1076 return(cache_info->nexus_info[id]->metacontent);
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084 + 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 %
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1091 % with the last call to QueueAuthenticPixelsCache() or
1092 % GetAuthenticPixelsCache().
1094 % The format of the GetAuthenticMetacontentFromCache() method is:
1096 % void *GetAuthenticMetacontentFromCache(const Image *image)
1098 % A description of each parameter follows:
1100 % o image: the image.
1103 static void *GetAuthenticMetacontentFromCache(const Image *image)
1106 *magick_restrict cache_info;
1109 id = GetOpenMPThreadId();
1111 assert(image != (const Image *) NULL);
1112 assert(image->signature == MagickCoreSignature);
1113 assert(image->cache != (Cache) NULL);
1114 cache_info=(CacheInfo *) image->cache;
1115 assert(cache_info->signature == MagickCoreSignature);
1116 assert(id < (int) cache_info->number_threads);
1117 return(cache_info->nexus_info[id]->metacontent);
1120 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 + G e t A u t h e n t i c O p e n C L B u f f e r %
1130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132 % GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1135 % The format of the GetAuthenticOpenCLBuffer() method is:
1137 % cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1138 % MagickCLDevice device,ExceptionInfo *exception)
1140 % A description of each parameter follows:
1142 % o image: the image.
1144 % o device: the device to use.
1146 % o exception: return any errors or warnings in this structure.
1149 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1150 MagickCLDevice device,ExceptionInfo *exception)
1153 *magick_restrict cache_info;
1158 assert(image != (const Image *) NULL);
1159 assert(device != (const MagickCLDevice) NULL);
1160 cache_info=(CacheInfo *) image->cache;
1161 if (cache_info->type == UndefinedCache)
1162 SyncImagePixelCache((Image *) image,exception);
1163 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1164 return((cl_mem) NULL);
1165 if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1166 (cache_info->opencl->device->context != device->context))
1167 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1168 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1170 assert(cache_info->pixels != (Quantum *) NULL);
1171 cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1172 cache_info->length);
1173 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1174 return((cl_mem) NULL);
1176 assert(cache_info->opencl->pixels == cache_info->pixels);
1177 return(cache_info->opencl->buffer);
1182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1186 + 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 %
1190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1193 % disk pixel cache as defined by the geometry parameters. A pointer to the
1194 % pixels is returned if the pixels are transferred, otherwise a NULL is
1197 % The format of the GetAuthenticPixelCacheNexus() method is:
1199 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1200 % const ssize_t y,const size_t columns,const size_t rows,
1201 % NexusInfo *nexus_info,ExceptionInfo *exception)
1203 % A description of each parameter follows:
1205 % o image: the image.
1207 % o x,y,columns,rows: These values define the perimeter of a region of
1210 % o nexus_info: the cache nexus to return.
1212 % o exception: return any errors or warnings in this structure.
1216 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1217 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1218 ExceptionInfo *exception)
1221 *magick_restrict cache_info;
1224 *magick_restrict pixels;
1227 Transfer pixels from the cache.
1229 assert(image != (Image *) NULL);
1230 assert(image->signature == MagickCoreSignature);
1231 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1232 nexus_info,exception);
1233 if (pixels == (Quantum *) NULL)
1234 return((Quantum *) NULL);
1235 cache_info=(CacheInfo *) image->cache;
1236 assert(cache_info->signature == MagickCoreSignature);
1237 if (nexus_info->authentic_pixel_cache != MagickFalse)
1239 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1240 return((Quantum *) NULL);
1241 if (cache_info->metacontent_extent != 0)
1242 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1243 return((Quantum *) NULL);
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 + 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 %
1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1259 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1261 % The format of the GetAuthenticPixelsFromCache() method is:
1263 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1265 % A description of each parameter follows:
1267 % o image: the image.
1270 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1273 *magick_restrict cache_info;
1276 id = GetOpenMPThreadId();
1278 assert(image != (const Image *) NULL);
1279 assert(image->signature == MagickCoreSignature);
1280 assert(image->cache != (Cache) NULL);
1281 cache_info=(CacheInfo *) image->cache;
1282 assert(cache_info->signature == MagickCoreSignature);
1283 assert(id < (int) cache_info->number_threads);
1284 return(cache_info->nexus_info[id]->pixels);
1288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1292 % G e t A u t h e n t i c P i x e l Q u e u e %
1296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1298 % GetAuthenticPixelQueue() returns the authentic pixels associated
1299 % corresponding with the last call to QueueAuthenticPixels() or
1300 % GetAuthenticPixels().
1302 % The format of the GetAuthenticPixelQueue() method is:
1304 % Quantum *GetAuthenticPixelQueue(const Image image)
1306 % A description of each parameter follows:
1308 % o image: the image.
1311 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1314 *magick_restrict cache_info;
1317 id = GetOpenMPThreadId();
1319 assert(image != (const Image *) NULL);
1320 assert(image->signature == MagickCoreSignature);
1321 assert(image->cache != (Cache) NULL);
1322 cache_info=(CacheInfo *) image->cache;
1323 assert(cache_info->signature == MagickCoreSignature);
1324 if (cache_info->methods.get_authentic_pixels_from_handler !=
1325 (GetAuthenticPixelsFromHandler) NULL)
1326 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1327 assert(id < (int) cache_info->number_threads);
1328 return(cache_info->nexus_info[id]->pixels);
1332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1336 % G e t A u t h e n t i c P i x e l s %
1340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1343 % region is successfully accessed, a pointer to a Quantum array
1344 % representing the region is returned, otherwise NULL is returned.
1346 % The returned pointer may point to a temporary working copy of the pixels
1347 % or it may point to the original pixels in memory. Performance is maximized
1348 % if the selected region is part of one row, or one or more full rows, since
1349 % then there is opportunity to access the pixels in-place (without a copy)
1350 % if the image is in memory, or in a memory-mapped file. The returned pointer
1351 % must *never* be deallocated by the user.
1353 % Pixels accessed via the returned pointer represent a simple array of type
1354 % Quantum. If the image has corresponding metacontent,call
1355 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1356 % meta-content corresponding to the region. Once the Quantum array has
1357 % been updated, the changes must be saved back to the underlying image using
1358 % SyncAuthenticPixels() or they may be lost.
1360 % The format of the GetAuthenticPixels() method is:
1362 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1363 % const ssize_t y,const size_t columns,const size_t rows,
1364 % ExceptionInfo *exception)
1366 % A description of each parameter follows:
1368 % o image: the image.
1370 % o x,y,columns,rows: These values define the perimeter of a region of
1373 % o exception: return any errors or warnings in this structure.
1376 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1377 const ssize_t y,const size_t columns,const size_t rows,
1378 ExceptionInfo *exception)
1381 *magick_restrict cache_info;
1384 id = GetOpenMPThreadId();
1389 assert(image != (Image *) NULL);
1390 assert(image->signature == MagickCoreSignature);
1391 assert(image->cache != (Cache) NULL);
1392 cache_info=(CacheInfo *) image->cache;
1393 assert(cache_info->signature == MagickCoreSignature);
1394 if (cache_info->methods.get_authentic_pixels_handler !=
1395 (GetAuthenticPixelsHandler) NULL)
1397 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1401 assert(id < (int) cache_info->number_threads);
1402 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1403 cache_info->nexus_info[id],exception);
1408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412 + G e t A u t h e n t i c P i x e l s C a c h e %
1416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1419 % as defined by the geometry parameters. A pointer to the pixels is returned
1420 % if the pixels are transferred, otherwise a NULL is returned.
1422 % The format of the GetAuthenticPixelsCache() method is:
1424 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1425 % const ssize_t y,const size_t columns,const size_t rows,
1426 % ExceptionInfo *exception)
1428 % A description of each parameter follows:
1430 % o image: the image.
1432 % o x,y,columns,rows: These values define the perimeter of a region of
1435 % o exception: return any errors or warnings in this structure.
1438 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1439 const ssize_t y,const size_t columns,const size_t rows,
1440 ExceptionInfo *exception)
1443 *magick_restrict cache_info;
1446 id = GetOpenMPThreadId();
1449 *magick_restrict pixels;
1451 assert(image != (const Image *) NULL);
1452 assert(image->signature == MagickCoreSignature);
1453 assert(image->cache != (Cache) NULL);
1454 cache_info=(CacheInfo *) image->cache;
1455 if (cache_info == (Cache) NULL)
1456 return((Quantum *) NULL);
1457 assert(cache_info->signature == MagickCoreSignature);
1458 assert(id < (int) cache_info->number_threads);
1459 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1460 cache_info->nexus_info[id],exception);
1465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1469 + G e t I m a g e E x t e n t %
1473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475 % GetImageExtent() returns the extent of the pixels associated corresponding
1476 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1478 % The format of the GetImageExtent() method is:
1480 % MagickSizeType GetImageExtent(const Image *image)
1482 % A description of each parameter follows:
1484 % o image: the image.
1487 MagickExport MagickSizeType GetImageExtent(const Image *image)
1490 *magick_restrict cache_info;
1493 id = GetOpenMPThreadId();
1495 assert(image != (Image *) NULL);
1496 assert(image->signature == MagickCoreSignature);
1497 if (image->debug != MagickFalse)
1498 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1499 assert(image->cache != (Cache) NULL);
1500 cache_info=(CacheInfo *) image->cache;
1501 assert(cache_info->signature == MagickCoreSignature);
1502 assert(id < (int) cache_info->number_threads);
1503 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1511 + G e t I m a g e P i x e l C a c h e %
1515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1517 % GetImagePixelCache() ensures that there is only a single reference to the
1518 % pixel cache to be modified, updating the provided cache pointer to point to
1519 % a clone of the original pixel cache if necessary.
1521 % The format of the GetImagePixelCache method is:
1523 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1524 % ExceptionInfo *exception)
1526 % A description of each parameter follows:
1528 % o image: the image.
1530 % o clone: any value other than MagickFalse clones the cache pixels.
1532 % o exception: return any errors or warnings in this structure.
1536 static inline MagickBooleanType ValidatePixelCacheMorphology(
1537 const Image *magick_restrict image)
1540 *magick_restrict cache_info;
1542 const PixelChannelMap
1547 Does the image match the pixel cache morphology?
1549 cache_info=(CacheInfo *) image->cache;
1550 p=image->channel_map;
1551 q=cache_info->channel_map;
1552 if ((image->storage_class != cache_info->storage_class) ||
1553 (image->colorspace != cache_info->colorspace) ||
1554 (image->alpha_trait != cache_info->alpha_trait) ||
1555 (image->read_mask != cache_info->read_mask) ||
1556 (image->write_mask != cache_info->write_mask) ||
1557 (image->columns != cache_info->columns) ||
1558 (image->rows != cache_info->rows) ||
1559 (image->number_channels != cache_info->number_channels) ||
1560 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1561 (image->metacontent_extent != cache_info->metacontent_extent) ||
1562 (cache_info->nexus_info == (NexusInfo **) NULL))
1563 return(MagickFalse);
1567 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1568 ExceptionInfo *exception)
1571 *magick_restrict cache_info;
1577 static MagickSizeType
1578 cache_timelimit = MagickResourceInfinity,
1579 cpu_throttle = MagickResourceInfinity,
1583 if (cpu_throttle == MagickResourceInfinity)
1584 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1585 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1586 MagickDelay(cpu_throttle);
1587 if (cache_epoch == 0)
1590 Set the expire time in seconds.
1592 cache_timelimit=GetMagickResourceLimit(TimeResource);
1593 cache_epoch=time((time_t *) NULL);
1595 if ((cache_timelimit != MagickResourceInfinity) &&
1596 ((MagickSizeType) (time((time_t *) NULL)-cache_epoch) >= cache_timelimit))
1598 #if defined(ECANCELED)
1601 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1603 LockSemaphoreInfo(image->semaphore);
1604 assert(image->cache != (Cache) NULL);
1605 cache_info=(CacheInfo *) image->cache;
1606 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1607 CopyOpenCLBuffer(cache_info);
1609 destroy=MagickFalse;
1610 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1612 LockSemaphoreInfo(cache_info->semaphore);
1613 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1624 clone_image=(*image);
1625 clone_image.semaphore=AcquireSemaphoreInfo();
1626 clone_image.reference_count=1;
1627 clone_image.cache=ClonePixelCache(cache_info);
1628 clone_info=(CacheInfo *) clone_image.cache;
1629 status=OpenPixelCache(&clone_image,IOMode,exception);
1630 if (status != MagickFalse)
1632 if (clone != MagickFalse)
1633 status=ClonePixelCacheRepository(clone_info,cache_info,
1635 if (status != MagickFalse)
1637 if (cache_info->reference_count == 1)
1638 cache_info->nexus_info=(NexusInfo **) NULL;
1640 image->cache=clone_image.cache;
1643 RelinquishSemaphoreInfo(&clone_image.semaphore);
1645 UnlockSemaphoreInfo(cache_info->semaphore);
1647 if (destroy != MagickFalse)
1648 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1649 if (status != MagickFalse)
1652 Ensure the image matches the pixel cache morphology.
1654 image->type=UndefinedType;
1655 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1657 status=OpenPixelCache(image,IOMode,exception);
1658 cache_info=(CacheInfo *) image->cache;
1659 if (cache_info->type == DiskCache)
1660 (void) ClosePixelCacheOnDisk(cache_info);
1663 UnlockSemaphoreInfo(image->semaphore);
1664 if (status == MagickFalse)
1665 return((Cache) NULL);
1666 return(image->cache);
1670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1674 + G e t I m a g e P i x e l C a c h e T y p e %
1678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1680 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1681 % DiskCache, MemoryCache, MapCache, or PingCache.
1683 % The format of the GetImagePixelCacheType() method is:
1685 % CacheType GetImagePixelCacheType(const Image *image)
1687 % A description of each parameter follows:
1689 % o image: the image.
1692 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1695 *magick_restrict cache_info;
1697 assert(image != (Image *) NULL);
1698 assert(image->signature == MagickCoreSignature);
1699 assert(image->cache != (Cache) NULL);
1700 cache_info=(CacheInfo *) image->cache;
1701 assert(cache_info->signature == MagickCoreSignature);
1702 return(cache_info->type);
1706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1710 % G e t O n e A u t h e n t i c P i x e l %
1714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1717 % location. The image background color is returned if an error occurs.
1719 % The format of the GetOneAuthenticPixel() method is:
1721 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1722 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1724 % A description of each parameter follows:
1726 % o image: the image.
1728 % o x,y: These values define the location of the pixel to return.
1730 % o pixel: return a pixel at the specified (x,y) location.
1732 % o exception: return any errors or warnings in this structure.
1736 static inline MagickBooleanType CopyPixel(const Image *image,
1737 const Quantum *source,Quantum *destination)
1742 if (source == (const Quantum *) NULL)
1744 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1745 destination[GreenPixelChannel]=ClampToQuantum(
1746 image->background_color.green);
1747 destination[BluePixelChannel]=ClampToQuantum(
1748 image->background_color.blue);
1749 destination[BlackPixelChannel]=ClampToQuantum(
1750 image->background_color.black);
1751 destination[AlphaPixelChannel]=ClampToQuantum(
1752 image->background_color.alpha);
1753 return(MagickFalse);
1755 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1757 PixelChannel channel=GetPixelChannelChannel(image,i);
1758 destination[channel]=source[i];
1763 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1764 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1767 *magick_restrict cache_info;
1772 assert(image != (Image *) NULL);
1773 assert(image->signature == MagickCoreSignature);
1774 assert(image->cache != (Cache) NULL);
1775 cache_info=(CacheInfo *) image->cache;
1776 assert(cache_info->signature == MagickCoreSignature);
1777 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1778 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1779 (GetOneAuthenticPixelFromHandler) NULL)
1780 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1782 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1783 return(CopyPixel(image,q,pixel));
1787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1791 + 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 %
1795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1797 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1798 % location. The image background color is returned if an error occurs.
1800 % The format of the GetOneAuthenticPixelFromCache() method is:
1802 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1803 % const ssize_t x,const ssize_t y,Quantum *pixel,
1804 % ExceptionInfo *exception)
1806 % A description of each parameter follows:
1808 % o image: the image.
1810 % o x,y: These values define the location of the pixel to return.
1812 % o pixel: return a pixel at the specified (x,y) location.
1814 % o exception: return any errors or warnings in this structure.
1817 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1818 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1821 *magick_restrict cache_info;
1824 id = GetOpenMPThreadId();
1829 assert(image != (const Image *) NULL);
1830 assert(image->signature == MagickCoreSignature);
1831 assert(image->cache != (Cache) NULL);
1832 cache_info=(CacheInfo *) image->cache;
1833 assert(cache_info->signature == MagickCoreSignature);
1834 assert(id < (int) cache_info->number_threads);
1835 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1836 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1838 return(CopyPixel(image,q,pixel));
1842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1846 % G e t O n e V i r t u a l P i x e l %
1850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1852 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1853 % (x,y) location. The image background color is returned if an error occurs.
1854 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1856 % The format of the GetOneVirtualPixel() method is:
1858 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1859 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1861 % A description of each parameter follows:
1863 % o image: the image.
1865 % o x,y: These values define the location of the pixel to return.
1867 % o pixel: return a pixel at the specified (x,y) location.
1869 % o exception: return any errors or warnings in this structure.
1872 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1873 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1876 *magick_restrict cache_info;
1879 id = GetOpenMPThreadId();
1884 assert(image != (const Image *) NULL);
1885 assert(image->signature == MagickCoreSignature);
1886 assert(image->cache != (Cache) NULL);
1887 cache_info=(CacheInfo *) image->cache;
1888 assert(cache_info->signature == MagickCoreSignature);
1889 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1890 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1891 (GetOneVirtualPixelFromHandler) NULL)
1892 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1893 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1894 assert(id < (int) cache_info->number_threads);
1895 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1896 1UL,1UL,cache_info->nexus_info[id],exception);
1897 return(CopyPixel(image,p,pixel));
1901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1905 + 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 %
1909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1911 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1912 % specified (x,y) location. The image background color is returned if an
1915 % The format of the GetOneVirtualPixelFromCache() method is:
1917 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1918 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1919 % Quantum *pixel,ExceptionInfo *exception)
1921 % A description of each parameter follows:
1923 % o image: the image.
1925 % o virtual_pixel_method: the virtual pixel method.
1927 % o x,y: These values define the location of the pixel to return.
1929 % o pixel: return a pixel at the specified (x,y) location.
1931 % o exception: return any errors or warnings in this structure.
1934 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1935 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1936 Quantum *pixel,ExceptionInfo *exception)
1939 *magick_restrict cache_info;
1942 id = GetOpenMPThreadId();
1947 assert(image != (const Image *) NULL);
1948 assert(image->signature == MagickCoreSignature);
1949 assert(image->cache != (Cache) NULL);
1950 cache_info=(CacheInfo *) image->cache;
1951 assert(cache_info->signature == MagickCoreSignature);
1952 assert(id < (int) cache_info->number_threads);
1953 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1954 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1955 cache_info->nexus_info[id],exception);
1956 return(CopyPixel(image,p,pixel));
1960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964 % G e t O n e V i r t u a l P i x e l I n f o %
1968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1971 % location. The image background color is returned if an error occurs. If
1972 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1974 % The format of the GetOneVirtualPixelInfo() method is:
1976 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1977 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1978 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1980 % A description of each parameter follows:
1982 % o image: the image.
1984 % o virtual_pixel_method: the virtual pixel method.
1986 % o x,y: these values define the location of the pixel to return.
1988 % o pixel: return a pixel at the specified (x,y) location.
1990 % o exception: return any errors or warnings in this structure.
1993 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1994 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1995 PixelInfo *pixel,ExceptionInfo *exception)
1998 *magick_restrict cache_info;
2001 id = GetOpenMPThreadId();
2003 register const Quantum
2006 assert(image != (const Image *) NULL);
2007 assert(image->signature == MagickCoreSignature);
2008 assert(image->cache != (Cache) NULL);
2009 cache_info=(CacheInfo *) image->cache;
2010 assert(cache_info->signature == MagickCoreSignature);
2011 assert(id < (int) cache_info->number_threads);
2012 GetPixelInfo(image,pixel);
2013 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2014 cache_info->nexus_info[id],exception);
2015 if (p == (const Quantum *) NULL)
2016 return(MagickFalse);
2017 GetPixelInfoPixel(image,p,pixel);
2022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2026 + G e t P i x e l C a c h e C o l o r s p a c e %
2030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2032 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2034 % The format of the GetPixelCacheColorspace() method is:
2036 % Colorspace GetPixelCacheColorspace(Cache cache)
2038 % A description of each parameter follows:
2040 % o cache: the pixel cache.
2043 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2046 *magick_restrict cache_info;
2048 assert(cache != (Cache) NULL);
2049 cache_info=(CacheInfo *) cache;
2050 assert(cache_info->signature == MagickCoreSignature);
2051 if (cache_info->debug != MagickFalse)
2052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2053 cache_info->filename);
2054 return(cache_info->colorspace);
2058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2062 + G e t P i x e l C a c h e M e t h o d s %
2066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2068 % GetPixelCacheMethods() initializes the CacheMethods structure.
2070 % The format of the GetPixelCacheMethods() method is:
2072 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2074 % A description of each parameter follows:
2076 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2079 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2081 assert(cache_methods != (CacheMethods *) NULL);
2082 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2083 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2084 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2085 cache_methods->get_virtual_metacontent_from_handler=
2086 GetVirtualMetacontentFromCache;
2087 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2088 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2089 cache_methods->get_authentic_metacontent_from_handler=
2090 GetAuthenticMetacontentFromCache;
2091 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2092 cache_methods->get_one_authentic_pixel_from_handler=
2093 GetOneAuthenticPixelFromCache;
2094 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2095 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2096 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2104 + G e t P i x e l C a c h e N e x u s E x t e n t %
2108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2111 % corresponding with the last call to SetPixelCacheNexusPixels() or
2112 % GetPixelCacheNexusPixels().
2114 % The format of the GetPixelCacheNexusExtent() method is:
2116 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2117 % NexusInfo *nexus_info)
2119 % A description of each parameter follows:
2121 % o nexus_info: the nexus info.
2124 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2125 NexusInfo *magick_restrict nexus_info)
2128 *magick_restrict cache_info;
2133 assert(cache != NULL);
2134 cache_info=(CacheInfo *) cache;
2135 assert(cache_info->signature == MagickCoreSignature);
2136 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2138 return((MagickSizeType) cache_info->columns*cache_info->rows);
2143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2147 + G e t P i x e l C a c h e P i x e l s %
2151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2153 % GetPixelCachePixels() returns the pixels associated with the specified image.
2155 % The format of the GetPixelCachePixels() method is:
2157 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2158 % ExceptionInfo *exception)
2160 % A description of each parameter follows:
2162 % o image: the image.
2164 % o length: the pixel cache length.
2166 % o exception: return any errors or warnings in this structure.
2169 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2170 ExceptionInfo *exception)
2173 *magick_restrict cache_info;
2175 assert(image != (const Image *) NULL);
2176 assert(image->signature == MagickCoreSignature);
2177 assert(image->cache != (Cache) NULL);
2178 assert(length != (MagickSizeType *) NULL);
2179 assert(exception != (ExceptionInfo *) NULL);
2180 assert(exception->signature == MagickCoreSignature);
2181 cache_info=(CacheInfo *) image->cache;
2182 assert(cache_info->signature == MagickCoreSignature);
2184 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2185 return((void *) NULL);
2186 *length=cache_info->length;
2187 return((void *) cache_info->pixels);
2191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2195 + 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 %
2199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2201 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2203 % The format of the GetPixelCacheStorageClass() method is:
2205 % ClassType GetPixelCacheStorageClass(Cache cache)
2207 % A description of each parameter follows:
2209 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2211 % o cache: the pixel cache.
2214 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2217 *magick_restrict cache_info;
2219 assert(cache != (Cache) NULL);
2220 cache_info=(CacheInfo *) cache;
2221 assert(cache_info->signature == MagickCoreSignature);
2222 if (cache_info->debug != MagickFalse)
2223 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2224 cache_info->filename);
2225 return(cache_info->storage_class);
2229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2233 + G e t P i x e l C a c h e T i l e S i z e %
2237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2239 % GetPixelCacheTileSize() returns the pixel cache tile size.
2241 % The format of the GetPixelCacheTileSize() method is:
2243 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2246 % A description of each parameter follows:
2248 % o image: the image.
2250 % o width: the optimize cache tile width in pixels.
2252 % o height: the optimize cache tile height in pixels.
2255 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2259 *magick_restrict cache_info;
2261 assert(image != (Image *) NULL);
2262 assert(image->signature == MagickCoreSignature);
2263 if (image->debug != MagickFalse)
2264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2265 cache_info=(CacheInfo *) image->cache;
2266 assert(cache_info->signature == MagickCoreSignature);
2267 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2268 if (GetImagePixelCacheType(image) == DiskCache)
2269 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 + 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 %
2282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2285 % pixel cache. A virtual pixel is any pixel access that is outside the
2286 % boundaries of the image cache.
2288 % The format of the GetPixelCacheVirtualMethod() method is:
2290 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2292 % A description of each parameter follows:
2294 % o image: the image.
2297 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2300 *magick_restrict cache_info;
2302 assert(image != (Image *) NULL);
2303 assert(image->signature == MagickCoreSignature);
2304 assert(image->cache != (Cache) NULL);
2305 cache_info=(CacheInfo *) image->cache;
2306 assert(cache_info->signature == MagickCoreSignature);
2307 return(cache_info->virtual_pixel_method);
2311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315 + 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 %
2319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2322 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2324 % The format of the GetVirtualMetacontentFromCache() method is:
2326 % void *GetVirtualMetacontentFromCache(const Image *image)
2328 % A description of each parameter follows:
2330 % o image: the image.
2333 static const void *GetVirtualMetacontentFromCache(const Image *image)
2336 *magick_restrict cache_info;
2339 id = GetOpenMPThreadId();
2342 *magick_restrict metacontent;
2344 assert(image != (const Image *) NULL);
2345 assert(image->signature == MagickCoreSignature);
2346 assert(image->cache != (Cache) NULL);
2347 cache_info=(CacheInfo *) image->cache;
2348 assert(cache_info->signature == MagickCoreSignature);
2349 assert(id < (int) cache_info->number_threads);
2350 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2351 cache_info->nexus_info[id]);
2352 return(metacontent);
2356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2360 + 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 %
2364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2366 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2369 % The format of the GetVirtualMetacontentFromNexus() method is:
2371 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2372 % NexusInfo *nexus_info)
2374 % A description of each parameter follows:
2376 % o cache: the pixel cache.
2378 % o nexus_info: the cache nexus to return the meta-content.
2381 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2382 NexusInfo *magick_restrict nexus_info)
2385 *magick_restrict cache_info;
2387 assert(cache != (Cache) NULL);
2388 cache_info=(CacheInfo *) cache;
2389 assert(cache_info->signature == MagickCoreSignature);
2390 if (cache_info->storage_class == UndefinedClass)
2391 return((void *) NULL);
2392 return(nexus_info->metacontent);
2396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2400 % G e t V i r t u a l M e t a c o n t e n t %
2404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2406 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2407 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2408 % returned if the meta-content are not available.
2410 % The format of the GetVirtualMetacontent() method is:
2412 % const void *GetVirtualMetacontent(const Image *image)
2414 % A description of each parameter follows:
2416 % o image: the image.
2419 MagickExport const void *GetVirtualMetacontent(const Image *image)
2422 *magick_restrict cache_info;
2425 id = GetOpenMPThreadId();
2428 *magick_restrict metacontent;
2430 assert(image != (const Image *) NULL);
2431 assert(image->signature == MagickCoreSignature);
2432 assert(image->cache != (Cache) NULL);
2433 cache_info=(CacheInfo *) image->cache;
2434 assert(cache_info->signature == MagickCoreSignature);
2435 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2436 if (metacontent != (void *) NULL)
2437 return(metacontent);
2438 assert(id < (int) cache_info->number_threads);
2439 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2440 cache_info->nexus_info[id]);
2441 return(metacontent);
2445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2449 + 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 %
2453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2455 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2456 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2457 % is returned if the pixels are transferred, otherwise a NULL is returned.
2459 % The format of the GetVirtualPixelsFromNexus() method is:
2461 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2462 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2463 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2464 % ExceptionInfo *exception)
2466 % A description of each parameter follows:
2468 % o image: the image.
2470 % o virtual_pixel_method: the virtual pixel method.
2472 % o x,y,columns,rows: These values define the perimeter of a region of
2475 % o nexus_info: the cache nexus to acquire.
2477 % o exception: return any errors or warnings in this structure.
2484 0, 48, 12, 60, 3, 51, 15, 63,
2485 32, 16, 44, 28, 35, 19, 47, 31,
2486 8, 56, 4, 52, 11, 59, 7, 55,
2487 40, 24, 36, 20, 43, 27, 39, 23,
2488 2, 50, 14, 62, 1, 49, 13, 61,
2489 34, 18, 46, 30, 33, 17, 45, 29,
2490 10, 58, 6, 54, 9, 57, 5, 53,
2491 42, 26, 38, 22, 41, 25, 37, 21
2494 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2499 index=x+DitherMatrix[x & 0x07]-32L;
2502 if (index >= (ssize_t) columns)
2503 return((ssize_t) columns-1L);
2507 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2512 index=y+DitherMatrix[y & 0x07]-32L;
2515 if (index >= (ssize_t) rows)
2516 return((ssize_t) rows-1L);
2520 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2524 if (x >= (ssize_t) columns)
2525 return((ssize_t) (columns-1));
2529 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2533 if (y >= (ssize_t) rows)
2534 return((ssize_t) (rows-1));
2538 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2540 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2543 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2545 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2548 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2549 const size_t extent)
2555 Compute the remainder of dividing offset by extent. It returns not only
2556 the quotient (tile the offset falls in) but also the positive remainer
2557 within that tile such that 0 <= remainder < extent. This method is
2558 essentially a ldiv() using a floored modulo division rather than the
2559 normal default truncated modulo division.
2561 modulo.quotient=offset/(ssize_t) extent;
2564 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2568 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2569 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2570 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2571 ExceptionInfo *exception)
2574 *magick_restrict cache_info;
2584 **magick_restrict virtual_nexus;
2587 *magick_restrict pixels,
2588 virtual_pixel[MaxPixelChannels];
2593 register const Quantum
2606 register unsigned char
2613 *magick_restrict virtual_metacontent;
2618 assert(image != (const Image *) NULL);
2619 assert(image->signature == MagickCoreSignature);
2620 assert(image->cache != (Cache) NULL);
2621 cache_info=(CacheInfo *) image->cache;
2622 assert(cache_info->signature == MagickCoreSignature);
2623 if (cache_info->type == UndefinedCache)
2624 return((const Quantum *) NULL);
2627 region.width=columns;
2629 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2631 if (pixels == (Quantum *) NULL)
2632 return((const Quantum *) NULL);
2634 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2635 nexus_info->region.x;
2636 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2637 nexus_info->region.width-1L;
2638 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2639 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2640 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2641 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2647 Pixel request is inside cache extents.
2649 if (nexus_info->authentic_pixel_cache != MagickFalse)
2651 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2652 if (status == MagickFalse)
2653 return((const Quantum *) NULL);
2654 if (cache_info->metacontent_extent != 0)
2656 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2657 if (status == MagickFalse)
2658 return((const Quantum *) NULL);
2663 Pixel request is outside cache extents.
2665 s=(unsigned char *) nexus_info->metacontent;
2666 virtual_nexus=AcquirePixelCacheNexus(1);
2667 if (virtual_nexus == (NexusInfo **) NULL)
2669 if (virtual_nexus != (NexusInfo **) NULL)
2670 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2671 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2672 "UnableToGetCacheNexus","`%s'",image->filename);
2673 return((const Quantum *) NULL);
2675 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2676 sizeof(*virtual_pixel));
2677 virtual_metacontent=(void *) NULL;
2678 switch (virtual_pixel_method)
2680 case BackgroundVirtualPixelMethod:
2681 case BlackVirtualPixelMethod:
2682 case GrayVirtualPixelMethod:
2683 case TransparentVirtualPixelMethod:
2684 case MaskVirtualPixelMethod:
2685 case WhiteVirtualPixelMethod:
2686 case EdgeVirtualPixelMethod:
2687 case CheckerTileVirtualPixelMethod:
2688 case HorizontalTileVirtualPixelMethod:
2689 case VerticalTileVirtualPixelMethod:
2691 if (cache_info->metacontent_extent != 0)
2694 Acquire a metacontent buffer.
2696 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2697 cache_info->metacontent_extent);
2698 if (virtual_metacontent == (void *) NULL)
2700 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2701 (void) ThrowMagickException(exception,GetMagickModule(),
2702 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2703 return((const Quantum *) NULL);
2705 (void) ResetMagickMemory(virtual_metacontent,0,
2706 cache_info->metacontent_extent);
2708 switch (virtual_pixel_method)
2710 case BlackVirtualPixelMethod:
2712 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2713 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2714 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2717 case GrayVirtualPixelMethod:
2719 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2720 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2722 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2725 case TransparentVirtualPixelMethod:
2727 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2728 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2729 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2732 case MaskVirtualPixelMethod:
2733 case WhiteVirtualPixelMethod:
2735 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2736 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2737 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2742 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2744 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2746 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2748 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2750 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2760 for (v=0; v < (ssize_t) rows; v++)
2766 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2767 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2768 y_offset=EdgeY(y_offset,cache_info->rows);
2769 for (u=0; u < (ssize_t) columns; u+=length)
2775 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2776 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2777 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2785 Transfer a single pixel.
2787 length=(MagickSizeType) 1;
2788 switch (virtual_pixel_method)
2790 case EdgeVirtualPixelMethod:
2793 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2794 EdgeX(x_offset,cache_info->columns),
2795 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2797 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2800 case RandomVirtualPixelMethod:
2802 if (cache_info->random_info == (RandomInfo *) NULL)
2803 cache_info->random_info=AcquireRandomInfo();
2804 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2805 RandomX(cache_info->random_info,cache_info->columns),
2806 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2807 *virtual_nexus,exception);
2808 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2811 case DitherVirtualPixelMethod:
2813 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2814 DitherX(x_offset,cache_info->columns),
2815 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2817 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2820 case TileVirtualPixelMethod:
2822 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2823 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2824 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2825 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2827 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2830 case MirrorVirtualPixelMethod:
2832 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2833 if ((x_modulo.quotient & 0x01) == 1L)
2834 x_modulo.remainder=(ssize_t) cache_info->columns-
2835 x_modulo.remainder-1L;
2836 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2837 if ((y_modulo.quotient & 0x01) == 1L)
2838 y_modulo.remainder=(ssize_t) cache_info->rows-
2839 y_modulo.remainder-1L;
2840 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2841 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2843 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2846 case HorizontalTileEdgeVirtualPixelMethod:
2848 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2849 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2850 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2851 *virtual_nexus,exception);
2852 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2855 case VerticalTileEdgeVirtualPixelMethod:
2857 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2858 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2859 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2860 *virtual_nexus,exception);
2861 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2864 case BackgroundVirtualPixelMethod:
2865 case BlackVirtualPixelMethod:
2866 case GrayVirtualPixelMethod:
2867 case TransparentVirtualPixelMethod:
2868 case MaskVirtualPixelMethod:
2869 case WhiteVirtualPixelMethod:
2872 r=virtual_metacontent;
2875 case CheckerTileVirtualPixelMethod:
2877 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2878 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2879 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2882 r=virtual_metacontent;
2885 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2886 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2888 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2891 case HorizontalTileVirtualPixelMethod:
2893 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2896 r=virtual_metacontent;
2899 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2900 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2901 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2902 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2904 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2907 case VerticalTileVirtualPixelMethod:
2909 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2912 r=virtual_metacontent;
2915 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2916 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2917 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2918 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2920 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2924 if (p == (const Quantum *) NULL)
2926 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2928 q+=cache_info->number_channels;
2929 if ((s != (void *) NULL) && (r != (const void *) NULL))
2931 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2932 s+=cache_info->metacontent_extent;
2937 Transfer a run of pixels.
2939 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2940 (size_t) length,1UL,*virtual_nexus,exception);
2941 if (p == (const Quantum *) NULL)
2943 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2944 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2945 q+=length*cache_info->number_channels;
2946 if ((r != (void *) NULL) && (s != (const void *) NULL))
2948 (void) memcpy(s,r,(size_t) length);
2949 s+=length*cache_info->metacontent_extent;
2952 if (u < (ssize_t) columns)
2958 if (virtual_metacontent != (void *) NULL)
2959 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2960 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2961 if (v < (ssize_t) rows)
2962 return((const Quantum *) NULL);
2967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971 + G e t V i r t u a l P i x e l C a c h e %
2975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2977 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2978 % cache as defined by the geometry parameters. A pointer to the pixels
2979 % is returned if the pixels are transferred, otherwise a NULL is returned.
2981 % The format of the GetVirtualPixelCache() method is:
2983 % const Quantum *GetVirtualPixelCache(const Image *image,
2984 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2985 % const ssize_t y,const size_t columns,const size_t rows,
2986 % ExceptionInfo *exception)
2988 % A description of each parameter follows:
2990 % o image: the image.
2992 % o virtual_pixel_method: the virtual pixel method.
2994 % o x,y,columns,rows: These values define the perimeter of a region of
2997 % o exception: return any errors or warnings in this structure.
3000 static const Quantum *GetVirtualPixelCache(const Image *image,
3001 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3002 const size_t columns,const size_t rows,ExceptionInfo *exception)
3005 *magick_restrict cache_info;
3008 id = GetOpenMPThreadId();
3013 assert(image != (const Image *) NULL);
3014 assert(image->signature == MagickCoreSignature);
3015 assert(image->cache != (Cache) NULL);
3016 cache_info=(CacheInfo *) image->cache;
3017 assert(cache_info->signature == MagickCoreSignature);
3018 assert(id < (int) cache_info->number_threads);
3019 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3020 cache_info->nexus_info[id],exception);
3025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3029 % G e t V i r t u a l P i x e l Q u e u e %
3033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3035 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3036 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3038 % The format of the GetVirtualPixelQueue() method is:
3040 % const Quantum *GetVirtualPixelQueue(const Image image)
3042 % A description of each parameter follows:
3044 % o image: the image.
3047 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3050 *magick_restrict cache_info;
3053 id = GetOpenMPThreadId();
3055 assert(image != (const Image *) NULL);
3056 assert(image->signature == MagickCoreSignature);
3057 assert(image->cache != (Cache) NULL);
3058 cache_info=(CacheInfo *) image->cache;
3059 assert(cache_info->signature == MagickCoreSignature);
3060 if (cache_info->methods.get_virtual_pixels_handler !=
3061 (GetVirtualPixelsHandler) NULL)
3062 return(cache_info->methods.get_virtual_pixels_handler(image));
3063 assert(id < (int) cache_info->number_threads);
3064 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3072 % G e t V i r t u a l P i x e l s %
3076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3078 % GetVirtualPixels() returns an immutable pixel region. If the
3079 % region is successfully accessed, a pointer to it is returned, otherwise
3080 % NULL is returned. The returned pointer may point to a temporary working
3081 % copy of the pixels or it may point to the original pixels in memory.
3082 % Performance is maximized if the selected region is part of one row, or one
3083 % or more full rows, since there is opportunity to access the pixels in-place
3084 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3085 % returned pointer must *never* be deallocated by the user.
3087 % Pixels accessed via the returned pointer represent a simple array of type
3088 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3089 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3090 % access the meta-content (of type void) corresponding to the the
3093 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3095 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3096 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3097 % GetCacheViewAuthenticPixels() instead.
3099 % The format of the GetVirtualPixels() method is:
3101 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3102 % const ssize_t y,const size_t columns,const size_t rows,
3103 % ExceptionInfo *exception)
3105 % A description of each parameter follows:
3107 % o image: the image.
3109 % o x,y,columns,rows: These values define the perimeter of a region of
3112 % o exception: return any errors or warnings in this structure.
3115 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3116 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3117 ExceptionInfo *exception)
3120 *magick_restrict cache_info;
3123 id = GetOpenMPThreadId();
3128 assert(image != (const Image *) NULL);
3129 assert(image->signature == MagickCoreSignature);
3130 assert(image->cache != (Cache) NULL);
3131 cache_info=(CacheInfo *) image->cache;
3132 assert(cache_info->signature == MagickCoreSignature);
3133 if (cache_info->methods.get_virtual_pixel_handler !=
3134 (GetVirtualPixelHandler) NULL)
3135 return(cache_info->methods.get_virtual_pixel_handler(image,
3136 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3137 assert(id < (int) cache_info->number_threads);
3138 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3139 columns,rows,cache_info->nexus_info[id],exception);
3144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3148 + 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 %
3152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3154 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3155 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3157 % The format of the GetVirtualPixelsCache() method is:
3159 % Quantum *GetVirtualPixelsCache(const Image *image)
3161 % A description of each parameter follows:
3163 % o image: the image.
3166 static const Quantum *GetVirtualPixelsCache(const Image *image)
3169 *magick_restrict cache_info;
3172 id = GetOpenMPThreadId();
3174 assert(image != (const Image *) NULL);
3175 assert(image->signature == MagickCoreSignature);
3176 assert(image->cache != (Cache) NULL);
3177 cache_info=(CacheInfo *) image->cache;
3178 assert(cache_info->signature == MagickCoreSignature);
3179 assert(id < (int) cache_info->number_threads);
3180 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3188 + G e t V i r t u a l P i x e l s N e x u s %
3192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3194 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3197 % The format of the GetVirtualPixelsNexus() method is:
3199 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3200 % NexusInfo *nexus_info)
3202 % A description of each parameter follows:
3204 % o cache: the pixel cache.
3206 % o nexus_info: the cache nexus to return the colormap pixels.
3209 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3210 NexusInfo *magick_restrict nexus_info)
3213 *magick_restrict cache_info;
3215 assert(cache != (Cache) NULL);
3216 cache_info=(CacheInfo *) cache;
3217 assert(cache_info->signature == MagickCoreSignature);
3218 if (cache_info->storage_class == UndefinedClass)
3219 return((Quantum *) NULL);
3220 return((const Quantum *) nexus_info->pixels);
3224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3228 + O p e n P i x e l C a c h e %
3232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3234 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3235 % dimensions, allocating space for the image pixels and optionally the
3236 % metacontent, and memory mapping the cache if it is disk based. The cache
3237 % nexus array is initialized as well.
3239 % The format of the OpenPixelCache() method is:
3241 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3242 % ExceptionInfo *exception)
3244 % A description of each parameter follows:
3246 % o image: the image.
3248 % o mode: ReadMode, WriteMode, or IOMode.
3250 % o exception: return any errors or warnings in this structure.
3254 #if defined(__cplusplus) || defined(c_plusplus)
3259 static void CacheSignalHandler(int status)
3261 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3265 #if defined(__cplusplus) || defined(c_plusplus)
3269 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3276 Open pixel cache on disk.
3278 if ((cache_info->file != -1) && (cache_info->mode == mode))
3279 return(MagickTrue); /* cache already open and in the proper mode */
3280 if (*cache_info->cache_filename == '\0')
3281 file=AcquireUniqueFileResource(cache_info->cache_filename);
3287 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3292 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3293 O_BINARY | O_EXCL,S_MODE);
3295 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3301 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3304 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3309 return(MagickFalse);
3310 (void) AcquireMagickResource(FileResource,1);
3311 if (cache_info->file != -1)
3312 (void) ClosePixelCacheOnDisk(cache_info);
3313 cache_info->file=file;
3317 static inline MagickOffsetType WritePixelCacheRegion(
3318 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3319 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3321 register MagickOffsetType
3327 #if !defined(MAGICKCORE_HAVE_PWRITE)
3328 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3329 return((MagickOffsetType) -1);
3332 for (i=0; i < (MagickOffsetType) length; i+=count)
3334 #if !defined(MAGICKCORE_HAVE_PWRITE)
3335 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3338 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3339 SSIZE_MAX),(off_t) (offset+i));
3351 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3354 *magick_restrict cache_info;
3361 cache_info=(CacheInfo *) image->cache;
3362 if (image->debug != MagickFalse)
3365 format[MagickPathExtent],
3366 message[MagickPathExtent];
3368 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3369 (void) FormatLocaleString(message,MagickPathExtent,
3370 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3371 cache_info->cache_filename,cache_info->file,format);
3372 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3374 if (length != (MagickSizeType) ((MagickOffsetType) length))
3375 return(MagickFalse);
3376 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3378 return(MagickFalse);
3379 if ((MagickSizeType) offset >= length)
3380 count=(MagickOffsetType) 1;
3383 extent=(MagickOffsetType) length-1;
3384 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3387 return(MagickFalse);
3388 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3389 if (cache_info->synchronize != MagickFalse)
3390 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3393 (void) signal(SIGBUS,CacheSignalHandler);
3396 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3398 return(MagickFalse);
3399 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3402 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3403 ExceptionInfo *exception)
3406 *magick_restrict cache_info,
3410 format[MagickPathExtent],
3411 message[MagickPathExtent];
3427 assert(image != (const Image *) NULL);
3428 assert(image->signature == MagickCoreSignature);
3429 assert(image->cache != (Cache) NULL);
3430 if (image->debug != MagickFalse)
3431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3432 if ((image->columns == 0) || (image->rows == 0))
3433 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3434 cache_info=(CacheInfo *) image->cache;
3435 assert(cache_info->signature == MagickCoreSignature);
3436 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3437 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3438 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3440 source_info=(*cache_info);
3441 source_info.file=(-1);
3442 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3443 image->filename,(double) GetImageIndexInList(image));
3444 cache_info->storage_class=image->storage_class;
3445 cache_info->colorspace=image->colorspace;
3446 cache_info->alpha_trait=image->alpha_trait;
3447 cache_info->read_mask=image->read_mask;
3448 cache_info->write_mask=image->write_mask;
3449 cache_info->rows=image->rows;
3450 cache_info->columns=image->columns;
3451 InitializePixelChannelMap(image);
3452 cache_info->number_channels=GetPixelChannels(image);
3453 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3454 sizeof(*image->channel_map));
3455 cache_info->metacontent_extent=image->metacontent_extent;
3456 cache_info->mode=mode;
3457 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3458 packet_size=cache_info->number_channels*sizeof(Quantum);
3459 if (image->metacontent_extent != 0)
3460 packet_size+=cache_info->metacontent_extent;
3461 length=number_pixels*packet_size;
3462 columns=(size_t) (length/cache_info->rows/packet_size);
3463 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3464 ((ssize_t) cache_info->rows < 0))
3465 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3467 cache_info->length=length;
3468 if (image->ping != MagickFalse)
3470 cache_info->storage_class=image->storage_class;
3471 cache_info->colorspace=image->colorspace;
3472 cache_info->type=PingCache;
3475 status=AcquireMagickResource(AreaResource,cache_info->length);
3476 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3477 cache_info->metacontent_extent);
3478 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3480 status=AcquireMagickResource(MemoryResource,cache_info->length);
3481 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3482 (cache_info->type == MemoryCache))
3485 cache_info->mapped=MagickFalse;
3486 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3487 AcquireAlignedMemory(1,(size_t) cache_info->length));
3488 if (cache_info->pixels == (Quantum *) NULL)
3489 cache_info->pixels=source_info.pixels;
3493 Create memory pixel cache.
3495 cache_info->type=MemoryCache;
3496 cache_info->metacontent=(void *) NULL;
3497 if (cache_info->metacontent_extent != 0)
3498 cache_info->metacontent=(void *) (cache_info->pixels+
3499 number_pixels*cache_info->number_channels);
3500 if ((source_info.storage_class != UndefinedClass) &&
3503 status=ClonePixelCacheRepository(cache_info,&source_info,
3505 RelinquishPixelCachePixels(&source_info);
3507 if (image->debug != MagickFalse)
3509 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3510 MagickPathExtent,format);
3511 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3513 (void) FormatLocaleString(message,MagickPathExtent,
3514 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3515 cache_info->filename,cache_info->mapped != MagickFalse ?
3516 "Anonymous" : "Heap",type,(double) cache_info->columns,
3517 (double) cache_info->rows,(double)
3518 cache_info->number_channels,format);
3519 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3522 return(status == 0 ? MagickFalse : MagickTrue);
3525 RelinquishMagickResource(MemoryResource,cache_info->length);
3528 Create pixel cache on disk.
3530 status=AcquireMagickResource(DiskResource,cache_info->length);
3531 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3536 if (cache_info->type == DistributedCache)
3537 RelinquishMagickResource(DiskResource,cache_info->length);
3538 server_info=AcquireDistributeCacheInfo(exception);
3539 if (server_info != (DistributeCacheInfo *) NULL)
3541 status=OpenDistributePixelCache(server_info,image);
3542 if (status == MagickFalse)
3544 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3545 GetDistributeCacheHostname(server_info));
3546 server_info=DestroyDistributeCacheInfo(server_info);
3551 Create a distributed pixel cache.
3554 cache_info->type=DistributedCache;
3555 cache_info->server_info=server_info;
3556 (void) FormatLocaleString(cache_info->cache_filename,
3557 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3558 (DistributeCacheInfo *) cache_info->server_info),
3559 GetDistributeCachePort((DistributeCacheInfo *)
3560 cache_info->server_info));
3561 if ((source_info.storage_class != UndefinedClass) &&
3564 status=ClonePixelCacheRepository(cache_info,&source_info,
3566 RelinquishPixelCachePixels(&source_info);
3568 if (image->debug != MagickFalse)
3570 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3571 MagickPathExtent,format);
3572 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3574 (void) FormatLocaleString(message,MagickPathExtent,
3575 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3576 cache_info->filename,cache_info->cache_filename,
3577 GetDistributeCacheFile((DistributeCacheInfo *)
3578 cache_info->server_info),type,(double) cache_info->columns,
3579 (double) cache_info->rows,(double)
3580 cache_info->number_channels,format);
3581 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3584 return(status == 0 ? MagickFalse : MagickTrue);
3587 RelinquishMagickResource(DiskResource,cache_info->length);
3588 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3589 "CacheResourcesExhausted","`%s'",image->filename);
3590 return(MagickFalse);
3592 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3594 (void) ClosePixelCacheOnDisk(cache_info);
3595 *cache_info->cache_filename='\0';
3597 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3599 RelinquishMagickResource(DiskResource,cache_info->length);
3600 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3602 return(MagickFalse);
3604 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3605 cache_info->length);
3606 if (status == MagickFalse)
3608 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3610 return(MagickFalse);
3612 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3613 cache_info->metacontent_extent);
3614 if (length != (MagickSizeType) ((size_t) length))
3615 cache_info->type=DiskCache;
3618 status=AcquireMagickResource(MapResource,cache_info->length);
3619 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3620 (cache_info->type != MemoryCache))
3623 cache_info->type=DiskCache;
3628 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3629 cache_info->offset,(size_t) cache_info->length);
3630 if (cache_info->pixels == (Quantum *) NULL)
3632 cache_info->type=DiskCache;
3633 cache_info->pixels=source_info.pixels;
3638 Create file-backed memory-mapped pixel cache.
3640 (void) ClosePixelCacheOnDisk(cache_info);
3641 cache_info->type=MapCache;
3642 cache_info->mapped=MagickTrue;
3643 cache_info->metacontent=(void *) NULL;
3644 if (cache_info->metacontent_extent != 0)
3645 cache_info->metacontent=(void *) (cache_info->pixels+
3646 number_pixels*cache_info->number_channels);
3647 if ((source_info.storage_class != UndefinedClass) &&
3650 status=ClonePixelCacheRepository(cache_info,&source_info,
3652 RelinquishPixelCachePixels(&source_info);
3654 if (image->debug != MagickFalse)
3656 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3657 MagickPathExtent,format);
3658 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3660 (void) FormatLocaleString(message,MagickPathExtent,
3661 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3662 cache_info->filename,cache_info->cache_filename,
3663 cache_info->file,type,(double) cache_info->columns,(double)
3664 cache_info->rows,(double) cache_info->number_channels,
3666 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3669 return(status == 0 ? MagickFalse : MagickTrue);
3672 RelinquishMagickResource(MapResource,cache_info->length);
3675 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3677 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3678 RelinquishPixelCachePixels(&source_info);
3680 if (image->debug != MagickFalse)
3682 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3683 MagickPathExtent,format);
3684 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3686 (void) FormatLocaleString(message,MagickPathExtent,
3687 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3688 cache_info->cache_filename,cache_info->file,type,(double)
3689 cache_info->columns,(double) cache_info->rows,(double)
3690 cache_info->number_channels,format);
3691 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3693 return(status == 0 ? MagickFalse : MagickTrue);
3697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3701 + P e r s i s t P i x e l C a c h e %
3705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3707 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3708 % persistent pixel cache is one that resides on disk and is not destroyed
3709 % when the program exits.
3711 % The format of the PersistPixelCache() method is:
3713 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3714 % const MagickBooleanType attach,MagickOffsetType *offset,
3715 % ExceptionInfo *exception)
3717 % A description of each parameter follows:
3719 % o image: the image.
3721 % o filename: the persistent pixel cache filename.
3723 % o attach: A value other than zero initializes the persistent pixel cache.
3725 % o initialize: A value other than zero initializes the persistent pixel
3728 % o offset: the offset in the persistent cache to store pixels.
3730 % o exception: return any errors or warnings in this structure.
3733 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3734 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3735 ExceptionInfo *exception)
3738 *magick_restrict cache_info,
3739 *magick_restrict clone_info;
3750 assert(image != (Image *) NULL);
3751 assert(image->signature == MagickCoreSignature);
3752 if (image->debug != MagickFalse)
3753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3754 assert(image->cache != (void *) NULL);
3755 assert(filename != (const char *) NULL);
3756 assert(offset != (MagickOffsetType *) NULL);
3757 page_size=GetMagickPageSize();
3758 cache_info=(CacheInfo *) image->cache;
3759 assert(cache_info->signature == MagickCoreSignature);
3760 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3761 CopyOpenCLBuffer(cache_info);
3763 if (attach != MagickFalse)
3766 Attach existing persistent pixel cache.
3768 if (image->debug != MagickFalse)
3769 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3770 "attach persistent cache");
3771 (void) CopyMagickString(cache_info->cache_filename,filename,
3773 cache_info->type=DiskCache;
3774 cache_info->offset=(*offset);
3775 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3776 return(MagickFalse);
3777 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3780 if ((cache_info->mode != ReadMode) &&
3781 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3782 (cache_info->reference_count == 1))
3784 LockSemaphoreInfo(cache_info->semaphore);
3785 if ((cache_info->mode != ReadMode) &&
3786 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3787 (cache_info->reference_count == 1))
3790 Usurp existing persistent pixel cache.
3792 if (rename_utf8(cache_info->cache_filename, filename) == 0)
3794 (void) CopyMagickString(cache_info->cache_filename,filename,
3796 *offset+=cache_info->length+page_size-(cache_info->length %
3798 UnlockSemaphoreInfo(cache_info->semaphore);
3799 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3800 if (image->debug != MagickFalse)
3801 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3802 "Usurp resident persistent cache");
3806 UnlockSemaphoreInfo(cache_info->semaphore);
3809 Clone persistent pixel cache.
3811 clone_image=(*image);
3812 clone_info=(CacheInfo *) clone_image.cache;
3813 image->cache=ClonePixelCache(cache_info);
3814 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3815 (void) CopyMagickString(cache_info->cache_filename,filename,MagickPathExtent);
3816 cache_info->type=DiskCache;
3817 cache_info->offset=(*offset);
3818 cache_info=(CacheInfo *) image->cache;
3819 status=OpenPixelCache(image,IOMode,exception);
3820 if (status != MagickFalse)
3821 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3822 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3823 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3832 + 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 %
3836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3838 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3839 % defined by the region rectangle and returns a pointer to the region. This
3840 % region is subsequently transferred from the pixel cache with
3841 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3842 % pixels are transferred, otherwise a NULL is returned.
3844 % The format of the QueueAuthenticPixelCacheNexus() method is:
3846 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3847 % const ssize_t y,const size_t columns,const size_t rows,
3848 % const MagickBooleanType clone,NexusInfo *nexus_info,
3849 % ExceptionInfo *exception)
3851 % A description of each parameter follows:
3853 % o image: the image.
3855 % o x,y,columns,rows: These values define the perimeter of a region of
3858 % o nexus_info: the cache nexus to set.
3860 % o clone: clone the pixel cache.
3862 % o exception: return any errors or warnings in this structure.
3865 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3866 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3867 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3870 *magick_restrict cache_info;
3879 *magick_restrict pixels;
3885 Validate pixel cache geometry.
3887 assert(image != (const Image *) NULL);
3888 assert(image->signature == MagickCoreSignature);
3889 assert(image->cache != (Cache) NULL);
3890 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3891 if (cache_info == (Cache) NULL)
3892 return((Quantum *) NULL);
3893 assert(cache_info->signature == MagickCoreSignature);
3894 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3895 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3896 (y >= (ssize_t) cache_info->rows))
3898 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3899 "PixelsAreNotAuthentic","`%s'",image->filename);
3900 return((Quantum *) NULL);
3902 offset=(MagickOffsetType) y*cache_info->columns+x;
3904 return((Quantum *) NULL);
3905 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3906 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3907 if ((MagickSizeType) offset >= number_pixels)
3908 return((Quantum *) NULL);
3914 region.width=columns;
3916 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3926 + 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 %
3930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3932 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3933 % defined by the region rectangle and returns a pointer to the region. This
3934 % region is subsequently transferred from the pixel cache with
3935 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3936 % pixels are transferred, otherwise a NULL is returned.
3938 % The format of the QueueAuthenticPixelsCache() method is:
3940 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3941 % const ssize_t y,const size_t columns,const size_t rows,
3942 % ExceptionInfo *exception)
3944 % A description of each parameter follows:
3946 % o image: the image.
3948 % o x,y,columns,rows: These values define the perimeter of a region of
3951 % o exception: return any errors or warnings in this structure.
3954 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3955 const ssize_t y,const size_t columns,const size_t rows,
3956 ExceptionInfo *exception)
3959 *magick_restrict cache_info;
3962 id = GetOpenMPThreadId();
3965 *magick_restrict pixels;
3967 assert(image != (const Image *) NULL);
3968 assert(image->signature == MagickCoreSignature);
3969 assert(image->cache != (Cache) NULL);
3970 cache_info=(CacheInfo *) image->cache;
3971 assert(cache_info->signature == MagickCoreSignature);
3972 assert(id < (int) cache_info->number_threads);
3973 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3974 cache_info->nexus_info[id],exception);
3979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3983 % Q u e u e A u t h e n t i c P i x e l s %
3987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3989 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3990 % successfully initialized a pointer to a Quantum array representing the
3991 % region is returned, otherwise NULL is returned. The returned pointer may
3992 % point to a temporary working buffer for the pixels or it may point to the
3993 % final location of the pixels in memory.
3995 % Write-only access means that any existing pixel values corresponding to
3996 % the region are ignored. This is useful if the initial image is being
3997 % created from scratch, or if the existing pixel values are to be
3998 % completely replaced without need to refer to their pre-existing values.
3999 % The application is free to read and write the pixel buffer returned by
4000 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4001 % initialize the pixel array values. Initializing pixel array values is the
4002 % application's responsibility.
4004 % Performance is maximized if the selected region is part of one row, or
4005 % one or more full rows, since then there is opportunity to access the
4006 % pixels in-place (without a copy) if the image is in memory, or in a
4007 % memory-mapped file. The returned pointer must *never* be deallocated
4010 % Pixels accessed via the returned pointer represent a simple array of type
4011 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4012 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4013 % obtain the meta-content (of type void) corresponding to the region.
4014 % Once the Quantum (and/or Quantum) array has been updated, the
4015 % changes must be saved back to the underlying image using
4016 % SyncAuthenticPixels() or they may be lost.
4018 % The format of the QueueAuthenticPixels() method is:
4020 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4021 % const ssize_t y,const size_t columns,const size_t rows,
4022 % ExceptionInfo *exception)
4024 % A description of each parameter follows:
4026 % o image: the image.
4028 % o x,y,columns,rows: These values define the perimeter of a region of
4031 % o exception: return any errors or warnings in this structure.
4034 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4035 const ssize_t y,const size_t columns,const size_t rows,
4036 ExceptionInfo *exception)
4039 *magick_restrict cache_info;
4042 id = GetOpenMPThreadId();
4045 *magick_restrict pixels;
4047 assert(image != (Image *) NULL);
4048 assert(image->signature == MagickCoreSignature);
4049 assert(image->cache != (Cache) NULL);
4050 cache_info=(CacheInfo *) image->cache;
4051 assert(cache_info->signature == MagickCoreSignature);
4052 if (cache_info->methods.queue_authentic_pixels_handler !=
4053 (QueueAuthenticPixelsHandler) NULL)
4055 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4056 columns,rows,exception);
4059 assert(id < (int) cache_info->number_threads);
4060 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4061 cache_info->nexus_info[id],exception);
4066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4070 + 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 %
4074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4076 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4079 % The format of the ReadPixelCacheMetacontent() method is:
4081 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4082 % NexusInfo *nexus_info,ExceptionInfo *exception)
4084 % A description of each parameter follows:
4086 % o cache_info: the pixel cache.
4088 % o nexus_info: the cache nexus to read the metacontent.
4090 % o exception: return any errors or warnings in this structure.
4094 static inline MagickOffsetType ReadPixelCacheRegion(
4095 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4096 const MagickSizeType length,unsigned char *magick_restrict buffer)
4098 register MagickOffsetType
4104 #if !defined(MAGICKCORE_HAVE_PREAD)
4105 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4106 return((MagickOffsetType) -1);
4109 for (i=0; i < (MagickOffsetType) length; i+=count)
4111 #if !defined(MAGICKCORE_HAVE_PREAD)
4112 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4115 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4116 SSIZE_MAX),(off_t) (offset+i));
4128 static MagickBooleanType ReadPixelCacheMetacontent(
4129 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4130 ExceptionInfo *exception)
4143 register unsigned char
4149 if (cache_info->metacontent_extent == 0)
4150 return(MagickFalse);
4151 if (nexus_info->authentic_pixel_cache != MagickFalse)
4153 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4154 nexus_info->region.x;
4155 length=(MagickSizeType) nexus_info->region.width*
4156 cache_info->metacontent_extent;
4157 extent=length*nexus_info->region.height;
4158 rows=nexus_info->region.height;
4160 q=(unsigned char *) nexus_info->metacontent;
4161 switch (cache_info->type)
4166 register unsigned char
4170 Read meta-content from memory.
4172 if ((cache_info->columns == nexus_info->region.width) &&
4173 (extent == (MagickSizeType) ((size_t) extent)))
4178 p=(unsigned char *) cache_info->metacontent+offset*
4179 cache_info->metacontent_extent;
4180 for (y=0; y < (ssize_t) rows; y++)
4182 (void) memcpy(q,p,(size_t) length);
4183 p+=cache_info->metacontent_extent*cache_info->columns;
4184 q+=cache_info->metacontent_extent*nexus_info->region.width;
4191 Read meta content from disk.
4193 LockSemaphoreInfo(cache_info->file_semaphore);
4194 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4196 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4197 cache_info->cache_filename);
4198 UnlockSemaphoreInfo(cache_info->file_semaphore);
4199 return(MagickFalse);
4201 if ((cache_info->columns == nexus_info->region.width) &&
4202 (extent <= MagickMaxBufferExtent))
4207 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4208 for (y=0; y < (ssize_t) rows; y++)
4210 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4211 cache_info->number_channels*sizeof(Quantum)+offset*
4212 cache_info->metacontent_extent,length,(unsigned char *) q);
4213 if (count != (MagickOffsetType) length)
4215 offset+=cache_info->columns;
4216 q+=cache_info->metacontent_extent*nexus_info->region.width;
4218 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4219 (void) ClosePixelCacheOnDisk(cache_info);
4220 UnlockSemaphoreInfo(cache_info->file_semaphore);
4223 case DistributedCache:
4229 Read metacontent from distributed cache.
4231 LockSemaphoreInfo(cache_info->file_semaphore);
4232 region=nexus_info->region;
4233 if ((cache_info->columns != nexus_info->region.width) ||
4234 (extent > MagickMaxBufferExtent))
4241 for (y=0; y < (ssize_t) rows; y++)
4243 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4244 cache_info->server_info,®ion,length,(unsigned char *) q);
4245 if (count != (MagickOffsetType) length)
4247 q+=cache_info->metacontent_extent*nexus_info->region.width;
4250 UnlockSemaphoreInfo(cache_info->file_semaphore);
4256 if (y < (ssize_t) rows)
4258 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4259 cache_info->cache_filename);
4260 return(MagickFalse);
4262 if ((cache_info->debug != MagickFalse) &&
4263 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4264 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4265 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4266 nexus_info->region.width,(double) nexus_info->region.height,(double)
4267 nexus_info->region.x,(double) nexus_info->region.y);
4272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4276 + R e a d P i x e l C a c h e P i x e l s %
4280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4282 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4285 % The format of the ReadPixelCachePixels() method is:
4287 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4288 % NexusInfo *nexus_info,ExceptionInfo *exception)
4290 % A description of each parameter follows:
4292 % o cache_info: the pixel cache.
4294 % o nexus_info: the cache nexus to read the pixels.
4296 % o exception: return any errors or warnings in this structure.
4299 static MagickBooleanType ReadPixelCachePixels(
4300 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4301 ExceptionInfo *exception)
4321 if (nexus_info->authentic_pixel_cache != MagickFalse)
4323 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4324 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4325 return(MagickFalse);
4326 offset+=nexus_info->region.x;
4327 number_channels=cache_info->number_channels;
4328 length=(MagickSizeType) number_channels*nexus_info->region.width*
4330 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4331 return(MagickFalse);
4332 rows=nexus_info->region.height;
4334 if ((extent == 0) || ((extent/length) != rows))
4335 return(MagickFalse);
4337 q=nexus_info->pixels;
4338 switch (cache_info->type)
4347 Read pixels from memory.
4349 if ((cache_info->columns == nexus_info->region.width) &&
4350 (extent == (MagickSizeType) ((size_t) extent)))
4355 p=cache_info->pixels+offset*cache_info->number_channels;
4356 for (y=0; y < (ssize_t) rows; y++)
4358 (void) memcpy(q,p,(size_t) length);
4359 p+=cache_info->number_channels*cache_info->columns;
4360 q+=cache_info->number_channels*nexus_info->region.width;
4367 Read pixels from disk.
4369 LockSemaphoreInfo(cache_info->file_semaphore);
4370 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4372 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4373 cache_info->cache_filename);
4374 UnlockSemaphoreInfo(cache_info->file_semaphore);
4375 return(MagickFalse);
4377 if ((cache_info->columns == nexus_info->region.width) &&
4378 (extent <= MagickMaxBufferExtent))
4383 for (y=0; y < (ssize_t) rows; y++)
4385 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4386 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4387 if (count != (MagickOffsetType) length)
4389 offset+=cache_info->columns;
4390 q+=cache_info->number_channels*nexus_info->region.width;
4392 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4393 (void) ClosePixelCacheOnDisk(cache_info);
4394 UnlockSemaphoreInfo(cache_info->file_semaphore);
4397 case DistributedCache:
4403 Read pixels from distributed cache.
4405 LockSemaphoreInfo(cache_info->file_semaphore);
4406 region=nexus_info->region;
4407 if ((cache_info->columns != nexus_info->region.width) ||
4408 (extent > MagickMaxBufferExtent))
4415 for (y=0; y < (ssize_t) rows; y++)
4417 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4418 cache_info->server_info,®ion,length,(unsigned char *) q);
4419 if (count != (MagickOffsetType) length)
4421 q+=cache_info->number_channels*nexus_info->region.width;
4424 UnlockSemaphoreInfo(cache_info->file_semaphore);
4430 if (y < (ssize_t) rows)
4432 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4433 cache_info->cache_filename);
4434 return(MagickFalse);
4436 if ((cache_info->debug != MagickFalse) &&
4437 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4438 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4439 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4440 nexus_info->region.width,(double) nexus_info->region.height,(double)
4441 nexus_info->region.x,(double) nexus_info->region.y);
4446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4450 + R e f e r e n c e P i x e l C a c h e %
4454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4456 % ReferencePixelCache() increments the reference count associated with the
4457 % pixel cache returning a pointer to the cache.
4459 % The format of the ReferencePixelCache method is:
4461 % Cache ReferencePixelCache(Cache cache_info)
4463 % A description of each parameter follows:
4465 % o cache_info: the pixel cache.
4468 MagickPrivate Cache ReferencePixelCache(Cache cache)
4471 *magick_restrict cache_info;
4473 assert(cache != (Cache *) NULL);
4474 cache_info=(CacheInfo *) cache;
4475 assert(cache_info->signature == MagickCoreSignature);
4476 LockSemaphoreInfo(cache_info->semaphore);
4477 cache_info->reference_count++;
4478 UnlockSemaphoreInfo(cache_info->semaphore);
4483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4487 + R e s e t P i x e l C a c h e C h a n n e l s %
4491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493 % ResetPixelCacheChannels() resets the pixel cache channels.
4495 % The format of the ResetPixelCacheChannels method is:
4497 % void ResetPixelCacheChannels(Image *)
4499 % A description of each parameter follows:
4501 % o image: the image.
4504 MagickPrivate void ResetPixelCacheChannels(Image *image)
4507 *magick_restrict cache_info;
4509 assert(image != (const Image *) NULL);
4510 assert(image->signature == MagickCoreSignature);
4511 assert(image->cache != (Cache) NULL);
4512 cache_info=(CacheInfo *) image->cache;
4513 assert(cache_info->signature == MagickCoreSignature);
4514 cache_info->number_channels=GetPixelChannels(image);
4518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4522 + R e s e t P i x e l C a c h e E p o c h %
4526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4528 % ResetPixelCacheEpoch() resets the pixel cache epoch.
4530 % The format of the ResetPixelCacheEpoch method is:
4532 % void ResetPixelCacheEpoch(void)
4535 MagickPrivate void ResetPixelCacheEpoch(void)
4541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4545 + S e t P i x e l C a c h e M e t h o d s %
4549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4551 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4553 % The format of the SetPixelCacheMethods() method is:
4555 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4557 % A description of each parameter follows:
4559 % o cache: the pixel cache.
4561 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4564 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4567 *magick_restrict cache_info;
4569 GetOneAuthenticPixelFromHandler
4570 get_one_authentic_pixel_from_handler;
4572 GetOneVirtualPixelFromHandler
4573 get_one_virtual_pixel_from_handler;
4576 Set cache pixel methods.
4578 assert(cache != (Cache) NULL);
4579 assert(cache_methods != (CacheMethods *) NULL);
4580 cache_info=(CacheInfo *) cache;
4581 assert(cache_info->signature == MagickCoreSignature);
4582 if (cache_info->debug != MagickFalse)
4583 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4584 cache_info->filename);
4585 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4586 cache_info->methods.get_virtual_pixel_handler=
4587 cache_methods->get_virtual_pixel_handler;
4588 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4589 cache_info->methods.destroy_pixel_handler=
4590 cache_methods->destroy_pixel_handler;
4591 if (cache_methods->get_virtual_metacontent_from_handler !=
4592 (GetVirtualMetacontentFromHandler) NULL)
4593 cache_info->methods.get_virtual_metacontent_from_handler=
4594 cache_methods->get_virtual_metacontent_from_handler;
4595 if (cache_methods->get_authentic_pixels_handler !=
4596 (GetAuthenticPixelsHandler) NULL)
4597 cache_info->methods.get_authentic_pixels_handler=
4598 cache_methods->get_authentic_pixels_handler;
4599 if (cache_methods->queue_authentic_pixels_handler !=
4600 (QueueAuthenticPixelsHandler) NULL)
4601 cache_info->methods.queue_authentic_pixels_handler=
4602 cache_methods->queue_authentic_pixels_handler;
4603 if (cache_methods->sync_authentic_pixels_handler !=
4604 (SyncAuthenticPixelsHandler) NULL)
4605 cache_info->methods.sync_authentic_pixels_handler=
4606 cache_methods->sync_authentic_pixels_handler;
4607 if (cache_methods->get_authentic_pixels_from_handler !=
4608 (GetAuthenticPixelsFromHandler) NULL)
4609 cache_info->methods.get_authentic_pixels_from_handler=
4610 cache_methods->get_authentic_pixels_from_handler;
4611 if (cache_methods->get_authentic_metacontent_from_handler !=
4612 (GetAuthenticMetacontentFromHandler) NULL)
4613 cache_info->methods.get_authentic_metacontent_from_handler=
4614 cache_methods->get_authentic_metacontent_from_handler;
4615 get_one_virtual_pixel_from_handler=
4616 cache_info->methods.get_one_virtual_pixel_from_handler;
4617 if (get_one_virtual_pixel_from_handler !=
4618 (GetOneVirtualPixelFromHandler) NULL)
4619 cache_info->methods.get_one_virtual_pixel_from_handler=
4620 cache_methods->get_one_virtual_pixel_from_handler;
4621 get_one_authentic_pixel_from_handler=
4622 cache_methods->get_one_authentic_pixel_from_handler;
4623 if (get_one_authentic_pixel_from_handler !=
4624 (GetOneAuthenticPixelFromHandler) NULL)
4625 cache_info->methods.get_one_authentic_pixel_from_handler=
4626 cache_methods->get_one_authentic_pixel_from_handler;
4630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4634 + S e t P i x e l C a c h e N e x u s P i x e l s %
4638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4640 % SetPixelCacheNexusPixels() defines the region of the cache for the
4641 % specified cache nexus.
4643 % The format of the SetPixelCacheNexusPixels() method is:
4645 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4646 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4647 % ExceptionInfo *exception)
4649 % A description of each parameter follows:
4651 % o cache_info: the pixel cache.
4653 % o mode: ReadMode, WriteMode, or IOMode.
4655 % o region: A pointer to the RectangleInfo structure that defines the
4656 % region of this particular cache nexus.
4658 % o nexus_info: the cache nexus to set.
4660 % o exception: return any errors or warnings in this structure.
4664 static inline MagickBooleanType AcquireCacheNexusPixels(
4665 const CacheInfo *magick_restrict cache_info,NexusInfo *nexus_info,
4666 ExceptionInfo *exception)
4668 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4669 return(MagickFalse);
4670 nexus_info->mapped=MagickFalse;
4671 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4672 (size_t) nexus_info->length));
4673 if (nexus_info->cache == (Quantum *) NULL)
4675 nexus_info->mapped=MagickTrue;
4676 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4677 nexus_info->length);
4679 if (nexus_info->cache == (Quantum *) NULL)
4681 (void) ThrowMagickException(exception,GetMagickModule(),
4682 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4683 cache_info->filename);
4684 return(MagickFalse);
4689 static inline MagickBooleanType IsPixelCacheAuthentic(
4690 const CacheInfo *magick_restrict cache_info,
4691 const NexusInfo *magick_restrict nexus_info)
4700 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4702 if (cache_info->type == PingCache)
4704 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4705 nexus_info->region.x;
4706 status=nexus_info->pixels == (cache_info->pixels+offset*
4707 cache_info->number_channels) ? MagickTrue : MagickFalse;
4711 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4714 if (mode == ReadMode)
4716 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4719 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4722 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4723 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4724 ExceptionInfo *exception)
4733 assert(cache_info != (const CacheInfo *) NULL);
4734 assert(cache_info->signature == MagickCoreSignature);
4735 if (cache_info->type == UndefinedCache)
4736 return((Quantum *) NULL);
4737 nexus_info->region=(*region);
4738 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4744 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4745 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4746 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4747 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4748 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4749 ((nexus_info->region.width == cache_info->columns) ||
4750 ((nexus_info->region.width % cache_info->columns) == 0)))))
4756 Pixels are accessed directly from memory.
4758 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4759 nexus_info->region.x;
4760 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4762 nexus_info->metacontent=(void *) NULL;
4763 if (cache_info->metacontent_extent != 0)
4764 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4765 offset*cache_info->metacontent_extent;
4766 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4767 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4769 return(nexus_info->pixels);
4773 Pixels are stored in a staging region until they are synced to the cache.
4775 number_pixels=(MagickSizeType) nexus_info->region.width*
4776 nexus_info->region.height;
4777 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4778 if (cache_info->metacontent_extent != 0)
4779 length+=number_pixels*cache_info->metacontent_extent;
4780 if (nexus_info->cache == (Quantum *) NULL)
4782 nexus_info->length=length;
4783 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4784 if (status == MagickFalse)
4786 nexus_info->length=0;
4787 return((Quantum *) NULL);
4791 if (nexus_info->length < length)
4793 RelinquishCacheNexusPixels(nexus_info);
4794 nexus_info->length=length;
4795 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4796 if (status == MagickFalse)
4798 nexus_info->length=0;
4799 return((Quantum *) NULL);
4802 nexus_info->pixels=nexus_info->cache;
4803 nexus_info->metacontent=(void *) NULL;
4804 if (cache_info->metacontent_extent != 0)
4805 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4806 cache_info->number_channels);
4807 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4808 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4810 return(nexus_info->pixels);
4814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4818 % 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 %
4822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4824 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4825 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4826 % access that is outside the boundaries of the image cache.
4828 % The format of the SetPixelCacheVirtualMethod() method is:
4830 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4831 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4833 % A description of each parameter follows:
4835 % o image: the image.
4837 % o virtual_pixel_method: choose the type of virtual pixel.
4839 % o exception: return any errors or warnings in this structure.
4843 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4844 ExceptionInfo *exception)
4847 *magick_restrict cache_info;
4850 *magick_restrict image_view;
4858 assert(image != (Image *) NULL);
4859 assert(image->signature == MagickCoreSignature);
4860 if (image->debug != MagickFalse)
4861 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4862 assert(image->cache != (Cache) NULL);
4863 cache_info=(CacheInfo *) image->cache;
4864 assert(cache_info->signature == MagickCoreSignature);
4865 image->alpha_trait=BlendPixelTrait;
4867 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4868 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4869 #pragma omp parallel for schedule(static,4) shared(status) \
4870 magick_threads(image,image,1,1)
4872 for (y=0; y < (ssize_t) image->rows; y++)
4880 if (status == MagickFalse)
4882 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4883 if (q == (Quantum *) NULL)
4888 for (x=0; x < (ssize_t) image->columns; x++)
4890 SetPixelAlpha(image,alpha,q);
4891 q+=GetPixelChannels(image);
4893 status=SyncCacheViewAuthenticPixels(image_view,exception);
4895 image_view=DestroyCacheView(image_view);
4899 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4900 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4903 *magick_restrict cache_info;
4908 assert(image != (Image *) NULL);
4909 assert(image->signature == MagickCoreSignature);
4910 if (image->debug != MagickFalse)
4911 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4912 assert(image->cache != (Cache) NULL);
4913 cache_info=(CacheInfo *) image->cache;
4914 assert(cache_info->signature == MagickCoreSignature);
4915 method=cache_info->virtual_pixel_method;
4916 cache_info->virtual_pixel_method=virtual_pixel_method;
4917 if ((image->columns != 0) && (image->rows != 0))
4918 switch (virtual_pixel_method)
4920 case BackgroundVirtualPixelMethod:
4922 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4923 (image->alpha_trait == UndefinedPixelTrait))
4924 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4925 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4926 (IsGrayColorspace(image->colorspace) != MagickFalse))
4927 (void) SetImageColorspace(image,sRGBColorspace,exception);
4930 case TransparentVirtualPixelMethod:
4932 if (image->alpha_trait == UndefinedPixelTrait)
4933 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4942 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4948 + S y n c A u t h e n t i c O p e n C L B u f f e r %
4952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4954 % SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
4955 % been completed and updates the host memory.
4957 % The format of the SyncAuthenticOpenCLBuffer() method is:
4959 % void SyncAuthenticOpenCLBuffer(const Image *image)
4961 % A description of each parameter follows:
4963 % o image: the image.
4966 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
4968 assert(cache_info != (CacheInfo *) NULL);
4969 assert(cache_info->signature == MagickCoreSignature);
4970 if ((cache_info->type != MemoryCache) ||
4971 (cache_info->opencl == (MagickCLCacheInfo) NULL))
4974 Ensure single threaded access to OpenCL environment.
4976 LockSemaphoreInfo(cache_info->semaphore);
4977 cache_info->opencl=(MagickCLCacheInfo) CopyMagickCLCacheInfo(
4978 cache_info->opencl);
4979 UnlockSemaphoreInfo(cache_info->semaphore);
4982 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
4985 *magick_restrict cache_info;
4987 assert(image != (const Image *) NULL);
4988 cache_info=(CacheInfo *) image->cache;
4989 CopyOpenCLBuffer(cache_info);
4994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4998 + 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 %
5002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5004 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5005 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5006 % is synced, otherwise MagickFalse.
5008 % The format of the SyncAuthenticPixelCacheNexus() method is:
5010 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5011 % NexusInfo *nexus_info,ExceptionInfo *exception)
5013 % A description of each parameter follows:
5015 % o image: the image.
5017 % o nexus_info: the cache nexus to sync.
5019 % o exception: return any errors or warnings in this structure.
5022 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5023 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5026 *magick_restrict cache_info;
5032 Transfer pixels to the cache.
5034 assert(image != (Image *) NULL);
5035 assert(image->signature == MagickCoreSignature);
5036 if (image->cache == (Cache) NULL)
5037 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5038 cache_info=(CacheInfo *) image->cache;
5039 assert(cache_info->signature == MagickCoreSignature);
5040 if (cache_info->type == UndefinedCache)
5041 return(MagickFalse);
5042 if (nexus_info->authentic_pixel_cache != MagickFalse)
5044 image->taint=MagickTrue;
5047 assert(cache_info->signature == MagickCoreSignature);
5048 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5049 if ((cache_info->metacontent_extent != 0) &&
5050 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5051 return(MagickFalse);
5052 if (status != MagickFalse)
5053 image->taint=MagickTrue;
5058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5062 + S y n c A u t h e n t i c P i x e l C a c h e %
5066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5068 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5069 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5070 % otherwise MagickFalse.
5072 % The format of the SyncAuthenticPixelsCache() method is:
5074 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5075 % ExceptionInfo *exception)
5077 % A description of each parameter follows:
5079 % o image: the image.
5081 % o exception: return any errors or warnings in this structure.
5084 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5085 ExceptionInfo *exception)
5088 *magick_restrict cache_info;
5091 id = GetOpenMPThreadId();
5096 assert(image != (Image *) NULL);
5097 assert(image->signature == MagickCoreSignature);
5098 assert(image->cache != (Cache) NULL);
5099 cache_info=(CacheInfo *) image->cache;
5100 assert(cache_info->signature == MagickCoreSignature);
5101 assert(id < (int) cache_info->number_threads);
5102 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5112 % S y n c A u t h e n t i c P i x e l s %
5116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5118 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5119 % The method returns MagickTrue if the pixel region is flushed, otherwise
5122 % The format of the SyncAuthenticPixels() method is:
5124 % MagickBooleanType SyncAuthenticPixels(Image *image,
5125 % ExceptionInfo *exception)
5127 % A description of each parameter follows:
5129 % o image: the image.
5131 % o exception: return any errors or warnings in this structure.
5134 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5135 ExceptionInfo *exception)
5138 *magick_restrict cache_info;
5141 id = GetOpenMPThreadId();
5146 assert(image != (Image *) NULL);
5147 assert(image->signature == MagickCoreSignature);
5148 assert(image->cache != (Cache) NULL);
5149 cache_info=(CacheInfo *) image->cache;
5150 assert(cache_info->signature == MagickCoreSignature);
5151 if (cache_info->methods.sync_authentic_pixels_handler !=
5152 (SyncAuthenticPixelsHandler) NULL)
5154 status=cache_info->methods.sync_authentic_pixels_handler(image,
5158 assert(id < (int) cache_info->number_threads);
5159 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5169 + S y n c I m a g e P i x e l C a c h e %
5173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5176 % The method returns MagickTrue if the pixel region is flushed, otherwise
5179 % The format of the SyncImagePixelCache() method is:
5181 % MagickBooleanType SyncImagePixelCache(Image *image,
5182 % ExceptionInfo *exception)
5184 % A description of each parameter follows:
5186 % o image: the image.
5188 % o exception: return any errors or warnings in this structure.
5191 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5192 ExceptionInfo *exception)
5195 *magick_restrict cache_info;
5197 assert(image != (Image *) NULL);
5198 assert(exception != (ExceptionInfo *) NULL);
5199 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5200 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5208 + 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 %
5212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5214 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5215 % of the pixel cache.
5217 % The format of the WritePixelCacheMetacontent() method is:
5219 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5220 % NexusInfo *nexus_info,ExceptionInfo *exception)
5222 % A description of each parameter follows:
5224 % o cache_info: the pixel cache.
5226 % o nexus_info: the cache nexus to write the meta-content.
5228 % o exception: return any errors or warnings in this structure.
5231 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5232 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5242 register const unsigned char
5251 if (cache_info->metacontent_extent == 0)
5252 return(MagickFalse);
5253 if (nexus_info->authentic_pixel_cache != MagickFalse)
5255 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5256 nexus_info->region.x;
5257 length=(MagickSizeType) nexus_info->region.width*
5258 cache_info->metacontent_extent;
5259 extent=(MagickSizeType) length*nexus_info->region.height;
5260 rows=nexus_info->region.height;
5262 p=(unsigned char *) nexus_info->metacontent;
5263 switch (cache_info->type)
5268 register unsigned char
5272 Write associated pixels to memory.
5274 if ((cache_info->columns == nexus_info->region.width) &&
5275 (extent == (MagickSizeType) ((size_t) extent)))
5280 q=(unsigned char *) cache_info->metacontent+offset*
5281 cache_info->metacontent_extent;
5282 for (y=0; y < (ssize_t) rows; y++)
5284 (void) memcpy(q,p,(size_t) length);
5285 p+=nexus_info->region.width*cache_info->metacontent_extent;
5286 q+=cache_info->columns*cache_info->metacontent_extent;
5293 Write associated pixels to disk.
5295 LockSemaphoreInfo(cache_info->file_semaphore);
5296 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5298 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5299 cache_info->cache_filename);
5300 UnlockSemaphoreInfo(cache_info->file_semaphore);
5301 return(MagickFalse);
5303 if ((cache_info->columns == nexus_info->region.width) &&
5304 (extent <= MagickMaxBufferExtent))
5309 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5310 for (y=0; y < (ssize_t) rows; y++)
5312 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5313 cache_info->number_channels*sizeof(Quantum)+offset*
5314 cache_info->metacontent_extent,length,(const unsigned char *) p);
5315 if (count != (MagickOffsetType) length)
5317 p+=cache_info->metacontent_extent*nexus_info->region.width;
5318 offset+=cache_info->columns;
5320 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5321 (void) ClosePixelCacheOnDisk(cache_info);
5322 UnlockSemaphoreInfo(cache_info->file_semaphore);
5325 case DistributedCache:
5331 Write metacontent to distributed cache.
5333 LockSemaphoreInfo(cache_info->file_semaphore);
5334 region=nexus_info->region;
5335 if ((cache_info->columns != nexus_info->region.width) ||
5336 (extent > MagickMaxBufferExtent))
5343 for (y=0; y < (ssize_t) rows; y++)
5345 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5346 cache_info->server_info,®ion,length,(const unsigned char *) p);
5347 if (count != (MagickOffsetType) length)
5349 p+=cache_info->metacontent_extent*nexus_info->region.width;
5352 UnlockSemaphoreInfo(cache_info->file_semaphore);
5358 if (y < (ssize_t) rows)
5360 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5361 cache_info->cache_filename);
5362 return(MagickFalse);
5364 if ((cache_info->debug != MagickFalse) &&
5365 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5366 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5367 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5368 nexus_info->region.width,(double) nexus_info->region.height,(double)
5369 nexus_info->region.x,(double) nexus_info->region.y);
5374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5378 + W r i t e C a c h e P i x e l s %
5382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5384 % WritePixelCachePixels() writes image pixels to the specified region of the
5387 % The format of the WritePixelCachePixels() method is:
5389 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5390 % NexusInfo *nexus_info,ExceptionInfo *exception)
5392 % A description of each parameter follows:
5394 % o cache_info: the pixel cache.
5396 % o nexus_info: the cache nexus to write the pixels.
5398 % o exception: return any errors or warnings in this structure.
5401 static MagickBooleanType WritePixelCachePixels(
5402 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5403 ExceptionInfo *exception)
5413 register const Quantum
5422 if (nexus_info->authentic_pixel_cache != MagickFalse)
5424 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5425 nexus_info->region.x;
5426 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5428 extent=length*nexus_info->region.height;
5429 rows=nexus_info->region.height;
5431 p=nexus_info->pixels;
5432 switch (cache_info->type)
5441 Write pixels to memory.
5443 if ((cache_info->columns == nexus_info->region.width) &&
5444 (extent == (MagickSizeType) ((size_t) extent)))
5449 q=cache_info->pixels+offset*cache_info->number_channels;
5450 for (y=0; y < (ssize_t) rows; y++)
5452 (void) memcpy(q,p,(size_t) length);
5453 p+=cache_info->number_channels*nexus_info->region.width;
5454 q+=cache_info->columns*cache_info->number_channels;
5461 Write pixels to disk.
5463 LockSemaphoreInfo(cache_info->file_semaphore);
5464 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5466 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5467 cache_info->cache_filename);
5468 UnlockSemaphoreInfo(cache_info->file_semaphore);
5469 return(MagickFalse);
5471 if ((cache_info->columns == nexus_info->region.width) &&
5472 (extent <= MagickMaxBufferExtent))
5477 for (y=0; y < (ssize_t) rows; y++)
5479 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5480 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5482 if (count != (MagickOffsetType) length)
5484 p+=cache_info->number_channels*nexus_info->region.width;
5485 offset+=cache_info->columns;
5487 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5488 (void) ClosePixelCacheOnDisk(cache_info);
5489 UnlockSemaphoreInfo(cache_info->file_semaphore);
5492 case DistributedCache:
5498 Write pixels to distributed cache.
5500 LockSemaphoreInfo(cache_info->file_semaphore);
5501 region=nexus_info->region;
5502 if ((cache_info->columns != nexus_info->region.width) ||
5503 (extent > MagickMaxBufferExtent))
5510 for (y=0; y < (ssize_t) rows; y++)
5512 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5513 cache_info->server_info,®ion,length,(const unsigned char *) p);
5514 if (count != (MagickOffsetType) length)
5516 p+=cache_info->number_channels*nexus_info->region.width;
5519 UnlockSemaphoreInfo(cache_info->file_semaphore);
5525 if (y < (ssize_t) rows)
5527 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5528 cache_info->cache_filename);
5529 return(MagickFalse);
5531 if ((cache_info->debug != MagickFalse) &&
5532 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5533 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5534 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5535 nexus_info->region.width,(double) nexus_info->region.height,(double)
5536 nexus_info->region.x,(double) nexus_info->region.y);