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-2017 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 % https://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;
160 cache_anonymous_memory = (-1);
166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 + A c q u i r e P i x e l C a c h e %
174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 % AcquirePixelCache() acquires a pixel cache.
178 % The format of the AcquirePixelCache() method is:
180 % Cache AcquirePixelCache(const size_t number_threads)
182 % A description of each parameter follows:
184 % o number_threads: the number of nexus threads.
187 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
190 *magick_restrict cache_info;
195 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
196 if (cache_info == (CacheInfo *) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
199 cache_info->type=UndefinedCache;
200 cache_info->mode=IOMode;
201 cache_info->colorspace=sRGBColorspace;
202 cache_info->file=(-1);
203 cache_info->id=GetMagickThreadId();
204 cache_info->number_threads=number_threads;
205 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
206 cache_info->number_threads=GetOpenMPMaximumThreads();
207 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
208 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
209 if (cache_info->number_threads == 0)
210 cache_info->number_threads=1;
211 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
212 if (cache_info->nexus_info == (NexusInfo **) NULL)
213 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
214 value=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
215 if (value != (const char *) NULL)
217 cache_info->synchronize=IsStringTrue(value);
218 value=DestroyString(value);
220 value=GetPolicyValue("cache:synchronize");
221 if (value != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(value);
224 value=DestroyString(value);
226 cache_info->semaphore=AcquireSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AcquireSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickCoreSignature;
231 return((Cache ) cache_info);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % A c q u i r e P i x e l C a c h e N e x u s %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
247 % The format of the AcquirePixelCacheNexus method is:
249 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 % A description of each parameter follows:
253 % o number_threads: the number of nexus threads.
256 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
259 **magick_restrict nexus_info;
264 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
265 number_threads,sizeof(*nexus_info)));
266 if (nexus_info == (NexusInfo **) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
269 sizeof(**nexus_info));
270 if (nexus_info[0] == (NexusInfo *) NULL)
271 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
272 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
273 for (i=0; i < (ssize_t) number_threads; i++)
275 nexus_info[i]=(&nexus_info[0][i]);
276 nexus_info[i]->signature=MagickCoreSignature;
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 + A c q u i r e P i x e l C a c h e P i x e l s %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % AcquirePixelCachePixels() returns the pixels associated with the specified
295 % The format of the AcquirePixelCachePixels() method is:
297 % const void *AcquirePixelCachePixels(const Image *image,
298 % MagickSizeType *length,ExceptionInfo *exception)
300 % A description of each parameter follows:
302 % o image: the image.
304 % o length: the pixel cache length.
306 % o exception: return any errors or warnings in this structure.
309 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
310 MagickSizeType *length,ExceptionInfo *exception)
313 *magick_restrict cache_info;
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickCoreSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickCoreSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickCoreSignature);
323 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
324 return((const void *) NULL);
325 *length=cache_info->length;
326 return((const void *) cache_info->pixels);
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 + C a c h e C o m p o n e n t G e n e s i s %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % CacheComponentGenesis() instantiates the cache component.
342 % The format of the CacheComponentGenesis method is:
344 % MagickBooleanType CacheComponentGenesis(void)
347 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
349 if (cache_semaphore == (SemaphoreInfo *) NULL)
350 cache_semaphore=AcquireSemaphoreInfo();
355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359 + C a c h e C o m p o n e n t T e r m i n u s %
363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 % CacheComponentTerminus() destroys the cache component.
367 % The format of the CacheComponentTerminus() method is:
369 % CacheComponentTerminus(void)
372 MagickPrivate void CacheComponentTerminus(void)
374 if (cache_semaphore == (SemaphoreInfo *) NULL)
375 ActivateSemaphoreInfo(&cache_semaphore);
376 LockSemaphoreInfo(cache_semaphore);
377 instantiate_cache=MagickFalse;
378 UnlockSemaphoreInfo(cache_semaphore);
379 RelinquishSemaphoreInfo(&cache_semaphore);
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387 + C l o n e P i x e l C a c h e %
391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
393 % ClonePixelCache() clones a pixel cache.
395 % The format of the ClonePixelCache() method is:
397 % Cache ClonePixelCache(const Cache cache)
399 % A description of each parameter follows:
401 % o cache: the pixel cache.
404 MagickPrivate Cache ClonePixelCache(const Cache cache)
407 *magick_restrict clone_info;
410 *magick_restrict cache_info;
412 assert(cache != NULL);
413 cache_info=(const CacheInfo *) cache;
414 assert(cache_info->signature == MagickCoreSignature);
415 if (cache_info->debug != MagickFalse)
416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
417 cache_info->filename);
418 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
419 if (clone_info == (Cache) NULL)
420 return((Cache) NULL);
421 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
422 return((Cache ) clone_info);
426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 + C l o n e P i x e l C a c h e M e t h o d s %
434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
439 % The format of the ClonePixelCacheMethods() method is:
441 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
443 % A description of each parameter follows:
445 % o clone: Specifies a pointer to a Cache structure.
447 % o cache: the pixel cache.
450 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
453 *magick_restrict cache_info,
454 *magick_restrict source_info;
456 assert(clone != (Cache) NULL);
457 source_info=(CacheInfo *) clone;
458 assert(source_info->signature == MagickCoreSignature);
459 if (source_info->debug != MagickFalse)
460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
461 source_info->filename);
462 assert(cache != (Cache) NULL);
463 cache_info=(CacheInfo *) cache;
464 assert(cache_info->signature == MagickCoreSignature);
465 source_info->methods=cache_info->methods;
469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 + 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 %
477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478 % ClonePixelCacheRepository() clones the source pixel cache to the destination
481 % The format of the ClonePixelCacheRepository() method is:
483 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
484 % CacheInfo *source_info,ExceptionInfo *exception)
486 % A description of each parameter follows:
488 % o cache_info: the pixel cache.
490 % o source_info: the source pixel cache.
492 % o exception: return any errors or warnings in this structure.
496 static MagickBooleanType ClonePixelCacheOnDisk(
497 CacheInfo *magick_restrict cache_info,CacheInfo *magick_restrict clone_info)
515 Clone pixel cache on disk with identical morphology.
517 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
518 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
520 quantum=(size_t) MagickMaxBufferExtent;
521 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
522 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
523 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
524 if (buffer == (unsigned char *) NULL)
525 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
527 while ((count=read(cache_info->file,buffer,quantum)) > 0)
532 number_bytes=write(clone_info->file,buffer,(size_t) count);
533 if (number_bytes != count)
535 extent+=number_bytes;
537 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
538 if (extent != cache_info->length)
543 static MagickBooleanType ClonePixelCacheRepository(
544 CacheInfo *magick_restrict clone_info,CacheInfo *magick_restrict cache_info,
545 ExceptionInfo *exception)
547 #define MaxCacheThreads 2
548 #define cache_threads(source,destination) \
549 num_threads(((source)->type == DiskCache) || \
550 ((destination)->type == DiskCache) || (((source)->rows) < \
551 (16*GetMagickResourceLimit(ThreadResource))) ? 1 : \
552 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
553 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
560 **magick_restrict cache_nexus,
561 **magick_restrict clone_nexus;
569 assert(cache_info != (CacheInfo *) NULL);
570 assert(clone_info != (CacheInfo *) NULL);
571 assert(exception != (ExceptionInfo *) NULL);
572 if (cache_info->type == PingCache)
574 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
575 if ((cache_info->columns == clone_info->columns) &&
576 (cache_info->rows == clone_info->rows) &&
577 (cache_info->number_channels == clone_info->number_channels) &&
578 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
579 (cache_info->metacontent_extent == clone_info->metacontent_extent))
582 Identical pixel cache morphology.
584 if (((cache_info->type == MemoryCache) ||
585 (cache_info->type == MapCache)) &&
586 ((clone_info->type == MemoryCache) ||
587 (clone_info->type == MapCache)))
589 (void) memcpy(clone_info->pixels,cache_info->pixels,
590 cache_info->columns*cache_info->number_channels*cache_info->rows*
591 sizeof(*cache_info->pixels));
592 if ((cache_info->metacontent_extent != 0) &&
593 (clone_info->metacontent_extent != 0))
594 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
595 cache_info->columns*cache_info->rows*
596 clone_info->metacontent_extent*sizeof(unsigned char));
599 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
600 return(ClonePixelCacheOnDisk(cache_info,clone_info));
603 Mismatched pixel cache morphology.
605 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
606 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
607 if ((cache_nexus == (NexusInfo **) NULL) ||
608 (clone_nexus == (NexusInfo **) NULL))
609 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
610 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
611 optimize=(cache_info->number_channels == clone_info->number_channels) &&
612 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
613 MagickTrue : MagickFalse;
614 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
615 clone_info->columns*clone_info->number_channels);
617 #if defined(MAGICKCORE_OPENMP_SUPPORT)
618 #pragma omp parallel for schedule(static,4) shared(status) \
619 cache_threads(cache_info,clone_info)
621 for (y=0; y < (ssize_t) cache_info->rows; y++)
624 id = GetOpenMPThreadId();
635 if (status == MagickFalse)
637 if (y >= (ssize_t) clone_info->rows)
639 region.width=cache_info->columns;
643 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
644 cache_nexus[id],exception);
645 if (pixels == (Quantum *) NULL)
647 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
648 if (status == MagickFalse)
650 region.width=clone_info->columns;
651 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
652 clone_nexus[id],exception);
653 if (pixels == (Quantum *) NULL)
655 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
656 clone_nexus[id]->length);
657 if (optimize != MagickFalse)
658 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
662 register const Quantum
669 Mismatched pixel channel map.
671 p=cache_nexus[id]->pixels;
672 q=clone_nexus[id]->pixels;
673 for (x=0; x < (ssize_t) cache_info->columns; x++)
678 if (x == (ssize_t) clone_info->columns)
680 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
688 channel=clone_info->channel_map[i].channel;
689 traits=cache_info->channel_map[channel].traits;
690 if (traits != UndefinedPixelTrait)
691 *q=*(p+cache_info->channel_map[channel].offset);
694 p+=cache_info->number_channels;
697 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
699 if ((cache_info->metacontent_extent != 0) &&
700 (clone_info->metacontent_extent != 0))
705 length=(size_t) MagickMin(cache_info->metacontent_extent,
706 clone_info->metacontent_extent);
707 #if defined(MAGICKCORE_OPENMP_SUPPORT)
708 #pragma omp parallel for schedule(static,4) shared(status) \
709 cache_threads(cache_info,clone_info)
711 for (y=0; y < (ssize_t) cache_info->rows; y++)
714 id = GetOpenMPThreadId();
722 if (status == MagickFalse)
724 if (y >= (ssize_t) clone_info->rows)
726 region.width=cache_info->columns;
730 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
731 cache_nexus[id],exception);
732 if (pixels == (Quantum *) NULL)
734 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
735 if (status == MagickFalse)
737 region.width=clone_info->columns;
738 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
739 clone_nexus[id],exception);
740 if (pixels == (Quantum *) NULL)
742 if ((clone_nexus[id]->metacontent != (void *) NULL) &&
743 (cache_nexus[id]->metacontent != (void *) NULL))
744 (void) memcpy(clone_nexus[id]->metacontent,
745 cache_nexus[id]->metacontent,length*sizeof(unsigned char));
746 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
749 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
750 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
751 if (cache_info->debug != MagickFalse)
754 message[MagickPathExtent];
756 (void) FormatLocaleString(message,MagickPathExtent,"%s => %s",
757 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
758 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
759 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769 + D e s t r o y I m a g e P i x e l C a c h e %
773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
775 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
777 % The format of the DestroyImagePixelCache() method is:
779 % void DestroyImagePixelCache(Image *image)
781 % A description of each parameter follows:
783 % o image: the image.
786 static void DestroyImagePixelCache(Image *image)
788 assert(image != (Image *) NULL);
789 assert(image->signature == MagickCoreSignature);
790 if (image->debug != MagickFalse)
791 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
792 if (image->cache == (void *) NULL)
794 image->cache=DestroyPixelCache(image->cache);
798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802 + D e s t r o y I m a g e P i x e l s %
806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
808 % DestroyImagePixels() deallocates memory associated with the pixel cache.
810 % The format of the DestroyImagePixels() method is:
812 % void DestroyImagePixels(Image *image)
814 % A description of each parameter follows:
816 % o image: the image.
819 MagickExport void DestroyImagePixels(Image *image)
822 *magick_restrict cache_info;
824 assert(image != (const Image *) NULL);
825 assert(image->signature == MagickCoreSignature);
826 if (image->debug != MagickFalse)
827 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
828 assert(image->cache != (Cache) NULL);
829 cache_info=(CacheInfo *) image->cache;
830 assert(cache_info->signature == MagickCoreSignature);
831 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
833 cache_info->methods.destroy_pixel_handler(image);
836 image->cache=DestroyPixelCache(image->cache);
840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
844 + D e s t r o y P i x e l C a c h e %
848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850 % DestroyPixelCache() deallocates memory associated with the pixel cache.
852 % The format of the DestroyPixelCache() method is:
854 % Cache DestroyPixelCache(Cache cache)
856 % A description of each parameter follows:
858 % o cache: the pixel cache.
862 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
868 if (cache_info->file != -1)
870 status=close(cache_info->file);
871 cache_info->file=(-1);
872 RelinquishMagickResource(FileResource,1);
874 return(status == -1 ? MagickFalse : MagickTrue);
877 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
879 switch (cache_info->type)
883 #if defined(MAGICKCORE_OPENCL_SUPPORT)
884 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
886 cache_info->opencl=RelinquishMagickCLCacheInfo(cache_info->opencl,
888 cache_info->pixels=(Quantum *) NULL;
892 if (cache_info->mapped == MagickFalse)
893 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
896 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
897 RelinquishMagickResource(MemoryResource,cache_info->length);
902 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
903 cache_info->pixels=(Quantum *) NULL;
904 if (cache_info->mode != ReadMode)
905 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
906 *cache_info->cache_filename='\0';
907 RelinquishMagickResource(MapResource,cache_info->length);
911 if (cache_info->file != -1)
912 (void) ClosePixelCacheOnDisk(cache_info);
913 if (cache_info->mode != ReadMode)
914 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
915 *cache_info->cache_filename='\0';
916 RelinquishMagickResource(DiskResource,cache_info->length);
919 case DistributedCache:
921 *cache_info->cache_filename='\0';
922 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
923 cache_info->server_info);
929 cache_info->type=UndefinedCache;
930 cache_info->mapped=MagickFalse;
931 cache_info->metacontent=(void *) NULL;
934 MagickPrivate Cache DestroyPixelCache(Cache cache)
937 *magick_restrict cache_info;
939 assert(cache != (Cache) NULL);
940 cache_info=(CacheInfo *) cache;
941 assert(cache_info->signature == MagickCoreSignature);
942 if (cache_info->debug != MagickFalse)
943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
944 cache_info->filename);
945 LockSemaphoreInfo(cache_info->semaphore);
946 cache_info->reference_count--;
947 if (cache_info->reference_count != 0)
949 UnlockSemaphoreInfo(cache_info->semaphore);
950 return((Cache) NULL);
952 UnlockSemaphoreInfo(cache_info->semaphore);
953 if (cache_info->debug != MagickFalse)
956 message[MagickPathExtent];
958 (void) FormatLocaleString(message,MagickPathExtent,"destroy %s",
959 cache_info->filename);
960 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
962 RelinquishPixelCachePixels(cache_info);
963 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
964 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
965 cache_info->server_info);
966 if (cache_info->nexus_info != (NexusInfo **) NULL)
967 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
968 cache_info->number_threads);
969 if (cache_info->random_info != (RandomInfo *) NULL)
970 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
971 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
972 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
973 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
974 RelinquishSemaphoreInfo(&cache_info->semaphore);
975 cache_info->signature=(~MagickCoreSignature);
976 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 + D e s t r o y P i x e l C a c h e N e x u s %
990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
994 % The format of the DestroyPixelCacheNexus() method is:
996 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
997 % const size_t number_threads)
999 % A description of each parameter follows:
1001 % o nexus_info: the nexus to destroy.
1003 % o number_threads: the number of nexus threads.
1007 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1009 if (nexus_info->mapped == MagickFalse)
1010 (void) RelinquishAlignedMemory(nexus_info->cache);
1012 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1013 nexus_info->cache=(Quantum *) NULL;
1014 nexus_info->pixels=(Quantum *) NULL;
1015 nexus_info->metacontent=(void *) NULL;
1016 nexus_info->length=0;
1017 nexus_info->mapped=MagickFalse;
1020 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1021 const size_t number_threads)
1026 assert(nexus_info != (NexusInfo **) NULL);
1027 for (i=0; i < (ssize_t) number_threads; i++)
1029 if (nexus_info[i]->cache != (Quantum *) NULL)
1030 RelinquishCacheNexusPixels(nexus_info[i]);
1031 nexus_info[i]->signature=(~MagickCoreSignature);
1033 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1034 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1043 % G e t A u t h e n t i c M e t a c o n t e n t %
1047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1050 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1051 % returned if the associated pixels are not available.
1053 % The format of the GetAuthenticMetacontent() method is:
1055 % void *GetAuthenticMetacontent(const Image *image)
1057 % A description of each parameter follows:
1059 % o image: the image.
1062 MagickExport void *GetAuthenticMetacontent(const Image *image)
1065 *magick_restrict cache_info;
1068 id = GetOpenMPThreadId();
1070 assert(image != (const Image *) NULL);
1071 assert(image->signature == MagickCoreSignature);
1072 assert(image->cache != (Cache) NULL);
1073 cache_info=(CacheInfo *) image->cache;
1074 assert(cache_info->signature == MagickCoreSignature);
1075 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1076 (GetAuthenticMetacontentFromHandler) NULL)
1081 metacontent=cache_info->methods.
1082 get_authentic_metacontent_from_handler(image);
1083 return(metacontent);
1085 assert(id < (int) cache_info->number_threads);
1086 return(cache_info->nexus_info[id]->metacontent);
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094 + 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 %
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1101 % with the last call to QueueAuthenticPixelsCache() or
1102 % GetAuthenticPixelsCache().
1104 % The format of the GetAuthenticMetacontentFromCache() method is:
1106 % void *GetAuthenticMetacontentFromCache(const Image *image)
1108 % A description of each parameter follows:
1110 % o image: the image.
1113 static void *GetAuthenticMetacontentFromCache(const Image *image)
1116 *magick_restrict cache_info;
1119 id = GetOpenMPThreadId();
1121 assert(image != (const Image *) NULL);
1122 assert(image->signature == MagickCoreSignature);
1123 assert(image->cache != (Cache) NULL);
1124 cache_info=(CacheInfo *) image->cache;
1125 assert(cache_info->signature == MagickCoreSignature);
1126 assert(id < (int) cache_info->number_threads);
1127 return(cache_info->nexus_info[id]->metacontent);
1130 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136 + G e t A u t h e n t i c O p e n C L B u f f e r %
1140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1142 % GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1145 % The format of the GetAuthenticOpenCLBuffer() method is:
1147 % cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1148 % MagickCLDevice device,ExceptionInfo *exception)
1150 % A description of each parameter follows:
1152 % o image: the image.
1154 % o device: the device to use.
1156 % o exception: return any errors or warnings in this structure.
1159 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1160 MagickCLDevice device,ExceptionInfo *exception)
1163 *magick_restrict cache_info;
1168 assert(image != (const Image *) NULL);
1169 assert(device != (const MagickCLDevice) NULL);
1170 cache_info=(CacheInfo *) image->cache;
1171 if (cache_info->type == UndefinedCache)
1172 SyncImagePixelCache((Image *) image,exception);
1173 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1174 return((cl_mem) NULL);
1175 if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1176 (cache_info->opencl->device->context != device->context))
1177 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1178 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1180 assert(cache_info->pixels != (Quantum *) NULL);
1181 cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1182 cache_info->length);
1183 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1184 return((cl_mem) NULL);
1186 assert(cache_info->opencl->pixels == cache_info->pixels);
1187 return(cache_info->opencl->buffer);
1192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1196 + 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 %
1200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1203 % disk pixel cache as defined by the geometry parameters. A pointer to the
1204 % pixels is returned if the pixels are transferred, otherwise a NULL is
1207 % The format of the GetAuthenticPixelCacheNexus() method is:
1209 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1210 % const ssize_t y,const size_t columns,const size_t rows,
1211 % NexusInfo *nexus_info,ExceptionInfo *exception)
1213 % A description of each parameter follows:
1215 % o image: the image.
1217 % o x,y,columns,rows: These values define the perimeter of a region of
1220 % o nexus_info: the cache nexus to return.
1222 % o exception: return any errors or warnings in this structure.
1226 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1227 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1228 ExceptionInfo *exception)
1231 *magick_restrict cache_info;
1234 *magick_restrict pixels;
1237 Transfer pixels from the cache.
1239 assert(image != (Image *) NULL);
1240 assert(image->signature == MagickCoreSignature);
1241 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1242 nexus_info,exception);
1243 if (pixels == (Quantum *) NULL)
1244 return((Quantum *) NULL);
1245 cache_info=(CacheInfo *) image->cache;
1246 assert(cache_info->signature == MagickCoreSignature);
1247 if (nexus_info->authentic_pixel_cache != MagickFalse)
1249 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1250 return((Quantum *) NULL);
1251 if (cache_info->metacontent_extent != 0)
1252 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1253 return((Quantum *) NULL);
1258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1262 + 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 %
1266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1268 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1269 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1271 % The format of the GetAuthenticPixelsFromCache() method is:
1273 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1275 % A description of each parameter follows:
1277 % o image: the image.
1280 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1283 *magick_restrict cache_info;
1286 id = GetOpenMPThreadId();
1288 assert(image != (const Image *) NULL);
1289 assert(image->signature == MagickCoreSignature);
1290 assert(image->cache != (Cache) NULL);
1291 cache_info=(CacheInfo *) image->cache;
1292 assert(cache_info->signature == MagickCoreSignature);
1293 assert(id < (int) cache_info->number_threads);
1294 return(cache_info->nexus_info[id]->pixels);
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 % G e t A u t h e n t i c P i x e l Q u e u e %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % GetAuthenticPixelQueue() returns the authentic pixels associated
1309 % corresponding with the last call to QueueAuthenticPixels() or
1310 % GetAuthenticPixels().
1312 % The format of the GetAuthenticPixelQueue() method is:
1314 % Quantum *GetAuthenticPixelQueue(const Image image)
1316 % A description of each parameter follows:
1318 % o image: the image.
1321 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1324 *magick_restrict cache_info;
1327 id = GetOpenMPThreadId();
1329 assert(image != (const Image *) NULL);
1330 assert(image->signature == MagickCoreSignature);
1331 assert(image->cache != (Cache) NULL);
1332 cache_info=(CacheInfo *) image->cache;
1333 assert(cache_info->signature == MagickCoreSignature);
1334 if (cache_info->methods.get_authentic_pixels_from_handler !=
1335 (GetAuthenticPixelsFromHandler) NULL)
1336 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1337 assert(id < (int) cache_info->number_threads);
1338 return(cache_info->nexus_info[id]->pixels);
1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346 % G e t A u t h e n t i c P i x e l s %
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1352 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1353 % region is successfully accessed, a pointer to a Quantum array
1354 % representing the region is returned, otherwise NULL is returned.
1356 % The returned pointer may point to a temporary working copy of the pixels
1357 % or it may point to the original pixels in memory. Performance is maximized
1358 % if the selected region is part of one row, or one or more full rows, since
1359 % then there is opportunity to access the pixels in-place (without a copy)
1360 % if the image is in memory, or in a memory-mapped file. The returned pointer
1361 % must *never* be deallocated by the user.
1363 % Pixels accessed via the returned pointer represent a simple array of type
1364 % Quantum. If the image has corresponding metacontent,call
1365 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1366 % meta-content corresponding to the region. Once the Quantum array has
1367 % been updated, the changes must be saved back to the underlying image using
1368 % SyncAuthenticPixels() or they may be lost.
1370 % The format of the GetAuthenticPixels() method is:
1372 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1373 % const ssize_t y,const size_t columns,const size_t rows,
1374 % ExceptionInfo *exception)
1376 % A description of each parameter follows:
1378 % o image: the image.
1380 % o x,y,columns,rows: These values define the perimeter of a region of
1383 % o exception: return any errors or warnings in this structure.
1386 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1387 const ssize_t y,const size_t columns,const size_t rows,
1388 ExceptionInfo *exception)
1391 *magick_restrict cache_info;
1394 id = GetOpenMPThreadId();
1399 assert(image != (Image *) NULL);
1400 assert(image->signature == MagickCoreSignature);
1401 assert(image->cache != (Cache) NULL);
1402 cache_info=(CacheInfo *) image->cache;
1403 assert(cache_info->signature == MagickCoreSignature);
1404 if (cache_info->methods.get_authentic_pixels_handler !=
1405 (GetAuthenticPixelsHandler) NULL)
1407 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1411 assert(id < (int) cache_info->number_threads);
1412 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1413 cache_info->nexus_info[id],exception);
1418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422 + G e t A u t h e n t i c P i x e l s C a c h e %
1426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1429 % as defined by the geometry parameters. A pointer to the pixels is returned
1430 % if the pixels are transferred, otherwise a NULL is returned.
1432 % The format of the GetAuthenticPixelsCache() method is:
1434 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1435 % const ssize_t y,const size_t columns,const size_t rows,
1436 % ExceptionInfo *exception)
1438 % A description of each parameter follows:
1440 % o image: the image.
1442 % o x,y,columns,rows: These values define the perimeter of a region of
1445 % o exception: return any errors or warnings in this structure.
1448 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1449 const ssize_t y,const size_t columns,const size_t rows,
1450 ExceptionInfo *exception)
1453 *magick_restrict cache_info;
1456 id = GetOpenMPThreadId();
1459 *magick_restrict pixels;
1461 assert(image != (const Image *) NULL);
1462 assert(image->signature == MagickCoreSignature);
1463 assert(image->cache != (Cache) NULL);
1464 cache_info=(CacheInfo *) image->cache;
1465 if (cache_info == (Cache) NULL)
1466 return((Quantum *) NULL);
1467 assert(cache_info->signature == MagickCoreSignature);
1468 assert(id < (int) cache_info->number_threads);
1469 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1470 cache_info->nexus_info[id],exception);
1475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1479 + G e t I m a g e E x t e n t %
1483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1485 % GetImageExtent() returns the extent of the pixels associated corresponding
1486 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1488 % The format of the GetImageExtent() method is:
1490 % MagickSizeType GetImageExtent(const Image *image)
1492 % A description of each parameter follows:
1494 % o image: the image.
1497 MagickExport MagickSizeType GetImageExtent(const Image *image)
1500 *magick_restrict cache_info;
1503 id = GetOpenMPThreadId();
1505 assert(image != (Image *) NULL);
1506 assert(image->signature == MagickCoreSignature);
1507 if (image->debug != MagickFalse)
1508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1509 assert(image->cache != (Cache) NULL);
1510 cache_info=(CacheInfo *) image->cache;
1511 assert(cache_info->signature == MagickCoreSignature);
1512 assert(id < (int) cache_info->number_threads);
1513 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521 + G e t I m a g e P i x e l C a c h e %
1525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527 % GetImagePixelCache() ensures that there is only a single reference to the
1528 % pixel cache to be modified, updating the provided cache pointer to point to
1529 % a clone of the original pixel cache if necessary.
1531 % The format of the GetImagePixelCache method is:
1533 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1534 % ExceptionInfo *exception)
1536 % A description of each parameter follows:
1538 % o image: the image.
1540 % o clone: any value other than MagickFalse clones the cache pixels.
1542 % o exception: return any errors or warnings in this structure.
1546 static inline MagickBooleanType ValidatePixelCacheMorphology(
1547 const Image *magick_restrict image)
1550 *magick_restrict cache_info;
1552 const PixelChannelMap
1557 Does the image match the pixel cache morphology?
1559 cache_info=(CacheInfo *) image->cache;
1560 p=image->channel_map;
1561 q=cache_info->channel_map;
1562 if ((image->storage_class != cache_info->storage_class) ||
1563 (image->colorspace != cache_info->colorspace) ||
1564 (image->alpha_trait != cache_info->alpha_trait) ||
1565 (image->read_mask != cache_info->read_mask) ||
1566 (image->write_mask != cache_info->write_mask) ||
1567 (image->columns != cache_info->columns) ||
1568 (image->rows != cache_info->rows) ||
1569 (image->number_channels != cache_info->number_channels) ||
1570 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1571 (image->metacontent_extent != cache_info->metacontent_extent) ||
1572 (cache_info->nexus_info == (NexusInfo **) NULL))
1573 return(MagickFalse);
1577 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1578 ExceptionInfo *exception)
1581 *magick_restrict cache_info;
1587 static MagickSizeType
1588 cache_timelimit = MagickResourceInfinity,
1589 cpu_throttle = MagickResourceInfinity,
1593 if (cpu_throttle == MagickResourceInfinity)
1594 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1595 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1596 MagickDelay(cpu_throttle);
1597 if (cache_epoch == 0)
1600 Set the expire time in seconds.
1602 cache_timelimit=GetMagickResourceLimit(TimeResource);
1603 cache_epoch=time((time_t *) NULL);
1605 if ((cache_timelimit != MagickResourceInfinity) &&
1606 ((MagickSizeType) (time((time_t *) NULL)-cache_epoch) >= cache_timelimit))
1608 #if defined(ECANCELED)
1611 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1613 LockSemaphoreInfo(image->semaphore);
1614 assert(image->cache != (Cache) NULL);
1615 cache_info=(CacheInfo *) image->cache;
1616 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1617 CopyOpenCLBuffer(cache_info);
1619 destroy=MagickFalse;
1620 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1622 LockSemaphoreInfo(cache_info->semaphore);
1623 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1634 clone_image=(*image);
1635 clone_image.semaphore=AcquireSemaphoreInfo();
1636 clone_image.reference_count=1;
1637 clone_image.cache=ClonePixelCache(cache_info);
1638 clone_info=(CacheInfo *) clone_image.cache;
1639 status=OpenPixelCache(&clone_image,IOMode,exception);
1640 if (status != MagickFalse)
1642 if (clone != MagickFalse)
1643 status=ClonePixelCacheRepository(clone_info,cache_info,
1645 if (status != MagickFalse)
1647 if (cache_info->reference_count == 1)
1648 cache_info->nexus_info=(NexusInfo **) NULL;
1650 image->cache=clone_image.cache;
1653 RelinquishSemaphoreInfo(&clone_image.semaphore);
1655 UnlockSemaphoreInfo(cache_info->semaphore);
1657 if (destroy != MagickFalse)
1658 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1659 if (status != MagickFalse)
1662 Ensure the image matches the pixel cache morphology.
1664 image->type=UndefinedType;
1665 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1667 status=OpenPixelCache(image,IOMode,exception);
1668 cache_info=(CacheInfo *) image->cache;
1669 if (cache_info->type == DiskCache)
1670 (void) ClosePixelCacheOnDisk(cache_info);
1673 UnlockSemaphoreInfo(image->semaphore);
1674 if (status == MagickFalse)
1675 return((Cache) NULL);
1676 return(image->cache);
1680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684 + G e t I m a g e P i x e l C a c h e T y p e %
1688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1690 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1691 % DiskCache, MemoryCache, MapCache, or PingCache.
1693 % The format of the GetImagePixelCacheType() method is:
1695 % CacheType GetImagePixelCacheType(const Image *image)
1697 % A description of each parameter follows:
1699 % o image: the image.
1702 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1705 *magick_restrict cache_info;
1707 assert(image != (Image *) NULL);
1708 assert(image->signature == MagickCoreSignature);
1709 assert(image->cache != (Cache) NULL);
1710 cache_info=(CacheInfo *) image->cache;
1711 assert(cache_info->signature == MagickCoreSignature);
1712 return(cache_info->type);
1716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1720 % G e t O n e A u t h e n t i c P i x e l %
1724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1726 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1727 % location. The image background color is returned if an error occurs.
1729 % The format of the GetOneAuthenticPixel() method is:
1731 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1732 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1734 % A description of each parameter follows:
1736 % o image: the image.
1738 % o x,y: These values define the location of the pixel to return.
1740 % o pixel: return a pixel at the specified (x,y) location.
1742 % o exception: return any errors or warnings in this structure.
1746 static inline MagickBooleanType CopyPixel(const Image *image,
1747 const Quantum *source,Quantum *destination)
1752 if (source == (const Quantum *) NULL)
1754 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1755 destination[GreenPixelChannel]=ClampToQuantum(
1756 image->background_color.green);
1757 destination[BluePixelChannel]=ClampToQuantum(
1758 image->background_color.blue);
1759 destination[BlackPixelChannel]=ClampToQuantum(
1760 image->background_color.black);
1761 destination[AlphaPixelChannel]=ClampToQuantum(
1762 image->background_color.alpha);
1763 return(MagickFalse);
1765 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1767 PixelChannel channel=GetPixelChannelChannel(image,i);
1768 destination[channel]=source[i];
1773 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1774 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1777 *magick_restrict cache_info;
1782 assert(image != (Image *) NULL);
1783 assert(image->signature == MagickCoreSignature);
1784 assert(image->cache != (Cache) NULL);
1785 cache_info=(CacheInfo *) image->cache;
1786 assert(cache_info->signature == MagickCoreSignature);
1787 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1788 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1789 (GetOneAuthenticPixelFromHandler) NULL)
1790 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1792 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1793 return(CopyPixel(image,q,pixel));
1797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1801 + 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 %
1805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1808 % location. The image background color is returned if an error occurs.
1810 % The format of the GetOneAuthenticPixelFromCache() method is:
1812 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1813 % const ssize_t x,const ssize_t y,Quantum *pixel,
1814 % ExceptionInfo *exception)
1816 % A description of each parameter follows:
1818 % o image: the image.
1820 % o x,y: These values define the location of the pixel to return.
1822 % o pixel: return a pixel at the specified (x,y) location.
1824 % o exception: return any errors or warnings in this structure.
1827 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1828 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1831 *magick_restrict cache_info;
1834 id = GetOpenMPThreadId();
1839 assert(image != (const Image *) NULL);
1840 assert(image->signature == MagickCoreSignature);
1841 assert(image->cache != (Cache) NULL);
1842 cache_info=(CacheInfo *) image->cache;
1843 assert(cache_info->signature == MagickCoreSignature);
1844 assert(id < (int) cache_info->number_threads);
1845 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1846 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1848 return(CopyPixel(image,q,pixel));
1852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1856 % G e t O n e V i r t u a l P i x e l %
1860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1863 % (x,y) location. The image background color is returned if an error occurs.
1864 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1866 % The format of the GetOneVirtualPixel() method is:
1868 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1869 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1871 % A description of each parameter follows:
1873 % o image: the image.
1875 % o x,y: These values define the location of the pixel to return.
1877 % o pixel: return a pixel at the specified (x,y) location.
1879 % o exception: return any errors or warnings in this structure.
1882 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1883 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1886 *magick_restrict cache_info;
1889 id = GetOpenMPThreadId();
1894 assert(image != (const Image *) NULL);
1895 assert(image->signature == MagickCoreSignature);
1896 assert(image->cache != (Cache) NULL);
1897 cache_info=(CacheInfo *) image->cache;
1898 assert(cache_info->signature == MagickCoreSignature);
1899 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1900 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1901 (GetOneVirtualPixelFromHandler) NULL)
1902 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1903 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1904 assert(id < (int) cache_info->number_threads);
1905 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1906 1UL,1UL,cache_info->nexus_info[id],exception);
1907 return(CopyPixel(image,p,pixel));
1911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1915 + 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 %
1919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1921 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1922 % specified (x,y) location. The image background color is returned if an
1925 % The format of the GetOneVirtualPixelFromCache() method is:
1927 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1928 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1929 % Quantum *pixel,ExceptionInfo *exception)
1931 % A description of each parameter follows:
1933 % o image: the image.
1935 % o virtual_pixel_method: the virtual pixel method.
1937 % o x,y: These values define the location of the pixel to return.
1939 % o pixel: return a pixel at the specified (x,y) location.
1941 % o exception: return any errors or warnings in this structure.
1944 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1945 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1946 Quantum *pixel,ExceptionInfo *exception)
1949 *magick_restrict cache_info;
1952 id = GetOpenMPThreadId();
1957 assert(image != (const Image *) NULL);
1958 assert(image->signature == MagickCoreSignature);
1959 assert(image->cache != (Cache) NULL);
1960 cache_info=(CacheInfo *) image->cache;
1961 assert(cache_info->signature == MagickCoreSignature);
1962 assert(id < (int) cache_info->number_threads);
1963 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1964 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1965 cache_info->nexus_info[id],exception);
1966 return(CopyPixel(image,p,pixel));
1970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1974 % G e t O n e V i r t u a l P i x e l I n f o %
1978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1981 % location. The image background color is returned if an error occurs. If
1982 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1984 % The format of the GetOneVirtualPixelInfo() method is:
1986 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1987 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1988 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1990 % A description of each parameter follows:
1992 % o image: the image.
1994 % o virtual_pixel_method: the virtual pixel method.
1996 % o x,y: these values define the location of the pixel to return.
1998 % o pixel: return a pixel at the specified (x,y) location.
2000 % o exception: return any errors or warnings in this structure.
2003 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2004 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2005 PixelInfo *pixel,ExceptionInfo *exception)
2008 *magick_restrict cache_info;
2011 id = GetOpenMPThreadId();
2013 register const Quantum
2016 assert(image != (const Image *) NULL);
2017 assert(image->signature == MagickCoreSignature);
2018 assert(image->cache != (Cache) NULL);
2019 cache_info=(CacheInfo *) image->cache;
2020 assert(cache_info->signature == MagickCoreSignature);
2021 assert(id < (int) cache_info->number_threads);
2022 GetPixelInfo(image,pixel);
2023 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2024 cache_info->nexus_info[id],exception);
2025 if (p == (const Quantum *) NULL)
2026 return(MagickFalse);
2027 GetPixelInfoPixel(image,p,pixel);
2032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2036 + G e t P i x e l C a c h e C o l o r s p a c e %
2040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2042 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2044 % The format of the GetPixelCacheColorspace() method is:
2046 % Colorspace GetPixelCacheColorspace(Cache cache)
2048 % A description of each parameter follows:
2050 % o cache: the pixel cache.
2053 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2056 *magick_restrict cache_info;
2058 assert(cache != (Cache) NULL);
2059 cache_info=(CacheInfo *) cache;
2060 assert(cache_info->signature == MagickCoreSignature);
2061 if (cache_info->debug != MagickFalse)
2062 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2063 cache_info->filename);
2064 return(cache_info->colorspace);
2068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072 + G e t P i x e l C a c h e M e t h o d s %
2076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078 % GetPixelCacheMethods() initializes the CacheMethods structure.
2080 % The format of the GetPixelCacheMethods() method is:
2082 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2084 % A description of each parameter follows:
2086 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2089 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2091 assert(cache_methods != (CacheMethods *) NULL);
2092 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2093 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2094 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2095 cache_methods->get_virtual_metacontent_from_handler=
2096 GetVirtualMetacontentFromCache;
2097 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2098 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2099 cache_methods->get_authentic_metacontent_from_handler=
2100 GetAuthenticMetacontentFromCache;
2101 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2102 cache_methods->get_one_authentic_pixel_from_handler=
2103 GetOneAuthenticPixelFromCache;
2104 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2105 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2106 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2114 + G e t P i x e l C a c h e N e x u s E x t e n t %
2118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2120 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2121 % corresponding with the last call to SetPixelCacheNexusPixels() or
2122 % GetPixelCacheNexusPixels().
2124 % The format of the GetPixelCacheNexusExtent() method is:
2126 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2127 % NexusInfo *nexus_info)
2129 % A description of each parameter follows:
2131 % o nexus_info: the nexus info.
2134 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2135 NexusInfo *magick_restrict nexus_info)
2138 *magick_restrict cache_info;
2143 assert(cache != NULL);
2144 cache_info=(CacheInfo *) cache;
2145 assert(cache_info->signature == MagickCoreSignature);
2146 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2148 return((MagickSizeType) cache_info->columns*cache_info->rows);
2153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157 + G e t P i x e l C a c h e P i x e l s %
2161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163 % GetPixelCachePixels() returns the pixels associated with the specified image.
2165 % The format of the GetPixelCachePixels() method is:
2167 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2168 % ExceptionInfo *exception)
2170 % A description of each parameter follows:
2172 % o image: the image.
2174 % o length: the pixel cache length.
2176 % o exception: return any errors or warnings in this structure.
2179 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2180 ExceptionInfo *exception)
2183 *magick_restrict cache_info;
2185 assert(image != (const Image *) NULL);
2186 assert(image->signature == MagickCoreSignature);
2187 assert(image->cache != (Cache) NULL);
2188 assert(length != (MagickSizeType *) NULL);
2189 assert(exception != (ExceptionInfo *) NULL);
2190 assert(exception->signature == MagickCoreSignature);
2191 cache_info=(CacheInfo *) image->cache;
2192 assert(cache_info->signature == MagickCoreSignature);
2194 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2195 return((void *) NULL);
2196 *length=cache_info->length;
2197 return((void *) cache_info->pixels);
2201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205 + 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 %
2209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2211 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2213 % The format of the GetPixelCacheStorageClass() method is:
2215 % ClassType GetPixelCacheStorageClass(Cache cache)
2217 % A description of each parameter follows:
2219 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2221 % o cache: the pixel cache.
2224 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2227 *magick_restrict cache_info;
2229 assert(cache != (Cache) NULL);
2230 cache_info=(CacheInfo *) cache;
2231 assert(cache_info->signature == MagickCoreSignature);
2232 if (cache_info->debug != MagickFalse)
2233 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2234 cache_info->filename);
2235 return(cache_info->storage_class);
2239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 + G e t P i x e l C a c h e T i l e S i z e %
2247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249 % GetPixelCacheTileSize() returns the pixel cache tile size.
2251 % The format of the GetPixelCacheTileSize() method is:
2253 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2256 % A description of each parameter follows:
2258 % o image: the image.
2260 % o width: the optimize cache tile width in pixels.
2262 % o height: the optimize cache tile height in pixels.
2265 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2269 *magick_restrict cache_info;
2271 assert(image != (Image *) NULL);
2272 assert(image->signature == MagickCoreSignature);
2273 if (image->debug != MagickFalse)
2274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2275 cache_info=(CacheInfo *) image->cache;
2276 assert(cache_info->signature == MagickCoreSignature);
2277 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2278 if (GetImagePixelCacheType(image) == DiskCache)
2279 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2288 + 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 %
2292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2294 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2295 % pixel cache. A virtual pixel is any pixel access that is outside the
2296 % boundaries of the image cache.
2298 % The format of the GetPixelCacheVirtualMethod() method is:
2300 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2302 % A description of each parameter follows:
2304 % o image: the image.
2307 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2310 *magick_restrict cache_info;
2312 assert(image != (Image *) NULL);
2313 assert(image->signature == MagickCoreSignature);
2314 assert(image->cache != (Cache) NULL);
2315 cache_info=(CacheInfo *) image->cache;
2316 assert(cache_info->signature == MagickCoreSignature);
2317 return(cache_info->virtual_pixel_method);
2321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2325 + 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 %
2329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2331 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2332 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2334 % The format of the GetVirtualMetacontentFromCache() method is:
2336 % void *GetVirtualMetacontentFromCache(const Image *image)
2338 % A description of each parameter follows:
2340 % o image: the image.
2343 static const void *GetVirtualMetacontentFromCache(const Image *image)
2346 *magick_restrict cache_info;
2349 id = GetOpenMPThreadId();
2352 *magick_restrict metacontent;
2354 assert(image != (const Image *) NULL);
2355 assert(image->signature == MagickCoreSignature);
2356 assert(image->cache != (Cache) NULL);
2357 cache_info=(CacheInfo *) image->cache;
2358 assert(cache_info->signature == MagickCoreSignature);
2359 assert(id < (int) cache_info->number_threads);
2360 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2361 cache_info->nexus_info[id]);
2362 return(metacontent);
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2370 + G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2379 % The format of the GetVirtualMetacontentFromNexus() method is:
2381 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2382 % NexusInfo *nexus_info)
2384 % A description of each parameter follows:
2386 % o cache: the pixel cache.
2388 % o nexus_info: the cache nexus to return the meta-content.
2391 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2392 NexusInfo *magick_restrict nexus_info)
2395 *magick_restrict cache_info;
2397 assert(cache != (Cache) NULL);
2398 cache_info=(CacheInfo *) cache;
2399 assert(cache_info->signature == MagickCoreSignature);
2400 if (cache_info->storage_class == UndefinedClass)
2401 return((void *) NULL);
2402 return(nexus_info->metacontent);
2406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2410 % G e t V i r t u a l M e t a c o n t e n t %
2414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2416 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2417 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2418 % returned if the meta-content are not available.
2420 % The format of the GetVirtualMetacontent() method is:
2422 % const void *GetVirtualMetacontent(const Image *image)
2424 % A description of each parameter follows:
2426 % o image: the image.
2429 MagickExport const void *GetVirtualMetacontent(const Image *image)
2432 *magick_restrict cache_info;
2435 id = GetOpenMPThreadId();
2438 *magick_restrict metacontent;
2440 assert(image != (const Image *) NULL);
2441 assert(image->signature == MagickCoreSignature);
2442 assert(image->cache != (Cache) NULL);
2443 cache_info=(CacheInfo *) image->cache;
2444 assert(cache_info->signature == MagickCoreSignature);
2445 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2446 if (metacontent != (void *) NULL)
2447 return(metacontent);
2448 assert(id < (int) cache_info->number_threads);
2449 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2450 cache_info->nexus_info[id]);
2451 return(metacontent);
2455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459 + 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 %
2463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2466 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2467 % is returned if the pixels are transferred, otherwise a NULL is returned.
2469 % The format of the GetVirtualPixelsFromNexus() method is:
2471 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2472 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2473 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2474 % ExceptionInfo *exception)
2476 % A description of each parameter follows:
2478 % o image: the image.
2480 % o virtual_pixel_method: the virtual pixel method.
2482 % o x,y,columns,rows: These values define the perimeter of a region of
2485 % o nexus_info: the cache nexus to acquire.
2487 % o exception: return any errors or warnings in this structure.
2494 0, 48, 12, 60, 3, 51, 15, 63,
2495 32, 16, 44, 28, 35, 19, 47, 31,
2496 8, 56, 4, 52, 11, 59, 7, 55,
2497 40, 24, 36, 20, 43, 27, 39, 23,
2498 2, 50, 14, 62, 1, 49, 13, 61,
2499 34, 18, 46, 30, 33, 17, 45, 29,
2500 10, 58, 6, 54, 9, 57, 5, 53,
2501 42, 26, 38, 22, 41, 25, 37, 21
2504 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2509 index=x+DitherMatrix[x & 0x07]-32L;
2512 if (index >= (ssize_t) columns)
2513 return((ssize_t) columns-1L);
2517 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2522 index=y+DitherMatrix[y & 0x07]-32L;
2525 if (index >= (ssize_t) rows)
2526 return((ssize_t) rows-1L);
2530 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2534 if (x >= (ssize_t) columns)
2535 return((ssize_t) (columns-1));
2539 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2543 if (y >= (ssize_t) rows)
2544 return((ssize_t) (rows-1));
2548 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2550 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2553 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2555 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2558 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2559 const size_t extent)
2565 Compute the remainder of dividing offset by extent. It returns not only
2566 the quotient (tile the offset falls in) but also the positive remainer
2567 within that tile such that 0 <= remainder < extent. This method is
2568 essentially a ldiv() using a floored modulo division rather than the
2569 normal default truncated modulo division.
2571 modulo.quotient=offset/(ssize_t) extent;
2574 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2578 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2579 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2580 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2581 ExceptionInfo *exception)
2584 *magick_restrict cache_info;
2594 **magick_restrict virtual_nexus;
2597 *magick_restrict pixels,
2598 virtual_pixel[MaxPixelChannels];
2603 register const Quantum
2616 register unsigned char
2623 *magick_restrict virtual_metacontent;
2628 assert(image != (const Image *) NULL);
2629 assert(image->signature == MagickCoreSignature);
2630 assert(image->cache != (Cache) NULL);
2631 cache_info=(CacheInfo *) image->cache;
2632 assert(cache_info->signature == MagickCoreSignature);
2633 if (cache_info->type == UndefinedCache)
2634 return((const Quantum *) NULL);
2635 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2636 CopyOpenCLBuffer(cache_info);
2640 region.width=columns;
2642 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2644 if (pixels == (Quantum *) NULL)
2645 return((const Quantum *) NULL);
2647 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2648 nexus_info->region.x;
2649 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2650 nexus_info->region.width-1L;
2651 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2652 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2653 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2654 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2660 Pixel request is inside cache extents.
2662 if (nexus_info->authentic_pixel_cache != MagickFalse)
2664 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2665 if (status == MagickFalse)
2666 return((const Quantum *) NULL);
2667 if (cache_info->metacontent_extent != 0)
2669 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2670 if (status == MagickFalse)
2671 return((const Quantum *) NULL);
2676 Pixel request is outside cache extents.
2678 s=(unsigned char *) nexus_info->metacontent;
2679 virtual_nexus=AcquirePixelCacheNexus(1);
2680 if (virtual_nexus == (NexusInfo **) NULL)
2682 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2683 "UnableToGetCacheNexus","`%s'",image->filename);
2684 return((const Quantum *) NULL);
2686 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2687 sizeof(*virtual_pixel));
2688 virtual_metacontent=(void *) NULL;
2689 switch (virtual_pixel_method)
2691 case BackgroundVirtualPixelMethod:
2692 case BlackVirtualPixelMethod:
2693 case GrayVirtualPixelMethod:
2694 case TransparentVirtualPixelMethod:
2695 case MaskVirtualPixelMethod:
2696 case WhiteVirtualPixelMethod:
2697 case EdgeVirtualPixelMethod:
2698 case CheckerTileVirtualPixelMethod:
2699 case HorizontalTileVirtualPixelMethod:
2700 case VerticalTileVirtualPixelMethod:
2702 if (cache_info->metacontent_extent != 0)
2705 Acquire a metacontent buffer.
2707 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2708 cache_info->metacontent_extent);
2709 if (virtual_metacontent == (void *) NULL)
2711 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2712 (void) ThrowMagickException(exception,GetMagickModule(),
2713 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2714 return((const Quantum *) NULL);
2716 (void) ResetMagickMemory(virtual_metacontent,0,
2717 cache_info->metacontent_extent);
2719 switch (virtual_pixel_method)
2721 case BlackVirtualPixelMethod:
2723 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2724 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2725 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2728 case GrayVirtualPixelMethod:
2730 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2731 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2733 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2736 case TransparentVirtualPixelMethod:
2738 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2739 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2740 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2743 case MaskVirtualPixelMethod:
2744 case WhiteVirtualPixelMethod:
2746 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2747 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2748 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2753 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2755 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2757 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2759 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2761 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2771 for (v=0; v < (ssize_t) rows; v++)
2777 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2778 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2779 y_offset=EdgeY(y_offset,cache_info->rows);
2780 for (u=0; u < (ssize_t) columns; u+=length)
2786 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2787 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2788 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2796 Transfer a single pixel.
2798 length=(MagickSizeType) 1;
2799 switch (virtual_pixel_method)
2801 case EdgeVirtualPixelMethod:
2804 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2805 EdgeX(x_offset,cache_info->columns),
2806 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2808 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2811 case RandomVirtualPixelMethod:
2813 if (cache_info->random_info == (RandomInfo *) NULL)
2814 cache_info->random_info=AcquireRandomInfo();
2815 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2816 RandomX(cache_info->random_info,cache_info->columns),
2817 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2818 *virtual_nexus,exception);
2819 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2822 case DitherVirtualPixelMethod:
2824 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2825 DitherX(x_offset,cache_info->columns),
2826 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2828 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2831 case TileVirtualPixelMethod:
2833 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2834 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2835 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2836 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2838 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2841 case MirrorVirtualPixelMethod:
2843 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2844 if ((x_modulo.quotient & 0x01) == 1L)
2845 x_modulo.remainder=(ssize_t) cache_info->columns-
2846 x_modulo.remainder-1L;
2847 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2848 if ((y_modulo.quotient & 0x01) == 1L)
2849 y_modulo.remainder=(ssize_t) cache_info->rows-
2850 y_modulo.remainder-1L;
2851 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2852 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2854 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2857 case HorizontalTileEdgeVirtualPixelMethod:
2859 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2860 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2861 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2862 *virtual_nexus,exception);
2863 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2866 case VerticalTileEdgeVirtualPixelMethod:
2868 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2869 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2870 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2871 *virtual_nexus,exception);
2872 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2875 case BackgroundVirtualPixelMethod:
2876 case BlackVirtualPixelMethod:
2877 case GrayVirtualPixelMethod:
2878 case TransparentVirtualPixelMethod:
2879 case MaskVirtualPixelMethod:
2880 case WhiteVirtualPixelMethod:
2883 r=virtual_metacontent;
2886 case CheckerTileVirtualPixelMethod:
2888 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2889 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2890 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2893 r=virtual_metacontent;
2896 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2897 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2899 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2902 case HorizontalTileVirtualPixelMethod:
2904 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2907 r=virtual_metacontent;
2910 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2911 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2912 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2913 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2915 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2918 case VerticalTileVirtualPixelMethod:
2920 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2923 r=virtual_metacontent;
2926 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2927 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2928 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2929 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2931 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2935 if (p == (const Quantum *) NULL)
2937 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2939 q+=cache_info->number_channels;
2940 if ((s != (void *) NULL) && (r != (const void *) NULL))
2942 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2943 s+=cache_info->metacontent_extent;
2948 Transfer a run of pixels.
2950 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2951 (size_t) length,1UL,*virtual_nexus,exception);
2952 if (p == (const Quantum *) NULL)
2954 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2955 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2956 q+=length*cache_info->number_channels;
2957 if ((r != (void *) NULL) && (s != (const void *) NULL))
2959 (void) memcpy(s,r,(size_t) length);
2960 s+=length*cache_info->metacontent_extent;
2963 if (u < (ssize_t) columns)
2969 if (virtual_metacontent != (void *) NULL)
2970 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2971 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2972 if (v < (ssize_t) rows)
2973 return((const Quantum *) NULL);
2978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2982 + G e t V i r t u a l P i x e l C a c h e %
2986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2989 % cache as defined by the geometry parameters. A pointer to the pixels
2990 % is returned if the pixels are transferred, otherwise a NULL is returned.
2992 % The format of the GetVirtualPixelCache() method is:
2994 % const Quantum *GetVirtualPixelCache(const Image *image,
2995 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2996 % const ssize_t y,const size_t columns,const size_t rows,
2997 % ExceptionInfo *exception)
2999 % A description of each parameter follows:
3001 % o image: the image.
3003 % o virtual_pixel_method: the virtual pixel method.
3005 % o x,y,columns,rows: These values define the perimeter of a region of
3008 % o exception: return any errors or warnings in this structure.
3011 static const Quantum *GetVirtualPixelCache(const Image *image,
3012 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3013 const size_t columns,const size_t rows,ExceptionInfo *exception)
3016 *magick_restrict cache_info;
3019 id = GetOpenMPThreadId();
3024 assert(image != (const Image *) NULL);
3025 assert(image->signature == MagickCoreSignature);
3026 assert(image->cache != (Cache) NULL);
3027 cache_info=(CacheInfo *) image->cache;
3028 assert(cache_info->signature == MagickCoreSignature);
3029 assert(id < (int) cache_info->number_threads);
3030 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3031 cache_info->nexus_info[id],exception);
3036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040 % G e t V i r t u a l P i x e l Q u e u e %
3044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3047 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3049 % The format of the GetVirtualPixelQueue() method is:
3051 % const Quantum *GetVirtualPixelQueue(const Image image)
3053 % A description of each parameter follows:
3055 % o image: the image.
3058 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3061 *magick_restrict cache_info;
3064 id = GetOpenMPThreadId();
3066 assert(image != (const Image *) NULL);
3067 assert(image->signature == MagickCoreSignature);
3068 assert(image->cache != (Cache) NULL);
3069 cache_info=(CacheInfo *) image->cache;
3070 assert(cache_info->signature == MagickCoreSignature);
3071 if (cache_info->methods.get_virtual_pixels_handler !=
3072 (GetVirtualPixelsHandler) NULL)
3073 return(cache_info->methods.get_virtual_pixels_handler(image));
3074 assert(id < (int) cache_info->number_threads);
3075 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3083 % G e t V i r t u a l P i x e l s %
3087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3089 % GetVirtualPixels() returns an immutable pixel region. If the
3090 % region is successfully accessed, a pointer to it is returned, otherwise
3091 % NULL is returned. The returned pointer may point to a temporary working
3092 % copy of the pixels or it may point to the original pixels in memory.
3093 % Performance is maximized if the selected region is part of one row, or one
3094 % or more full rows, since there is opportunity to access the pixels in-place
3095 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3096 % returned pointer must *never* be deallocated by the user.
3098 % Pixels accessed via the returned pointer represent a simple array of type
3099 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3100 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3101 % access the meta-content (of type void) corresponding to the the
3104 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3106 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3107 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3108 % GetCacheViewAuthenticPixels() instead.
3110 % The format of the GetVirtualPixels() method is:
3112 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3113 % const ssize_t y,const size_t columns,const size_t rows,
3114 % ExceptionInfo *exception)
3116 % A description of each parameter follows:
3118 % o image: the image.
3120 % o x,y,columns,rows: These values define the perimeter of a region of
3123 % o exception: return any errors or warnings in this structure.
3126 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3127 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3128 ExceptionInfo *exception)
3131 *magick_restrict cache_info;
3134 id = GetOpenMPThreadId();
3139 assert(image != (const Image *) NULL);
3140 assert(image->signature == MagickCoreSignature);
3141 assert(image->cache != (Cache) NULL);
3142 cache_info=(CacheInfo *) image->cache;
3143 assert(cache_info->signature == MagickCoreSignature);
3144 if (cache_info->methods.get_virtual_pixel_handler !=
3145 (GetVirtualPixelHandler) NULL)
3146 return(cache_info->methods.get_virtual_pixel_handler(image,
3147 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3148 assert(id < (int) cache_info->number_threads);
3149 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3150 columns,rows,cache_info->nexus_info[id],exception);
3155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3159 + 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 %
3163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3165 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3166 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3168 % The format of the GetVirtualPixelsCache() method is:
3170 % Quantum *GetVirtualPixelsCache(const Image *image)
3172 % A description of each parameter follows:
3174 % o image: the image.
3177 static const Quantum *GetVirtualPixelsCache(const Image *image)
3180 *magick_restrict cache_info;
3183 id = GetOpenMPThreadId();
3185 assert(image != (const Image *) NULL);
3186 assert(image->signature == MagickCoreSignature);
3187 assert(image->cache != (Cache) NULL);
3188 cache_info=(CacheInfo *) image->cache;
3189 assert(cache_info->signature == MagickCoreSignature);
3190 assert(id < (int) cache_info->number_threads);
3191 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3199 + G e t V i r t u a l P i x e l s N e x u s %
3203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3205 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3208 % The format of the GetVirtualPixelsNexus() method is:
3210 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3211 % NexusInfo *nexus_info)
3213 % A description of each parameter follows:
3215 % o cache: the pixel cache.
3217 % o nexus_info: the cache nexus to return the colormap pixels.
3220 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3221 NexusInfo *magick_restrict nexus_info)
3224 *magick_restrict cache_info;
3226 assert(cache != (Cache) NULL);
3227 cache_info=(CacheInfo *) cache;
3228 assert(cache_info->signature == MagickCoreSignature);
3229 if (cache_info->storage_class == UndefinedClass)
3230 return((Quantum *) NULL);
3231 return((const Quantum *) nexus_info->pixels);
3235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3239 + O p e n P i x e l C a c h e %
3243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3245 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3246 % dimensions, allocating space for the image pixels and optionally the
3247 % metacontent, and memory mapping the cache if it is disk based. The cache
3248 % nexus array is initialized as well.
3250 % The format of the OpenPixelCache() method is:
3252 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3253 % ExceptionInfo *exception)
3255 % A description of each parameter follows:
3257 % o image: the image.
3259 % o mode: ReadMode, WriteMode, or IOMode.
3261 % o exception: return any errors or warnings in this structure.
3265 #if defined(__cplusplus) || defined(c_plusplus)
3270 static void CacheSignalHandler(int status)
3272 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3276 #if defined(__cplusplus) || defined(c_plusplus)
3280 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3287 Open pixel cache on disk.
3289 if ((cache_info->file != -1) && (cache_info->mode == mode))
3290 return(MagickTrue); /* cache already open and in the proper mode */
3291 if (*cache_info->cache_filename == '\0')
3292 file=AcquireUniqueFileResource(cache_info->cache_filename);
3298 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3303 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3304 O_BINARY | O_EXCL,S_MODE);
3306 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3312 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3315 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3320 return(MagickFalse);
3321 (void) AcquireMagickResource(FileResource,1);
3322 if (cache_info->file != -1)
3323 (void) ClosePixelCacheOnDisk(cache_info);
3324 cache_info->file=file;
3328 static inline MagickOffsetType WritePixelCacheRegion(
3329 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3330 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3332 register MagickOffsetType
3338 #if !defined(MAGICKCORE_HAVE_PWRITE)
3339 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3340 return((MagickOffsetType) -1);
3343 for (i=0; i < (MagickOffsetType) length; i+=count)
3345 #if !defined(MAGICKCORE_HAVE_PWRITE)
3346 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3349 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3350 SSIZE_MAX),(off_t) (offset+i));
3362 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3365 *magick_restrict cache_info;
3372 cache_info=(CacheInfo *) image->cache;
3373 if (image->debug != MagickFalse)
3376 format[MagickPathExtent],
3377 message[MagickPathExtent];
3379 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3380 (void) FormatLocaleString(message,MagickPathExtent,
3381 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3382 cache_info->cache_filename,cache_info->file,format);
3383 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3385 if (length != (MagickSizeType) ((MagickOffsetType) length))
3386 return(MagickFalse);
3387 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3389 return(MagickFalse);
3390 if ((MagickSizeType) offset >= length)
3391 count=(MagickOffsetType) 1;
3394 extent=(MagickOffsetType) length-1;
3395 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3398 return(MagickFalse);
3399 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3400 if (cache_info->synchronize != MagickFalse)
3401 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3404 (void) signal(SIGBUS,CacheSignalHandler);
3407 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3409 return(MagickFalse);
3413 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3414 ExceptionInfo *exception)
3417 *magick_restrict cache_info,
3421 format[MagickPathExtent],
3422 message[MagickPathExtent];
3438 assert(image != (const Image *) NULL);
3439 assert(image->signature == MagickCoreSignature);
3440 assert(image->cache != (Cache) NULL);
3441 if (image->debug != MagickFalse)
3442 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3443 if (cache_anonymous_memory < 0)
3449 Does the security policy require anonymous mapping for pixel cache?
3451 cache_anonymous_memory=0;
3452 value=GetPolicyValue("pixel-cache-memory");
3453 if (value == (char *) NULL)
3454 value=GetPolicyValue("cache:memory-map");
3455 if (LocaleCompare(value,"anonymous") == 0)
3457 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3458 cache_anonymous_memory=1;
3460 (void) ThrowMagickException(exception,GetMagickModule(),
3461 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3462 "'%s' (policy requires anonymous memory mapping)",image->filename);
3465 value=DestroyString(value);
3467 if ((image->columns == 0) || (image->rows == 0))
3468 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3469 cache_info=(CacheInfo *) image->cache;
3470 assert(cache_info->signature == MagickCoreSignature);
3471 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3472 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3473 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3475 source_info=(*cache_info);
3476 source_info.file=(-1);
3477 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3478 image->filename,(double) GetImageIndexInList(image));
3479 cache_info->storage_class=image->storage_class;
3480 cache_info->colorspace=image->colorspace;
3481 cache_info->alpha_trait=image->alpha_trait;
3482 cache_info->read_mask=image->read_mask;
3483 cache_info->write_mask=image->write_mask;
3484 cache_info->rows=image->rows;
3485 cache_info->columns=image->columns;
3486 InitializePixelChannelMap(image);
3487 cache_info->number_channels=GetPixelChannels(image);
3488 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3489 sizeof(*image->channel_map));
3490 cache_info->metacontent_extent=image->metacontent_extent;
3491 cache_info->mode=mode;
3492 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3493 packet_size=cache_info->number_channels*sizeof(Quantum);
3494 if (image->metacontent_extent != 0)
3495 packet_size+=cache_info->metacontent_extent;
3496 length=number_pixels*packet_size;
3497 columns=(size_t) (length/cache_info->rows/packet_size);
3498 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3499 ((ssize_t) cache_info->rows < 0))
3500 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3502 cache_info->length=length;
3503 if (image->ping != MagickFalse)
3505 cache_info->storage_class=image->storage_class;
3506 cache_info->colorspace=image->colorspace;
3507 cache_info->type=PingCache;
3510 status=AcquireMagickResource(AreaResource,cache_info->length);
3511 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3512 cache_info->metacontent_extent);
3513 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3515 status=AcquireMagickResource(MemoryResource,cache_info->length);
3516 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3517 (cache_info->type == MemoryCache))
3520 if (cache_anonymous_memory <= 0)
3522 cache_info->mapped=MagickFalse;
3523 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3524 AcquireAlignedMemory(1,(size_t) cache_info->length));
3528 cache_info->mapped=MagickTrue;
3529 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3530 cache_info->length);
3532 if (cache_info->pixels == (Quantum *) NULL)
3533 cache_info->pixels=source_info.pixels;
3537 Create memory pixel cache.
3539 cache_info->type=MemoryCache;
3540 cache_info->metacontent=(void *) NULL;
3541 if (cache_info->metacontent_extent != 0)
3542 cache_info->metacontent=(void *) (cache_info->pixels+
3543 number_pixels*cache_info->number_channels);
3544 if ((source_info.storage_class != UndefinedClass) &&
3547 status=ClonePixelCacheRepository(cache_info,&source_info,
3549 RelinquishPixelCachePixels(&source_info);
3551 if (image->debug != MagickFalse)
3553 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3554 MagickPathExtent,format);
3555 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3557 (void) FormatLocaleString(message,MagickPathExtent,
3558 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3559 cache_info->filename,cache_info->mapped != MagickFalse ?
3560 "Anonymous" : "Heap",type,(double) cache_info->columns,
3561 (double) cache_info->rows,(double)
3562 cache_info->number_channels,format);
3563 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3566 return(status == 0 ? MagickFalse : MagickTrue);
3569 RelinquishMagickResource(MemoryResource,cache_info->length);
3572 Create pixel cache on disk.
3574 status=AcquireMagickResource(DiskResource,cache_info->length);
3575 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3580 if (cache_info->type == DistributedCache)
3581 RelinquishMagickResource(DiskResource,cache_info->length);
3582 server_info=AcquireDistributeCacheInfo(exception);
3583 if (server_info != (DistributeCacheInfo *) NULL)
3585 status=OpenDistributePixelCache(server_info,image);
3586 if (status == MagickFalse)
3588 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3589 GetDistributeCacheHostname(server_info));
3590 server_info=DestroyDistributeCacheInfo(server_info);
3595 Create a distributed pixel cache.
3598 cache_info->type=DistributedCache;
3599 cache_info->server_info=server_info;
3600 (void) FormatLocaleString(cache_info->cache_filename,
3601 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3602 (DistributeCacheInfo *) cache_info->server_info),
3603 GetDistributeCachePort((DistributeCacheInfo *)
3604 cache_info->server_info));
3605 if ((source_info.storage_class != UndefinedClass) &&
3608 status=ClonePixelCacheRepository(cache_info,&source_info,
3610 RelinquishPixelCachePixels(&source_info);
3612 if (image->debug != MagickFalse)
3614 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3615 MagickPathExtent,format);
3616 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3618 (void) FormatLocaleString(message,MagickPathExtent,
3619 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3620 cache_info->filename,cache_info->cache_filename,
3621 GetDistributeCacheFile((DistributeCacheInfo *)
3622 cache_info->server_info),type,(double) cache_info->columns,
3623 (double) cache_info->rows,(double)
3624 cache_info->number_channels,format);
3625 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3628 return(status == 0 ? MagickFalse : MagickTrue);
3631 RelinquishMagickResource(DiskResource,cache_info->length);
3632 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3633 "CacheResourcesExhausted","`%s'",image->filename);
3634 return(MagickFalse);
3636 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3638 (void) ClosePixelCacheOnDisk(cache_info);
3639 *cache_info->cache_filename='\0';
3641 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3643 RelinquishMagickResource(DiskResource,cache_info->length);
3644 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3646 return(MagickFalse);
3648 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3649 cache_info->length);
3650 if (status == MagickFalse)
3652 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3654 return(MagickFalse);
3656 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3657 cache_info->metacontent_extent);
3658 if (length != (MagickSizeType) ((size_t) length))
3659 cache_info->type=DiskCache;
3662 status=AcquireMagickResource(MapResource,cache_info->length);
3663 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3664 (cache_info->type != MemoryCache))
3667 cache_info->type=DiskCache;
3672 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3673 cache_info->offset,(size_t) cache_info->length);
3674 if (cache_info->pixels == (Quantum *) NULL)
3676 cache_info->type=DiskCache;
3677 cache_info->pixels=source_info.pixels;
3682 Create file-backed memory-mapped pixel cache.
3684 (void) ClosePixelCacheOnDisk(cache_info);
3685 cache_info->type=MapCache;
3686 cache_info->mapped=MagickTrue;
3687 cache_info->metacontent=(void *) NULL;
3688 if (cache_info->metacontent_extent != 0)
3689 cache_info->metacontent=(void *) (cache_info->pixels+
3690 number_pixels*cache_info->number_channels);
3691 if ((source_info.storage_class != UndefinedClass) &&
3694 status=ClonePixelCacheRepository(cache_info,&source_info,
3696 RelinquishPixelCachePixels(&source_info);
3698 if (image->debug != MagickFalse)
3700 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3701 MagickPathExtent,format);
3702 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3704 (void) FormatLocaleString(message,MagickPathExtent,
3705 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3706 cache_info->filename,cache_info->cache_filename,
3707 cache_info->file,type,(double) cache_info->columns,(double)
3708 cache_info->rows,(double) cache_info->number_channels,
3710 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3713 return(status == 0 ? MagickFalse : MagickTrue);
3716 RelinquishMagickResource(MapResource,cache_info->length);
3719 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3721 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3722 RelinquishPixelCachePixels(&source_info);
3724 if (image->debug != MagickFalse)
3726 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3727 MagickPathExtent,format);
3728 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3730 (void) FormatLocaleString(message,MagickPathExtent,
3731 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3732 cache_info->cache_filename,cache_info->file,type,(double)
3733 cache_info->columns,(double) cache_info->rows,(double)
3734 cache_info->number_channels,format);
3735 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3737 return(status == 0 ? MagickFalse : MagickTrue);
3741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3745 + P e r s i s t P i x e l C a c h e %
3749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3751 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3752 % persistent pixel cache is one that resides on disk and is not destroyed
3753 % when the program exits.
3755 % The format of the PersistPixelCache() method is:
3757 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3758 % const MagickBooleanType attach,MagickOffsetType *offset,
3759 % ExceptionInfo *exception)
3761 % A description of each parameter follows:
3763 % o image: the image.
3765 % o filename: the persistent pixel cache filename.
3767 % o attach: A value other than zero initializes the persistent pixel cache.
3769 % o initialize: A value other than zero initializes the persistent pixel
3772 % o offset: the offset in the persistent cache to store pixels.
3774 % o exception: return any errors or warnings in this structure.
3777 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3778 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3779 ExceptionInfo *exception)
3782 *magick_restrict cache_info,
3783 *magick_restrict clone_info;
3794 assert(image != (Image *) NULL);
3795 assert(image->signature == MagickCoreSignature);
3796 if (image->debug != MagickFalse)
3797 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3798 assert(image->cache != (void *) NULL);
3799 assert(filename != (const char *) NULL);
3800 assert(offset != (MagickOffsetType *) NULL);
3801 page_size=GetMagickPageSize();
3802 cache_info=(CacheInfo *) image->cache;
3803 assert(cache_info->signature == MagickCoreSignature);
3804 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3805 CopyOpenCLBuffer(cache_info);
3807 if (attach != MagickFalse)
3810 Attach existing persistent pixel cache.
3812 if (image->debug != MagickFalse)
3813 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3814 "attach persistent cache");
3815 (void) CopyMagickString(cache_info->cache_filename,filename,
3817 cache_info->type=DiskCache;
3818 cache_info->offset=(*offset);
3819 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3820 return(MagickFalse);
3821 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3825 Clone persistent pixel cache.
3827 clone_image=(*image);
3828 clone_info=(CacheInfo *) clone_image.cache;
3829 image->cache=ClonePixelCache(cache_info);
3830 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3831 (void) CopyMagickString(cache_info->cache_filename,filename,MagickPathExtent);
3832 cache_info->type=DiskCache;
3833 cache_info->offset=(*offset);
3834 cache_info=(CacheInfo *) image->cache;
3835 status=OpenPixelCache(image,IOMode,exception);
3836 if (status != MagickFalse)
3837 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3838 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3839 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3848 + 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 %
3852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3854 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3855 % defined by the region rectangle and returns a pointer to the region. This
3856 % region is subsequently transferred from the pixel cache with
3857 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3858 % pixels are transferred, otherwise a NULL is returned.
3860 % The format of the QueueAuthenticPixelCacheNexus() method is:
3862 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3863 % const ssize_t y,const size_t columns,const size_t rows,
3864 % const MagickBooleanType clone,NexusInfo *nexus_info,
3865 % ExceptionInfo *exception)
3867 % A description of each parameter follows:
3869 % o image: the image.
3871 % o x,y,columns,rows: These values define the perimeter of a region of
3874 % o nexus_info: the cache nexus to set.
3876 % o clone: clone the pixel cache.
3878 % o exception: return any errors or warnings in this structure.
3881 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3882 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3883 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3886 *magick_restrict cache_info;
3895 *magick_restrict pixels;
3901 Validate pixel cache geometry.
3903 assert(image != (const Image *) NULL);
3904 assert(image->signature == MagickCoreSignature);
3905 assert(image->cache != (Cache) NULL);
3906 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3907 if (cache_info == (Cache) NULL)
3908 return((Quantum *) NULL);
3909 assert(cache_info->signature == MagickCoreSignature);
3910 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3911 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3912 (y >= (ssize_t) cache_info->rows))
3914 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3915 "PixelsAreNotAuthentic","`%s'",image->filename);
3916 return((Quantum *) NULL);
3918 offset=(MagickOffsetType) y*cache_info->columns+x;
3920 return((Quantum *) NULL);
3921 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3922 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3923 if ((MagickSizeType) offset >= number_pixels)
3924 return((Quantum *) NULL);
3930 region.width=columns;
3932 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3942 + 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 %
3946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3948 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3949 % defined by the region rectangle and returns a pointer to the region. This
3950 % region is subsequently transferred from the pixel cache with
3951 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3952 % pixels are transferred, otherwise a NULL is returned.
3954 % The format of the QueueAuthenticPixelsCache() method is:
3956 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3957 % const ssize_t y,const size_t columns,const size_t rows,
3958 % ExceptionInfo *exception)
3960 % A description of each parameter follows:
3962 % o image: the image.
3964 % o x,y,columns,rows: These values define the perimeter of a region of
3967 % o exception: return any errors or warnings in this structure.
3970 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3971 const ssize_t y,const size_t columns,const size_t rows,
3972 ExceptionInfo *exception)
3975 *magick_restrict cache_info;
3978 id = GetOpenMPThreadId();
3981 *magick_restrict pixels;
3983 assert(image != (const Image *) NULL);
3984 assert(image->signature == MagickCoreSignature);
3985 assert(image->cache != (Cache) NULL);
3986 cache_info=(CacheInfo *) image->cache;
3987 assert(cache_info->signature == MagickCoreSignature);
3988 assert(id < (int) cache_info->number_threads);
3989 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3990 cache_info->nexus_info[id],exception);
3995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3999 % Q u e u e A u t h e n t i c P i x e l s %
4003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4005 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4006 % successfully initialized a pointer to a Quantum array representing the
4007 % region is returned, otherwise NULL is returned. The returned pointer may
4008 % point to a temporary working buffer for the pixels or it may point to the
4009 % final location of the pixels in memory.
4011 % Write-only access means that any existing pixel values corresponding to
4012 % the region are ignored. This is useful if the initial image is being
4013 % created from scratch, or if the existing pixel values are to be
4014 % completely replaced without need to refer to their pre-existing values.
4015 % The application is free to read and write the pixel buffer returned by
4016 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4017 % initialize the pixel array values. Initializing pixel array values is the
4018 % application's responsibility.
4020 % Performance is maximized if the selected region is part of one row, or
4021 % one or more full rows, since then there is opportunity to access the
4022 % pixels in-place (without a copy) if the image is in memory, or in a
4023 % memory-mapped file. The returned pointer must *never* be deallocated
4026 % Pixels accessed via the returned pointer represent a simple array of type
4027 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4028 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4029 % obtain the meta-content (of type void) corresponding to the region.
4030 % Once the Quantum (and/or Quantum) array has been updated, the
4031 % changes must be saved back to the underlying image using
4032 % SyncAuthenticPixels() or they may be lost.
4034 % The format of the QueueAuthenticPixels() method is:
4036 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4037 % const ssize_t y,const size_t columns,const size_t rows,
4038 % ExceptionInfo *exception)
4040 % A description of each parameter follows:
4042 % o image: the image.
4044 % o x,y,columns,rows: These values define the perimeter of a region of
4047 % o exception: return any errors or warnings in this structure.
4050 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4051 const ssize_t y,const size_t columns,const size_t rows,
4052 ExceptionInfo *exception)
4055 *magick_restrict cache_info;
4058 id = GetOpenMPThreadId();
4061 *magick_restrict pixels;
4063 assert(image != (Image *) NULL);
4064 assert(image->signature == MagickCoreSignature);
4065 assert(image->cache != (Cache) NULL);
4066 cache_info=(CacheInfo *) image->cache;
4067 assert(cache_info->signature == MagickCoreSignature);
4068 if (cache_info->methods.queue_authentic_pixels_handler !=
4069 (QueueAuthenticPixelsHandler) NULL)
4071 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4072 columns,rows,exception);
4075 assert(id < (int) cache_info->number_threads);
4076 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4077 cache_info->nexus_info[id],exception);
4082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4086 + 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 %
4090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4092 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4095 % The format of the ReadPixelCacheMetacontent() method is:
4097 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4098 % NexusInfo *nexus_info,ExceptionInfo *exception)
4100 % A description of each parameter follows:
4102 % o cache_info: the pixel cache.
4104 % o nexus_info: the cache nexus to read the metacontent.
4106 % o exception: return any errors or warnings in this structure.
4110 static inline MagickOffsetType ReadPixelCacheRegion(
4111 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4112 const MagickSizeType length,unsigned char *magick_restrict buffer)
4114 register MagickOffsetType
4120 #if !defined(MAGICKCORE_HAVE_PREAD)
4121 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4122 return((MagickOffsetType) -1);
4125 for (i=0; i < (MagickOffsetType) length; i+=count)
4127 #if !defined(MAGICKCORE_HAVE_PREAD)
4128 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4131 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4132 SSIZE_MAX),(off_t) (offset+i));
4144 static MagickBooleanType ReadPixelCacheMetacontent(
4145 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4146 ExceptionInfo *exception)
4159 register unsigned char
4165 if (cache_info->metacontent_extent == 0)
4166 return(MagickFalse);
4167 if (nexus_info->authentic_pixel_cache != MagickFalse)
4169 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4170 nexus_info->region.x;
4171 length=(MagickSizeType) nexus_info->region.width*
4172 cache_info->metacontent_extent;
4173 extent=length*nexus_info->region.height;
4174 rows=nexus_info->region.height;
4176 q=(unsigned char *) nexus_info->metacontent;
4177 switch (cache_info->type)
4182 register unsigned char
4186 Read meta-content from memory.
4188 if ((cache_info->columns == nexus_info->region.width) &&
4189 (extent == (MagickSizeType) ((size_t) extent)))
4194 p=(unsigned char *) cache_info->metacontent+offset*
4195 cache_info->metacontent_extent;
4196 for (y=0; y < (ssize_t) rows; y++)
4198 (void) memcpy(q,p,(size_t) length);
4199 p+=cache_info->metacontent_extent*cache_info->columns;
4200 q+=cache_info->metacontent_extent*nexus_info->region.width;
4207 Read meta content from disk.
4209 LockSemaphoreInfo(cache_info->file_semaphore);
4210 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4212 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4213 cache_info->cache_filename);
4214 UnlockSemaphoreInfo(cache_info->file_semaphore);
4215 return(MagickFalse);
4217 if ((cache_info->columns == nexus_info->region.width) &&
4218 (extent <= MagickMaxBufferExtent))
4223 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4224 for (y=0; y < (ssize_t) rows; y++)
4226 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4227 cache_info->number_channels*sizeof(Quantum)+offset*
4228 cache_info->metacontent_extent,length,(unsigned char *) q);
4229 if (count != (MagickOffsetType) length)
4231 offset+=cache_info->columns;
4232 q+=cache_info->metacontent_extent*nexus_info->region.width;
4234 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4235 (void) ClosePixelCacheOnDisk(cache_info);
4236 UnlockSemaphoreInfo(cache_info->file_semaphore);
4239 case DistributedCache:
4245 Read metacontent from distributed cache.
4247 LockSemaphoreInfo(cache_info->file_semaphore);
4248 region=nexus_info->region;
4249 if ((cache_info->columns != nexus_info->region.width) ||
4250 (extent > MagickMaxBufferExtent))
4257 for (y=0; y < (ssize_t) rows; y++)
4259 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4260 cache_info->server_info,®ion,length,(unsigned char *) q);
4261 if (count != (MagickOffsetType) length)
4263 q+=cache_info->metacontent_extent*nexus_info->region.width;
4266 UnlockSemaphoreInfo(cache_info->file_semaphore);
4272 if (y < (ssize_t) rows)
4274 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4275 cache_info->cache_filename);
4276 return(MagickFalse);
4278 if ((cache_info->debug != MagickFalse) &&
4279 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4280 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4281 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4282 nexus_info->region.width,(double) nexus_info->region.height,(double)
4283 nexus_info->region.x,(double) nexus_info->region.y);
4288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4292 + R e a d P i x e l C a c h e P i x e l s %
4296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4298 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4301 % The format of the ReadPixelCachePixels() method is:
4303 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4304 % NexusInfo *nexus_info,ExceptionInfo *exception)
4306 % A description of each parameter follows:
4308 % o cache_info: the pixel cache.
4310 % o nexus_info: the cache nexus to read the pixels.
4312 % o exception: return any errors or warnings in this structure.
4315 static MagickBooleanType ReadPixelCachePixels(
4316 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4317 ExceptionInfo *exception)
4337 if (nexus_info->authentic_pixel_cache != MagickFalse)
4339 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4340 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4341 return(MagickFalse);
4342 offset+=nexus_info->region.x;
4343 number_channels=cache_info->number_channels;
4344 length=(MagickSizeType) number_channels*nexus_info->region.width*
4346 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4347 return(MagickFalse);
4348 rows=nexus_info->region.height;
4350 if ((extent == 0) || ((extent/length) != rows))
4351 return(MagickFalse);
4353 q=nexus_info->pixels;
4354 switch (cache_info->type)
4363 Read pixels from memory.
4365 if ((cache_info->columns == nexus_info->region.width) &&
4366 (extent == (MagickSizeType) ((size_t) extent)))
4371 p=cache_info->pixels+offset*cache_info->number_channels;
4372 for (y=0; y < (ssize_t) rows; y++)
4374 (void) memcpy(q,p,(size_t) length);
4375 p+=cache_info->number_channels*cache_info->columns;
4376 q+=cache_info->number_channels*nexus_info->region.width;
4383 Read pixels from disk.
4385 LockSemaphoreInfo(cache_info->file_semaphore);
4386 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4388 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4389 cache_info->cache_filename);
4390 UnlockSemaphoreInfo(cache_info->file_semaphore);
4391 return(MagickFalse);
4393 if ((cache_info->columns == nexus_info->region.width) &&
4394 (extent <= MagickMaxBufferExtent))
4399 for (y=0; y < (ssize_t) rows; y++)
4401 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4402 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4403 if (count != (MagickOffsetType) length)
4405 offset+=cache_info->columns;
4406 q+=cache_info->number_channels*nexus_info->region.width;
4408 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4409 (void) ClosePixelCacheOnDisk(cache_info);
4410 UnlockSemaphoreInfo(cache_info->file_semaphore);
4413 case DistributedCache:
4419 Read pixels from distributed cache.
4421 LockSemaphoreInfo(cache_info->file_semaphore);
4422 region=nexus_info->region;
4423 if ((cache_info->columns != nexus_info->region.width) ||
4424 (extent > MagickMaxBufferExtent))
4431 for (y=0; y < (ssize_t) rows; y++)
4433 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4434 cache_info->server_info,®ion,length,(unsigned char *) q);
4435 if (count != (MagickOffsetType) length)
4437 q+=cache_info->number_channels*nexus_info->region.width;
4440 UnlockSemaphoreInfo(cache_info->file_semaphore);
4446 if (y < (ssize_t) rows)
4448 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4449 cache_info->cache_filename);
4450 return(MagickFalse);
4452 if ((cache_info->debug != MagickFalse) &&
4453 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4454 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4455 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4456 nexus_info->region.width,(double) nexus_info->region.height,(double)
4457 nexus_info->region.x,(double) nexus_info->region.y);
4462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4466 + R e f e r e n c e P i x e l C a c h e %
4470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4472 % ReferencePixelCache() increments the reference count associated with the
4473 % pixel cache returning a pointer to the cache.
4475 % The format of the ReferencePixelCache method is:
4477 % Cache ReferencePixelCache(Cache cache_info)
4479 % A description of each parameter follows:
4481 % o cache_info: the pixel cache.
4484 MagickPrivate Cache ReferencePixelCache(Cache cache)
4487 *magick_restrict cache_info;
4489 assert(cache != (Cache *) NULL);
4490 cache_info=(CacheInfo *) cache;
4491 assert(cache_info->signature == MagickCoreSignature);
4492 LockSemaphoreInfo(cache_info->semaphore);
4493 cache_info->reference_count++;
4494 UnlockSemaphoreInfo(cache_info->semaphore);
4499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4503 + R e s e t P i x e l C a c h e C h a n n e l s %
4507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4509 % ResetPixelCacheChannels() resets the pixel cache channels.
4511 % The format of the ResetPixelCacheChannels method is:
4513 % void ResetPixelCacheChannels(Image *)
4515 % A description of each parameter follows:
4517 % o image: the image.
4520 MagickPrivate void ResetPixelCacheChannels(Image *image)
4523 *magick_restrict cache_info;
4525 assert(image != (const Image *) NULL);
4526 assert(image->signature == MagickCoreSignature);
4527 assert(image->cache != (Cache) NULL);
4528 cache_info=(CacheInfo *) image->cache;
4529 assert(cache_info->signature == MagickCoreSignature);
4530 cache_info->number_channels=GetPixelChannels(image);
4534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4538 + R e s e t P i x e l C a c h e E p o c h %
4542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4544 % ResetPixelCacheEpoch() resets the pixel cache epoch.
4546 % The format of the ResetPixelCacheEpoch method is:
4548 % void ResetPixelCacheEpoch(void)
4551 MagickPrivate void ResetPixelCacheEpoch(void)
4557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561 + S e t P i x e l C a c h e M e t h o d s %
4565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4567 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4569 % The format of the SetPixelCacheMethods() method is:
4571 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4573 % A description of each parameter follows:
4575 % o cache: the pixel cache.
4577 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4580 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4583 *magick_restrict cache_info;
4585 GetOneAuthenticPixelFromHandler
4586 get_one_authentic_pixel_from_handler;
4588 GetOneVirtualPixelFromHandler
4589 get_one_virtual_pixel_from_handler;
4592 Set cache pixel methods.
4594 assert(cache != (Cache) NULL);
4595 assert(cache_methods != (CacheMethods *) NULL);
4596 cache_info=(CacheInfo *) cache;
4597 assert(cache_info->signature == MagickCoreSignature);
4598 if (cache_info->debug != MagickFalse)
4599 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4600 cache_info->filename);
4601 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4602 cache_info->methods.get_virtual_pixel_handler=
4603 cache_methods->get_virtual_pixel_handler;
4604 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4605 cache_info->methods.destroy_pixel_handler=
4606 cache_methods->destroy_pixel_handler;
4607 if (cache_methods->get_virtual_metacontent_from_handler !=
4608 (GetVirtualMetacontentFromHandler) NULL)
4609 cache_info->methods.get_virtual_metacontent_from_handler=
4610 cache_methods->get_virtual_metacontent_from_handler;
4611 if (cache_methods->get_authentic_pixels_handler !=
4612 (GetAuthenticPixelsHandler) NULL)
4613 cache_info->methods.get_authentic_pixels_handler=
4614 cache_methods->get_authentic_pixels_handler;
4615 if (cache_methods->queue_authentic_pixels_handler !=
4616 (QueueAuthenticPixelsHandler) NULL)
4617 cache_info->methods.queue_authentic_pixels_handler=
4618 cache_methods->queue_authentic_pixels_handler;
4619 if (cache_methods->sync_authentic_pixels_handler !=
4620 (SyncAuthenticPixelsHandler) NULL)
4621 cache_info->methods.sync_authentic_pixels_handler=
4622 cache_methods->sync_authentic_pixels_handler;
4623 if (cache_methods->get_authentic_pixels_from_handler !=
4624 (GetAuthenticPixelsFromHandler) NULL)
4625 cache_info->methods.get_authentic_pixels_from_handler=
4626 cache_methods->get_authentic_pixels_from_handler;
4627 if (cache_methods->get_authentic_metacontent_from_handler !=
4628 (GetAuthenticMetacontentFromHandler) NULL)
4629 cache_info->methods.get_authentic_metacontent_from_handler=
4630 cache_methods->get_authentic_metacontent_from_handler;
4631 get_one_virtual_pixel_from_handler=
4632 cache_info->methods.get_one_virtual_pixel_from_handler;
4633 if (get_one_virtual_pixel_from_handler !=
4634 (GetOneVirtualPixelFromHandler) NULL)
4635 cache_info->methods.get_one_virtual_pixel_from_handler=
4636 cache_methods->get_one_virtual_pixel_from_handler;
4637 get_one_authentic_pixel_from_handler=
4638 cache_methods->get_one_authentic_pixel_from_handler;
4639 if (get_one_authentic_pixel_from_handler !=
4640 (GetOneAuthenticPixelFromHandler) NULL)
4641 cache_info->methods.get_one_authentic_pixel_from_handler=
4642 cache_methods->get_one_authentic_pixel_from_handler;
4646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4650 + S e t P i x e l C a c h e N e x u s P i x e l s %
4654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4656 % SetPixelCacheNexusPixels() defines the region of the cache for the
4657 % specified cache nexus.
4659 % The format of the SetPixelCacheNexusPixels() method is:
4661 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4662 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4663 % ExceptionInfo *exception)
4665 % A description of each parameter follows:
4667 % o cache_info: the pixel cache.
4669 % o mode: ReadMode, WriteMode, or IOMode.
4671 % o region: A pointer to the RectangleInfo structure that defines the
4672 % region of this particular cache nexus.
4674 % o nexus_info: the cache nexus to set.
4676 % o exception: return any errors or warnings in this structure.
4680 static inline MagickBooleanType AcquireCacheNexusPixels(
4681 const CacheInfo *magick_restrict cache_info,NexusInfo *nexus_info,
4682 ExceptionInfo *exception)
4684 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4685 return(MagickFalse);
4686 if (cache_anonymous_memory <= 0)
4688 nexus_info->mapped=MagickFalse;
4689 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4690 (size_t) nexus_info->length));
4691 if (nexus_info->cache != (Quantum *) NULL)
4692 (void) ResetMagickMemory(nexus_info->cache,0,(size_t)
4693 nexus_info->length);
4697 nexus_info->mapped=MagickTrue;
4698 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4699 nexus_info->length);
4701 if (nexus_info->cache == (Quantum *) NULL)
4703 (void) ThrowMagickException(exception,GetMagickModule(),
4704 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4705 cache_info->filename);
4706 return(MagickFalse);
4711 static inline MagickBooleanType IsPixelCacheAuthentic(
4712 const CacheInfo *magick_restrict cache_info,
4713 const NexusInfo *magick_restrict nexus_info)
4722 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4724 if (cache_info->type == PingCache)
4726 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4727 nexus_info->region.x;
4728 status=nexus_info->pixels == (cache_info->pixels+offset*
4729 cache_info->number_channels) ? MagickTrue : MagickFalse;
4733 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4736 if (mode == ReadMode)
4738 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4741 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4744 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4745 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4746 ExceptionInfo *exception)
4755 assert(cache_info != (const CacheInfo *) NULL);
4756 assert(cache_info->signature == MagickCoreSignature);
4757 if (cache_info->type == UndefinedCache)
4758 return((Quantum *) NULL);
4759 nexus_info->region=(*region);
4760 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4766 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4767 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4768 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4769 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4770 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4771 ((nexus_info->region.width == cache_info->columns) ||
4772 ((nexus_info->region.width % cache_info->columns) == 0)))))
4778 Pixels are accessed directly from memory.
4780 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4781 nexus_info->region.x;
4782 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4784 nexus_info->metacontent=(void *) NULL;
4785 if (cache_info->metacontent_extent != 0)
4786 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4787 offset*cache_info->metacontent_extent;
4788 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4789 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4791 return(nexus_info->pixels);
4795 Pixels are stored in a staging region until they are synced to the cache.
4797 number_pixels=(MagickSizeType) nexus_info->region.width*
4798 nexus_info->region.height;
4799 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4800 if (cache_info->metacontent_extent != 0)
4801 length+=number_pixels*cache_info->metacontent_extent;
4802 if (nexus_info->cache == (Quantum *) NULL)
4804 nexus_info->length=length;
4805 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4806 if (status == MagickFalse)
4808 nexus_info->length=0;
4809 return((Quantum *) NULL);
4813 if (nexus_info->length < length)
4815 RelinquishCacheNexusPixels(nexus_info);
4816 nexus_info->length=length;
4817 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4818 if (status == MagickFalse)
4820 nexus_info->length=0;
4821 return((Quantum *) NULL);
4824 nexus_info->pixels=nexus_info->cache;
4825 nexus_info->metacontent=(void *) NULL;
4826 if (cache_info->metacontent_extent != 0)
4827 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4828 cache_info->number_channels);
4829 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4830 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4832 return(nexus_info->pixels);
4836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4840 % 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 %
4844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4846 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4847 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4848 % access that is outside the boundaries of the image cache.
4850 % The format of the SetPixelCacheVirtualMethod() method is:
4852 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4853 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4855 % A description of each parameter follows:
4857 % o image: the image.
4859 % o virtual_pixel_method: choose the type of virtual pixel.
4861 % o exception: return any errors or warnings in this structure.
4865 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4866 ExceptionInfo *exception)
4869 *magick_restrict cache_info;
4872 *magick_restrict image_view;
4880 assert(image != (Image *) NULL);
4881 assert(image->signature == MagickCoreSignature);
4882 if (image->debug != MagickFalse)
4883 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4884 assert(image->cache != (Cache) NULL);
4885 cache_info=(CacheInfo *) image->cache;
4886 assert(cache_info->signature == MagickCoreSignature);
4887 image->alpha_trait=BlendPixelTrait;
4889 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4890 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4891 #pragma omp parallel for schedule(static,4) shared(status) \
4892 magick_threads(image,image,1,1)
4894 for (y=0; y < (ssize_t) image->rows; y++)
4902 if (status == MagickFalse)
4904 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4905 if (q == (Quantum *) NULL)
4910 for (x=0; x < (ssize_t) image->columns; x++)
4912 SetPixelAlpha(image,alpha,q);
4913 q+=GetPixelChannels(image);
4915 status=SyncCacheViewAuthenticPixels(image_view,exception);
4917 image_view=DestroyCacheView(image_view);
4921 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4922 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4925 *magick_restrict cache_info;
4930 assert(image != (Image *) NULL);
4931 assert(image->signature == MagickCoreSignature);
4932 if (image->debug != MagickFalse)
4933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4934 assert(image->cache != (Cache) NULL);
4935 cache_info=(CacheInfo *) image->cache;
4936 assert(cache_info->signature == MagickCoreSignature);
4937 method=cache_info->virtual_pixel_method;
4938 cache_info->virtual_pixel_method=virtual_pixel_method;
4939 if ((image->columns != 0) && (image->rows != 0))
4940 switch (virtual_pixel_method)
4942 case BackgroundVirtualPixelMethod:
4944 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4945 (image->alpha_trait == UndefinedPixelTrait))
4946 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4947 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4948 (IsGrayColorspace(image->colorspace) != MagickFalse))
4949 (void) SetImageColorspace(image,sRGBColorspace,exception);
4952 case TransparentVirtualPixelMethod:
4954 if (image->alpha_trait == UndefinedPixelTrait)
4955 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4964 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4970 + 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 %
4974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4976 % SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
4977 % been completed and updates the host memory.
4979 % The format of the SyncAuthenticOpenCLBuffer() method is:
4981 % void SyncAuthenticOpenCLBuffer(const Image *image)
4983 % A description of each parameter follows:
4985 % o image: the image.
4989 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
4991 assert(cache_info != (CacheInfo *) NULL);
4992 assert(cache_info->signature == MagickCoreSignature);
4993 if ((cache_info->type != MemoryCache) ||
4994 (cache_info->opencl == (MagickCLCacheInfo) NULL))
4997 Ensure single threaded access to OpenCL environment.
4999 LockSemaphoreInfo(cache_info->semaphore);
5000 cache_info->opencl=(MagickCLCacheInfo) CopyMagickCLCacheInfo(
5001 cache_info->opencl);
5002 UnlockSemaphoreInfo(cache_info->semaphore);
5005 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5008 *magick_restrict cache_info;
5010 assert(image != (const Image *) NULL);
5011 cache_info=(CacheInfo *) image->cache;
5012 CopyOpenCLBuffer(cache_info);
5017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5021 + 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 %
5025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5027 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5028 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5029 % is synced, otherwise MagickFalse.
5031 % The format of the SyncAuthenticPixelCacheNexus() method is:
5033 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5034 % NexusInfo *nexus_info,ExceptionInfo *exception)
5036 % A description of each parameter follows:
5038 % o image: the image.
5040 % o nexus_info: the cache nexus to sync.
5042 % o exception: return any errors or warnings in this structure.
5045 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5046 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5049 *magick_restrict cache_info;
5055 Transfer pixels to the cache.
5057 assert(image != (Image *) NULL);
5058 assert(image->signature == MagickCoreSignature);
5059 if (image->cache == (Cache) NULL)
5060 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5061 cache_info=(CacheInfo *) image->cache;
5062 assert(cache_info->signature == MagickCoreSignature);
5063 if (cache_info->type == UndefinedCache)
5064 return(MagickFalse);
5065 if (nexus_info->authentic_pixel_cache != MagickFalse)
5067 image->taint=MagickTrue;
5070 assert(cache_info->signature == MagickCoreSignature);
5071 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5072 if ((cache_info->metacontent_extent != 0) &&
5073 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5074 return(MagickFalse);
5075 if (status != MagickFalse)
5076 image->taint=MagickTrue;
5081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5085 + S y n c A u t h e n t i c P i x e l C a c h e %
5089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5091 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5092 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5093 % otherwise MagickFalse.
5095 % The format of the SyncAuthenticPixelsCache() method is:
5097 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5098 % ExceptionInfo *exception)
5100 % A description of each parameter follows:
5102 % o image: the image.
5104 % o exception: return any errors or warnings in this structure.
5107 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5108 ExceptionInfo *exception)
5111 *magick_restrict cache_info;
5114 id = GetOpenMPThreadId();
5119 assert(image != (Image *) NULL);
5120 assert(image->signature == MagickCoreSignature);
5121 assert(image->cache != (Cache) NULL);
5122 cache_info=(CacheInfo *) image->cache;
5123 assert(cache_info->signature == MagickCoreSignature);
5124 assert(id < (int) cache_info->number_threads);
5125 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5135 % S y n c A u t h e n t i c P i x e l s %
5139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5141 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5142 % The method returns MagickTrue if the pixel region is flushed, otherwise
5145 % The format of the SyncAuthenticPixels() method is:
5147 % MagickBooleanType SyncAuthenticPixels(Image *image,
5148 % ExceptionInfo *exception)
5150 % A description of each parameter follows:
5152 % o image: the image.
5154 % o exception: return any errors or warnings in this structure.
5157 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5158 ExceptionInfo *exception)
5161 *magick_restrict cache_info;
5164 id = GetOpenMPThreadId();
5169 assert(image != (Image *) NULL);
5170 assert(image->signature == MagickCoreSignature);
5171 assert(image->cache != (Cache) NULL);
5172 cache_info=(CacheInfo *) image->cache;
5173 assert(cache_info->signature == MagickCoreSignature);
5174 if (cache_info->methods.sync_authentic_pixels_handler !=
5175 (SyncAuthenticPixelsHandler) NULL)
5177 status=cache_info->methods.sync_authentic_pixels_handler(image,
5181 assert(id < (int) cache_info->number_threads);
5182 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5192 + S y n c I m a g e P i x e l C a c h e %
5196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5198 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5199 % The method returns MagickTrue if the pixel region is flushed, otherwise
5202 % The format of the SyncImagePixelCache() method is:
5204 % MagickBooleanType SyncImagePixelCache(Image *image,
5205 % ExceptionInfo *exception)
5207 % A description of each parameter follows:
5209 % o image: the image.
5211 % o exception: return any errors or warnings in this structure.
5214 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5215 ExceptionInfo *exception)
5218 *magick_restrict cache_info;
5220 assert(image != (Image *) NULL);
5221 assert(exception != (ExceptionInfo *) NULL);
5222 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5223 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5231 + 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 %
5235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5237 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5238 % of the pixel cache.
5240 % The format of the WritePixelCacheMetacontent() method is:
5242 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5243 % NexusInfo *nexus_info,ExceptionInfo *exception)
5245 % A description of each parameter follows:
5247 % o cache_info: the pixel cache.
5249 % o nexus_info: the cache nexus to write the meta-content.
5251 % o exception: return any errors or warnings in this structure.
5254 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5255 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5265 register const unsigned char
5274 if (cache_info->metacontent_extent == 0)
5275 return(MagickFalse);
5276 if (nexus_info->authentic_pixel_cache != MagickFalse)
5278 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5279 nexus_info->region.x;
5280 length=(MagickSizeType) nexus_info->region.width*
5281 cache_info->metacontent_extent;
5282 extent=(MagickSizeType) length*nexus_info->region.height;
5283 rows=nexus_info->region.height;
5285 p=(unsigned char *) nexus_info->metacontent;
5286 switch (cache_info->type)
5291 register unsigned char
5295 Write associated pixels to memory.
5297 if ((cache_info->columns == nexus_info->region.width) &&
5298 (extent == (MagickSizeType) ((size_t) extent)))
5303 q=(unsigned char *) cache_info->metacontent+offset*
5304 cache_info->metacontent_extent;
5305 for (y=0; y < (ssize_t) rows; y++)
5307 (void) memcpy(q,p,(size_t) length);
5308 p+=nexus_info->region.width*cache_info->metacontent_extent;
5309 q+=cache_info->columns*cache_info->metacontent_extent;
5316 Write associated pixels to disk.
5318 LockSemaphoreInfo(cache_info->file_semaphore);
5319 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5321 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5322 cache_info->cache_filename);
5323 UnlockSemaphoreInfo(cache_info->file_semaphore);
5324 return(MagickFalse);
5326 if ((cache_info->columns == nexus_info->region.width) &&
5327 (extent <= MagickMaxBufferExtent))
5332 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5333 for (y=0; y < (ssize_t) rows; y++)
5335 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5336 cache_info->number_channels*sizeof(Quantum)+offset*
5337 cache_info->metacontent_extent,length,(const unsigned char *) p);
5338 if (count != (MagickOffsetType) length)
5340 p+=cache_info->metacontent_extent*nexus_info->region.width;
5341 offset+=cache_info->columns;
5343 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5344 (void) ClosePixelCacheOnDisk(cache_info);
5345 UnlockSemaphoreInfo(cache_info->file_semaphore);
5348 case DistributedCache:
5354 Write metacontent to distributed cache.
5356 LockSemaphoreInfo(cache_info->file_semaphore);
5357 region=nexus_info->region;
5358 if ((cache_info->columns != nexus_info->region.width) ||
5359 (extent > MagickMaxBufferExtent))
5366 for (y=0; y < (ssize_t) rows; y++)
5368 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5369 cache_info->server_info,®ion,length,(const unsigned char *) p);
5370 if (count != (MagickOffsetType) length)
5372 p+=cache_info->metacontent_extent*nexus_info->region.width;
5375 UnlockSemaphoreInfo(cache_info->file_semaphore);
5381 if (y < (ssize_t) rows)
5383 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5384 cache_info->cache_filename);
5385 return(MagickFalse);
5387 if ((cache_info->debug != MagickFalse) &&
5388 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5389 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5390 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5391 nexus_info->region.width,(double) nexus_info->region.height,(double)
5392 nexus_info->region.x,(double) nexus_info->region.y);
5397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5401 + W r i t e C a c h e P i x e l s %
5405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5407 % WritePixelCachePixels() writes image pixels to the specified region of the
5410 % The format of the WritePixelCachePixels() method is:
5412 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5413 % NexusInfo *nexus_info,ExceptionInfo *exception)
5415 % A description of each parameter follows:
5417 % o cache_info: the pixel cache.
5419 % o nexus_info: the cache nexus to write the pixels.
5421 % o exception: return any errors or warnings in this structure.
5424 static MagickBooleanType WritePixelCachePixels(
5425 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5426 ExceptionInfo *exception)
5436 register const Quantum
5445 if (nexus_info->authentic_pixel_cache != MagickFalse)
5447 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5448 nexus_info->region.x;
5449 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5451 extent=length*nexus_info->region.height;
5452 rows=nexus_info->region.height;
5454 p=nexus_info->pixels;
5455 switch (cache_info->type)
5464 Write pixels to memory.
5466 if ((cache_info->columns == nexus_info->region.width) &&
5467 (extent == (MagickSizeType) ((size_t) extent)))
5472 q=cache_info->pixels+offset*cache_info->number_channels;
5473 for (y=0; y < (ssize_t) rows; y++)
5475 (void) memcpy(q,p,(size_t) length);
5476 p+=cache_info->number_channels*nexus_info->region.width;
5477 q+=cache_info->columns*cache_info->number_channels;
5484 Write pixels to disk.
5486 LockSemaphoreInfo(cache_info->file_semaphore);
5487 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5489 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5490 cache_info->cache_filename);
5491 UnlockSemaphoreInfo(cache_info->file_semaphore);
5492 return(MagickFalse);
5494 if ((cache_info->columns == nexus_info->region.width) &&
5495 (extent <= MagickMaxBufferExtent))
5500 for (y=0; y < (ssize_t) rows; y++)
5502 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5503 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5505 if (count != (MagickOffsetType) length)
5507 p+=cache_info->number_channels*nexus_info->region.width;
5508 offset+=cache_info->columns;
5510 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5511 (void) ClosePixelCacheOnDisk(cache_info);
5512 UnlockSemaphoreInfo(cache_info->file_semaphore);
5515 case DistributedCache:
5521 Write pixels to distributed cache.
5523 LockSemaphoreInfo(cache_info->file_semaphore);
5524 region=nexus_info->region;
5525 if ((cache_info->columns != nexus_info->region.width) ||
5526 (extent > MagickMaxBufferExtent))
5533 for (y=0; y < (ssize_t) rows; y++)
5535 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5536 cache_info->server_info,®ion,length,(const unsigned char *) p);
5537 if (count != (MagickOffsetType) length)
5539 p+=cache_info->number_channels*nexus_info->region.width;
5542 UnlockSemaphoreInfo(cache_info->file_semaphore);
5548 if (y < (ssize_t) rows)
5550 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5551 cache_info->cache_filename);
5552 return(MagickFalse);
5554 if ((cache_info->debug != MagickFalse) &&
5555 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5556 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5557 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5558 nexus_info->region.width,(double) nexus_info->region.height,(double)
5559 nexus_info->region.x,(double) nexus_info->region.y);