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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479 % ClonePixelCacheRepository() clones the source pixel cache to the destination
482 % The format of the ClonePixelCacheRepository() method is:
484 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
485 % CacheInfo *source_info,ExceptionInfo *exception)
487 % A description of each parameter follows:
489 % o cache_info: the pixel cache.
491 % o source_info: the source pixel cache.
493 % o exception: return any errors or warnings in this structure.
497 static MagickBooleanType ClonePixelCacheOnDisk(
498 CacheInfo *magick_restrict cache_info,CacheInfo *magick_restrict clone_info)
516 Clone pixel cache on disk with identical morphology.
518 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
519 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
521 quantum=(size_t) MagickMaxBufferExtent;
522 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
523 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
524 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
525 if (buffer == (unsigned char *) NULL)
526 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
528 while ((count=read(cache_info->file,buffer,quantum)) > 0)
533 number_bytes=write(clone_info->file,buffer,(size_t) count);
534 if (number_bytes != count)
536 extent+=number_bytes;
538 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
539 if (extent != cache_info->length)
544 static MagickBooleanType ClonePixelCacheRepository(
545 CacheInfo *magick_restrict clone_info,CacheInfo *magick_restrict cache_info,
546 ExceptionInfo *exception)
548 #define MaxCacheThreads 2
549 #define cache_threads(source,destination) \
550 num_threads(((source)->type == DiskCache) || \
551 ((destination)->type == DiskCache) || (((source)->rows) < \
552 (16*GetMagickResourceLimit(ThreadResource))) ? 1 : \
553 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
554 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
561 **magick_restrict cache_nexus,
562 **magick_restrict clone_nexus;
570 assert(cache_info != (CacheInfo *) NULL);
571 assert(clone_info != (CacheInfo *) NULL);
572 assert(exception != (ExceptionInfo *) NULL);
573 if (cache_info->type == PingCache)
575 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
576 if ((cache_info->columns == clone_info->columns) &&
577 (cache_info->rows == clone_info->rows) &&
578 (cache_info->number_channels == clone_info->number_channels) &&
579 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
580 (cache_info->metacontent_extent == clone_info->metacontent_extent))
583 Identical pixel cache morphology.
585 if (((cache_info->type == MemoryCache) ||
586 (cache_info->type == MapCache)) &&
587 ((clone_info->type == MemoryCache) ||
588 (clone_info->type == MapCache)))
590 (void) memcpy(clone_info->pixels,cache_info->pixels,
591 cache_info->columns*cache_info->number_channels*cache_info->rows*
592 sizeof(*cache_info->pixels));
593 if ((cache_info->metacontent_extent != 0) &&
594 (clone_info->metacontent_extent != 0))
595 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
596 cache_info->columns*cache_info->rows*
597 clone_info->metacontent_extent*sizeof(unsigned char));
600 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
601 return(ClonePixelCacheOnDisk(cache_info,clone_info));
604 Mismatched pixel cache morphology.
606 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
607 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
608 if ((cache_nexus == (NexusInfo **) NULL) ||
609 (clone_nexus == (NexusInfo **) NULL))
610 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
611 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
612 optimize=(cache_info->number_channels == clone_info->number_channels) &&
613 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
614 MagickTrue : MagickFalse;
615 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
616 clone_info->columns*clone_info->number_channels);
618 #if defined(MAGICKCORE_OPENMP_SUPPORT)
619 #pragma omp parallel for schedule(static,4) shared(status) \
620 cache_threads(cache_info,clone_info)
622 for (y=0; y < (ssize_t) cache_info->rows; y++)
625 id = GetOpenMPThreadId();
636 if (status == MagickFalse)
638 if (y >= (ssize_t) clone_info->rows)
640 region.width=cache_info->columns;
644 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
645 cache_nexus[id],exception);
646 if (pixels == (Quantum *) NULL)
648 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
649 if (status == MagickFalse)
651 region.width=clone_info->columns;
652 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
653 clone_nexus[id],exception);
654 if (pixels == (Quantum *) NULL)
656 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
657 clone_nexus[id]->length);
658 if (optimize != MagickFalse)
659 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
663 register const Quantum
670 Mismatched pixel channel map.
672 p=cache_nexus[id]->pixels;
673 q=clone_nexus[id]->pixels;
674 for (x=0; x < (ssize_t) cache_info->columns; x++)
679 if (x == (ssize_t) clone_info->columns)
681 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
689 channel=clone_info->channel_map[i].channel;
690 traits=cache_info->channel_map[channel].traits;
691 if (traits != UndefinedPixelTrait)
692 *q=*(p+cache_info->channel_map[channel].offset);
695 p+=cache_info->number_channels;
698 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
700 if ((cache_info->metacontent_extent != 0) &&
701 (clone_info->metacontent_extent != 0))
706 length=(size_t) MagickMin(cache_info->metacontent_extent,
707 clone_info->metacontent_extent);
708 #if defined(MAGICKCORE_OPENMP_SUPPORT)
709 #pragma omp parallel for schedule(static,4) shared(status) \
710 cache_threads(cache_info,clone_info)
712 for (y=0; y < (ssize_t) cache_info->rows; y++)
715 id = GetOpenMPThreadId();
723 if (status == MagickFalse)
725 if (y >= (ssize_t) clone_info->rows)
727 region.width=cache_info->columns;
731 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
732 cache_nexus[id],exception);
733 if (pixels == (Quantum *) NULL)
735 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
736 if (status == MagickFalse)
738 region.width=clone_info->columns;
739 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
740 clone_nexus[id],exception);
741 if (pixels == (Quantum *) NULL)
743 if ((clone_nexus[id]->metacontent != (void *) NULL) &&
744 (cache_nexus[id]->metacontent != (void *) NULL))
745 (void) memcpy(clone_nexus[id]->metacontent,
746 cache_nexus[id]->metacontent,length*sizeof(unsigned char));
747 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
750 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
751 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
752 if (cache_info->debug != MagickFalse)
755 message[MagickPathExtent];
757 (void) FormatLocaleString(message,MagickPathExtent,"%s => %s",
758 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
759 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
760 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
770 + D e s t r o y I m a g e P i x e l C a c h e %
774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
778 % The format of the DestroyImagePixelCache() method is:
780 % void DestroyImagePixelCache(Image *image)
782 % A description of each parameter follows:
784 % o image: the image.
787 static void DestroyImagePixelCache(Image *image)
789 assert(image != (Image *) NULL);
790 assert(image->signature == MagickCoreSignature);
791 if (image->debug != MagickFalse)
792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
793 if (image->cache == (void *) NULL)
795 image->cache=DestroyPixelCache(image->cache);
799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
803 + D e s t r o y I m a g e P i x e l s %
807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
809 % DestroyImagePixels() deallocates memory associated with the pixel cache.
811 % The format of the DestroyImagePixels() method is:
813 % void DestroyImagePixels(Image *image)
815 % A description of each parameter follows:
817 % o image: the image.
820 MagickExport void DestroyImagePixels(Image *image)
823 *magick_restrict cache_info;
825 assert(image != (const Image *) NULL);
826 assert(image->signature == MagickCoreSignature);
827 if (image->debug != MagickFalse)
828 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
829 assert(image->cache != (Cache) NULL);
830 cache_info=(CacheInfo *) image->cache;
831 assert(cache_info->signature == MagickCoreSignature);
832 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
834 cache_info->methods.destroy_pixel_handler(image);
837 image->cache=DestroyPixelCache(image->cache);
841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
845 + D e s t r o y P i x e l C a c h e %
849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
851 % DestroyPixelCache() deallocates memory associated with the pixel cache.
853 % The format of the DestroyPixelCache() method is:
855 % Cache DestroyPixelCache(Cache cache)
857 % A description of each parameter follows:
859 % o cache: the pixel cache.
863 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
869 if (cache_info->file != -1)
871 status=close(cache_info->file);
872 cache_info->file=(-1);
873 RelinquishMagickResource(FileResource,1);
875 return(status == -1 ? MagickFalse : MagickTrue);
878 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
880 switch (cache_info->type)
884 #if defined(MAGICKCORE_OPENCL_SUPPORT)
885 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
887 cache_info->opencl=RelinquishMagickCLCacheInfo(cache_info->opencl,
889 cache_info->pixels=(Quantum *) NULL;
893 if (cache_info->mapped == MagickFalse)
894 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
897 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
898 RelinquishMagickResource(MemoryResource,cache_info->length);
903 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
904 cache_info->pixels=(Quantum *) NULL;
905 if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
906 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
907 *cache_info->cache_filename='\0';
908 RelinquishMagickResource(MapResource,cache_info->length);
912 if (cache_info->file != -1)
913 (void) ClosePixelCacheOnDisk(cache_info);
914 if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
915 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
916 *cache_info->cache_filename='\0';
917 RelinquishMagickResource(DiskResource,cache_info->length);
920 case DistributedCache:
922 *cache_info->cache_filename='\0';
923 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
924 cache_info->server_info);
930 cache_info->type=UndefinedCache;
931 cache_info->mapped=MagickFalse;
932 cache_info->metacontent=(void *) NULL;
935 MagickPrivate Cache DestroyPixelCache(Cache cache)
938 *magick_restrict cache_info;
940 assert(cache != (Cache) NULL);
941 cache_info=(CacheInfo *) cache;
942 assert(cache_info->signature == MagickCoreSignature);
943 if (cache_info->debug != MagickFalse)
944 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
945 cache_info->filename);
946 LockSemaphoreInfo(cache_info->semaphore);
947 cache_info->reference_count--;
948 if (cache_info->reference_count != 0)
950 UnlockSemaphoreInfo(cache_info->semaphore);
951 return((Cache) NULL);
953 UnlockSemaphoreInfo(cache_info->semaphore);
954 if (cache_info->debug != MagickFalse)
957 message[MagickPathExtent];
959 (void) FormatLocaleString(message,MagickPathExtent,"destroy %s",
960 cache_info->filename);
961 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
963 RelinquishPixelCachePixels(cache_info);
964 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
965 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
966 cache_info->server_info);
967 if (cache_info->nexus_info != (NexusInfo **) NULL)
968 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
969 cache_info->number_threads);
970 if (cache_info->random_info != (RandomInfo *) NULL)
971 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
972 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
973 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
974 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
975 RelinquishSemaphoreInfo(&cache_info->semaphore);
976 cache_info->signature=(~MagickCoreSignature);
977 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 + D e s t r o y P i x e l C a c h e N e x u s %
991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
995 % The format of the DestroyPixelCacheNexus() method is:
997 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
998 % const size_t number_threads)
1000 % A description of each parameter follows:
1002 % o nexus_info: the nexus to destroy.
1004 % o number_threads: the number of nexus threads.
1008 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1010 if (nexus_info->mapped == MagickFalse)
1011 (void) RelinquishAlignedMemory(nexus_info->cache);
1013 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1014 nexus_info->cache=(Quantum *) NULL;
1015 nexus_info->pixels=(Quantum *) NULL;
1016 nexus_info->metacontent=(void *) NULL;
1017 nexus_info->length=0;
1018 nexus_info->mapped=MagickFalse;
1021 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1022 const size_t number_threads)
1027 assert(nexus_info != (NexusInfo **) NULL);
1028 for (i=0; i < (ssize_t) number_threads; i++)
1030 if (nexus_info[i]->cache != (Quantum *) NULL)
1031 RelinquishCacheNexusPixels(nexus_info[i]);
1032 nexus_info[i]->signature=(~MagickCoreSignature);
1034 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1035 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 % G e t A u t h e n t i c M e t a c o n t e n t %
1048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1051 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1052 % returned if the associated pixels are not available.
1054 % The format of the GetAuthenticMetacontent() method is:
1056 % void *GetAuthenticMetacontent(const Image *image)
1058 % A description of each parameter follows:
1060 % o image: the image.
1063 MagickExport void *GetAuthenticMetacontent(const Image *image)
1066 *magick_restrict cache_info;
1069 id = GetOpenMPThreadId();
1071 assert(image != (const Image *) NULL);
1072 assert(image->signature == MagickCoreSignature);
1073 assert(image->cache != (Cache) NULL);
1074 cache_info=(CacheInfo *) image->cache;
1075 assert(cache_info->signature == MagickCoreSignature);
1076 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1077 (GetAuthenticMetacontentFromHandler) NULL)
1082 metacontent=cache_info->methods.
1083 get_authentic_metacontent_from_handler(image);
1084 return(metacontent);
1086 assert(id < (int) cache_info->number_threads);
1087 return(cache_info->nexus_info[id]->metacontent);
1091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1095 + 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 %
1099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1101 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1102 % with the last call to QueueAuthenticPixelsCache() or
1103 % GetAuthenticPixelsCache().
1105 % The format of the GetAuthenticMetacontentFromCache() method is:
1107 % void *GetAuthenticMetacontentFromCache(const Image *image)
1109 % A description of each parameter follows:
1111 % o image: the image.
1114 static void *GetAuthenticMetacontentFromCache(const Image *image)
1117 *magick_restrict cache_info;
1120 id = GetOpenMPThreadId();
1122 assert(image != (const Image *) NULL);
1123 assert(image->signature == MagickCoreSignature);
1124 assert(image->cache != (Cache) NULL);
1125 cache_info=(CacheInfo *) image->cache;
1126 assert(cache_info->signature == MagickCoreSignature);
1127 assert(id < (int) cache_info->number_threads);
1128 return(cache_info->nexus_info[id]->metacontent);
1131 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1137 + G e t A u t h e n t i c O p e n C L B u f f e r %
1141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1143 % GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1146 % The format of the GetAuthenticOpenCLBuffer() method is:
1148 % cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1149 % MagickCLDevice device,ExceptionInfo *exception)
1151 % A description of each parameter follows:
1153 % o image: the image.
1155 % o device: the device to use.
1157 % o exception: return any errors or warnings in this structure.
1160 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1161 MagickCLDevice device,ExceptionInfo *exception)
1164 *magick_restrict cache_info;
1169 assert(image != (const Image *) NULL);
1170 assert(device != (const MagickCLDevice) NULL);
1171 cache_info=(CacheInfo *) image->cache;
1172 if (cache_info->type == UndefinedCache)
1173 SyncImagePixelCache((Image *) image,exception);
1174 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1175 return((cl_mem) NULL);
1176 if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1177 (cache_info->opencl->device->context != device->context))
1178 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1179 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1181 assert(cache_info->pixels != (Quantum *) NULL);
1182 cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1183 cache_info->length);
1184 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1185 return((cl_mem) NULL);
1187 assert(cache_info->opencl->pixels == cache_info->pixels);
1188 return(cache_info->opencl->buffer);
1193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197 + 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 %
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1204 % disk pixel cache as defined by the geometry parameters. A pointer to the
1205 % pixels is returned if the pixels are transferred, otherwise a NULL is
1208 % The format of the GetAuthenticPixelCacheNexus() method is:
1210 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1211 % const ssize_t y,const size_t columns,const size_t rows,
1212 % NexusInfo *nexus_info,ExceptionInfo *exception)
1214 % A description of each parameter follows:
1216 % o image: the image.
1218 % o x,y,columns,rows: These values define the perimeter of a region of
1221 % o nexus_info: the cache nexus to return.
1223 % o exception: return any errors or warnings in this structure.
1227 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1228 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1229 ExceptionInfo *exception)
1232 *magick_restrict cache_info;
1235 *magick_restrict pixels;
1238 Transfer pixels from the cache.
1240 assert(image != (Image *) NULL);
1241 assert(image->signature == MagickCoreSignature);
1242 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1243 nexus_info,exception);
1244 if (pixels == (Quantum *) NULL)
1245 return((Quantum *) NULL);
1246 cache_info=(CacheInfo *) image->cache;
1247 assert(cache_info->signature == MagickCoreSignature);
1248 if (nexus_info->authentic_pixel_cache != MagickFalse)
1250 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1251 return((Quantum *) NULL);
1252 if (cache_info->metacontent_extent != 0)
1253 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1254 return((Quantum *) NULL);
1259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1263 + 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 %
1267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1269 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1270 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1272 % The format of the GetAuthenticPixelsFromCache() method is:
1274 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1276 % A description of each parameter follows:
1278 % o image: the image.
1281 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1284 *magick_restrict cache_info;
1287 id = GetOpenMPThreadId();
1289 assert(image != (const Image *) NULL);
1290 assert(image->signature == MagickCoreSignature);
1291 assert(image->cache != (Cache) NULL);
1292 cache_info=(CacheInfo *) image->cache;
1293 assert(cache_info->signature == MagickCoreSignature);
1294 assert(id < (int) cache_info->number_threads);
1295 return(cache_info->nexus_info[id]->pixels);
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % G e t A u t h e n t i c P i x e l Q u e u e %
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 % GetAuthenticPixelQueue() returns the authentic pixels associated
1310 % corresponding with the last call to QueueAuthenticPixels() or
1311 % GetAuthenticPixels().
1313 % The format of the GetAuthenticPixelQueue() method is:
1315 % Quantum *GetAuthenticPixelQueue(const Image image)
1317 % A description of each parameter follows:
1319 % o image: the image.
1322 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1325 *magick_restrict cache_info;
1328 id = GetOpenMPThreadId();
1330 assert(image != (const Image *) NULL);
1331 assert(image->signature == MagickCoreSignature);
1332 assert(image->cache != (Cache) NULL);
1333 cache_info=(CacheInfo *) image->cache;
1334 assert(cache_info->signature == MagickCoreSignature);
1335 if (cache_info->methods.get_authentic_pixels_from_handler !=
1336 (GetAuthenticPixelsFromHandler) NULL)
1337 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1338 assert(id < (int) cache_info->number_threads);
1339 return(cache_info->nexus_info[id]->pixels);
1343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347 % G e t A u t h e n t i c P i x e l s %
1351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1354 % region is successfully accessed, a pointer to a Quantum array
1355 % representing the region is returned, otherwise NULL is returned.
1357 % The returned pointer may point to a temporary working copy of the pixels
1358 % or it may point to the original pixels in memory. Performance is maximized
1359 % if the selected region is part of one row, or one or more full rows, since
1360 % then there is opportunity to access the pixels in-place (without a copy)
1361 % if the image is in memory, or in a memory-mapped file. The returned pointer
1362 % must *never* be deallocated by the user.
1364 % Pixels accessed via the returned pointer represent a simple array of type
1365 % Quantum. If the image has corresponding metacontent,call
1366 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1367 % meta-content corresponding to the region. Once the Quantum array has
1368 % been updated, the changes must be saved back to the underlying image using
1369 % SyncAuthenticPixels() or they may be lost.
1371 % The format of the GetAuthenticPixels() method is:
1373 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1374 % const ssize_t y,const size_t columns,const size_t rows,
1375 % ExceptionInfo *exception)
1377 % A description of each parameter follows:
1379 % o image: the image.
1381 % o x,y,columns,rows: These values define the perimeter of a region of
1384 % o exception: return any errors or warnings in this structure.
1387 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1388 const ssize_t y,const size_t columns,const size_t rows,
1389 ExceptionInfo *exception)
1392 *magick_restrict cache_info;
1395 id = GetOpenMPThreadId();
1400 assert(image != (Image *) NULL);
1401 assert(image->signature == MagickCoreSignature);
1402 assert(image->cache != (Cache) NULL);
1403 cache_info=(CacheInfo *) image->cache;
1404 assert(cache_info->signature == MagickCoreSignature);
1405 if (cache_info->methods.get_authentic_pixels_handler !=
1406 (GetAuthenticPixelsHandler) NULL)
1408 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1412 assert(id < (int) cache_info->number_threads);
1413 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1414 cache_info->nexus_info[id],exception);
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 + G e t A u t h e n t i c P i x e l s C a c h e %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1430 % as defined by the geometry parameters. A pointer to the pixels is returned
1431 % if the pixels are transferred, otherwise a NULL is returned.
1433 % The format of the GetAuthenticPixelsCache() method is:
1435 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1436 % const ssize_t y,const size_t columns,const size_t rows,
1437 % ExceptionInfo *exception)
1439 % A description of each parameter follows:
1441 % o image: the image.
1443 % o x,y,columns,rows: These values define the perimeter of a region of
1446 % o exception: return any errors or warnings in this structure.
1449 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1450 const ssize_t y,const size_t columns,const size_t rows,
1451 ExceptionInfo *exception)
1454 *magick_restrict cache_info;
1457 id = GetOpenMPThreadId();
1460 *magick_restrict pixels;
1462 assert(image != (const Image *) NULL);
1463 assert(image->signature == MagickCoreSignature);
1464 assert(image->cache != (Cache) NULL);
1465 cache_info=(CacheInfo *) image->cache;
1466 if (cache_info == (Cache) NULL)
1467 return((Quantum *) NULL);
1468 assert(cache_info->signature == MagickCoreSignature);
1469 assert(id < (int) cache_info->number_threads);
1470 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1471 cache_info->nexus_info[id],exception);
1476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480 + G e t I m a g e E x t e n t %
1484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1486 % GetImageExtent() returns the extent of the pixels associated corresponding
1487 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1489 % The format of the GetImageExtent() method is:
1491 % MagickSizeType GetImageExtent(const Image *image)
1493 % A description of each parameter follows:
1495 % o image: the image.
1498 MagickExport MagickSizeType GetImageExtent(const Image *image)
1501 *magick_restrict cache_info;
1504 id = GetOpenMPThreadId();
1506 assert(image != (Image *) NULL);
1507 assert(image->signature == MagickCoreSignature);
1508 if (image->debug != MagickFalse)
1509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1510 assert(image->cache != (Cache) NULL);
1511 cache_info=(CacheInfo *) image->cache;
1512 assert(cache_info->signature == MagickCoreSignature);
1513 assert(id < (int) cache_info->number_threads);
1514 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522 + G e t I m a g e P i x e l C a c h e %
1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 % GetImagePixelCache() ensures that there is only a single reference to the
1529 % pixel cache to be modified, updating the provided cache pointer to point to
1530 % a clone of the original pixel cache if necessary.
1532 % The format of the GetImagePixelCache method is:
1534 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1535 % ExceptionInfo *exception)
1537 % A description of each parameter follows:
1539 % o image: the image.
1541 % o clone: any value other than MagickFalse clones the cache pixels.
1543 % o exception: return any errors or warnings in this structure.
1547 static inline MagickBooleanType ValidatePixelCacheMorphology(
1548 const Image *magick_restrict image)
1551 *magick_restrict cache_info;
1553 const PixelChannelMap
1558 Does the image match the pixel cache morphology?
1560 cache_info=(CacheInfo *) image->cache;
1561 p=image->channel_map;
1562 q=cache_info->channel_map;
1563 if ((image->storage_class != cache_info->storage_class) ||
1564 (image->colorspace != cache_info->colorspace) ||
1565 (image->alpha_trait != cache_info->alpha_trait) ||
1566 (image->read_mask != cache_info->read_mask) ||
1567 (image->write_mask != cache_info->write_mask) ||
1568 (image->columns != cache_info->columns) ||
1569 (image->rows != cache_info->rows) ||
1570 (image->number_channels != cache_info->number_channels) ||
1571 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1572 (image->metacontent_extent != cache_info->metacontent_extent) ||
1573 (cache_info->nexus_info == (NexusInfo **) NULL))
1574 return(MagickFalse);
1578 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1579 ExceptionInfo *exception)
1582 *magick_restrict cache_info;
1588 static MagickSizeType
1589 cache_timelimit = MagickResourceInfinity,
1590 cpu_throttle = MagickResourceInfinity,
1594 if (cpu_throttle == MagickResourceInfinity)
1595 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1596 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1597 MagickDelay(cpu_throttle);
1598 if (cache_epoch == 0)
1601 Set the expire time in seconds.
1603 cache_timelimit=GetMagickResourceLimit(TimeResource);
1604 cache_epoch=time((time_t *) NULL);
1606 if ((cache_timelimit != MagickResourceInfinity) &&
1607 ((MagickSizeType) (time((time_t *) NULL)-cache_epoch) >= cache_timelimit))
1609 #if defined(ECANCELED)
1612 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1614 LockSemaphoreInfo(image->semaphore);
1615 assert(image->cache != (Cache) NULL);
1616 cache_info=(CacheInfo *) image->cache;
1617 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1618 CopyOpenCLBuffer(cache_info);
1620 destroy=MagickFalse;
1621 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1623 LockSemaphoreInfo(cache_info->semaphore);
1624 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1635 clone_image=(*image);
1636 clone_image.semaphore=AcquireSemaphoreInfo();
1637 clone_image.reference_count=1;
1638 clone_image.cache=ClonePixelCache(cache_info);
1639 clone_info=(CacheInfo *) clone_image.cache;
1640 status=OpenPixelCache(&clone_image,IOMode,exception);
1641 if (status != MagickFalse)
1643 if (clone != MagickFalse)
1644 status=ClonePixelCacheRepository(clone_info,cache_info,
1646 if (status != MagickFalse)
1648 if (cache_info->reference_count == 1)
1649 cache_info->nexus_info=(NexusInfo **) NULL;
1651 image->cache=clone_image.cache;
1654 RelinquishSemaphoreInfo(&clone_image.semaphore);
1656 UnlockSemaphoreInfo(cache_info->semaphore);
1658 if (destroy != MagickFalse)
1659 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1660 if (status != MagickFalse)
1663 Ensure the image matches the pixel cache morphology.
1665 image->type=UndefinedType;
1666 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1668 status=OpenPixelCache(image,IOMode,exception);
1669 cache_info=(CacheInfo *) image->cache;
1670 if (cache_info->type == DiskCache)
1671 (void) ClosePixelCacheOnDisk(cache_info);
1674 UnlockSemaphoreInfo(image->semaphore);
1675 if (status == MagickFalse)
1676 return((Cache) NULL);
1677 return(image->cache);
1681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685 + G e t I m a g e P i x e l C a c h e T y p e %
1689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1692 % DiskCache, MemoryCache, MapCache, or PingCache.
1694 % The format of the GetImagePixelCacheType() method is:
1696 % CacheType GetImagePixelCacheType(const Image *image)
1698 % A description of each parameter follows:
1700 % o image: the image.
1703 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1706 *magick_restrict cache_info;
1708 assert(image != (Image *) NULL);
1709 assert(image->signature == MagickCoreSignature);
1710 assert(image->cache != (Cache) NULL);
1711 cache_info=(CacheInfo *) image->cache;
1712 assert(cache_info->signature == MagickCoreSignature);
1713 return(cache_info->type);
1717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1721 % G e t O n e A u t h e n t i c P i x e l %
1725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1728 % location. The image background color is returned if an error occurs.
1730 % The format of the GetOneAuthenticPixel() method is:
1732 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1733 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1735 % A description of each parameter follows:
1737 % o image: the image.
1739 % o x,y: These values define the location of the pixel to return.
1741 % o pixel: return a pixel at the specified (x,y) location.
1743 % o exception: return any errors or warnings in this structure.
1747 static inline MagickBooleanType CopyPixel(const Image *image,
1748 const Quantum *source,Quantum *destination)
1753 if (source == (const Quantum *) NULL)
1755 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1756 destination[GreenPixelChannel]=ClampToQuantum(
1757 image->background_color.green);
1758 destination[BluePixelChannel]=ClampToQuantum(
1759 image->background_color.blue);
1760 destination[BlackPixelChannel]=ClampToQuantum(
1761 image->background_color.black);
1762 destination[AlphaPixelChannel]=ClampToQuantum(
1763 image->background_color.alpha);
1764 return(MagickFalse);
1766 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1768 PixelChannel channel=GetPixelChannelChannel(image,i);
1769 destination[channel]=source[i];
1774 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1775 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1778 *magick_restrict cache_info;
1783 assert(image != (Image *) NULL);
1784 assert(image->signature == MagickCoreSignature);
1785 assert(image->cache != (Cache) NULL);
1786 cache_info=(CacheInfo *) image->cache;
1787 assert(cache_info->signature == MagickCoreSignature);
1788 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1789 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1790 (GetOneAuthenticPixelFromHandler) NULL)
1791 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1793 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1794 return(CopyPixel(image,q,pixel));
1798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802 + 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 %
1806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1808 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1809 % location. The image background color is returned if an error occurs.
1811 % The format of the GetOneAuthenticPixelFromCache() method is:
1813 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1814 % const ssize_t x,const ssize_t y,Quantum *pixel,
1815 % ExceptionInfo *exception)
1817 % A description of each parameter follows:
1819 % o image: the image.
1821 % o x,y: These values define the location of the pixel to return.
1823 % o pixel: return a pixel at the specified (x,y) location.
1825 % o exception: return any errors or warnings in this structure.
1828 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1829 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1832 *magick_restrict cache_info;
1835 id = GetOpenMPThreadId();
1840 assert(image != (const Image *) NULL);
1841 assert(image->signature == MagickCoreSignature);
1842 assert(image->cache != (Cache) NULL);
1843 cache_info=(CacheInfo *) image->cache;
1844 assert(cache_info->signature == MagickCoreSignature);
1845 assert(id < (int) cache_info->number_threads);
1846 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1847 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1849 return(CopyPixel(image,q,pixel));
1853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1857 % G e t O n e V i r t u a l P i x e l %
1861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1864 % (x,y) location. The image background color is returned if an error occurs.
1865 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1867 % The format of the GetOneVirtualPixel() method is:
1869 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1870 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1872 % A description of each parameter follows:
1874 % o image: the image.
1876 % o x,y: These values define the location of the pixel to return.
1878 % o pixel: return a pixel at the specified (x,y) location.
1880 % o exception: return any errors or warnings in this structure.
1883 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1884 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1887 *magick_restrict cache_info;
1890 id = GetOpenMPThreadId();
1895 assert(image != (const Image *) NULL);
1896 assert(image->signature == MagickCoreSignature);
1897 assert(image->cache != (Cache) NULL);
1898 cache_info=(CacheInfo *) image->cache;
1899 assert(cache_info->signature == MagickCoreSignature);
1900 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1901 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1902 (GetOneVirtualPixelFromHandler) NULL)
1903 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1904 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1905 assert(id < (int) cache_info->number_threads);
1906 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1907 1UL,1UL,cache_info->nexus_info[id],exception);
1908 return(CopyPixel(image,p,pixel));
1912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1916 + 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 %
1920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1922 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1923 % specified (x,y) location. The image background color is returned if an
1926 % The format of the GetOneVirtualPixelFromCache() method is:
1928 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1929 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1930 % Quantum *pixel,ExceptionInfo *exception)
1932 % A description of each parameter follows:
1934 % o image: the image.
1936 % o virtual_pixel_method: the virtual pixel method.
1938 % o x,y: These values define the location of the pixel to return.
1940 % o pixel: return a pixel at the specified (x,y) location.
1942 % o exception: return any errors or warnings in this structure.
1945 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1946 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1947 Quantum *pixel,ExceptionInfo *exception)
1950 *magick_restrict cache_info;
1953 id = GetOpenMPThreadId();
1958 assert(image != (const Image *) NULL);
1959 assert(image->signature == MagickCoreSignature);
1960 assert(image->cache != (Cache) NULL);
1961 cache_info=(CacheInfo *) image->cache;
1962 assert(cache_info->signature == MagickCoreSignature);
1963 assert(id < (int) cache_info->number_threads);
1964 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1965 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1966 cache_info->nexus_info[id],exception);
1967 return(CopyPixel(image,p,pixel));
1971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975 % G e t O n e V i r t u a l P i x e l I n f o %
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1982 % location. The image background color is returned if an error occurs. If
1983 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1985 % The format of the GetOneVirtualPixelInfo() method is:
1987 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1988 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1989 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1991 % A description of each parameter follows:
1993 % o image: the image.
1995 % o virtual_pixel_method: the virtual pixel method.
1997 % o x,y: these values define the location of the pixel to return.
1999 % o pixel: return a pixel at the specified (x,y) location.
2001 % o exception: return any errors or warnings in this structure.
2004 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2005 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2006 PixelInfo *pixel,ExceptionInfo *exception)
2009 *magick_restrict cache_info;
2012 id = GetOpenMPThreadId();
2014 register const Quantum
2017 assert(image != (const Image *) NULL);
2018 assert(image->signature == MagickCoreSignature);
2019 assert(image->cache != (Cache) NULL);
2020 cache_info=(CacheInfo *) image->cache;
2021 assert(cache_info->signature == MagickCoreSignature);
2022 assert(id < (int) cache_info->number_threads);
2023 GetPixelInfo(image,pixel);
2024 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2025 cache_info->nexus_info[id],exception);
2026 if (p == (const Quantum *) NULL)
2027 return(MagickFalse);
2028 GetPixelInfoPixel(image,p,pixel);
2033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2037 + G e t P i x e l C a c h e C o l o r s p a c e %
2041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2045 % The format of the GetPixelCacheColorspace() method is:
2047 % Colorspace GetPixelCacheColorspace(Cache cache)
2049 % A description of each parameter follows:
2051 % o cache: the pixel cache.
2054 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2057 *magick_restrict cache_info;
2059 assert(cache != (Cache) NULL);
2060 cache_info=(CacheInfo *) cache;
2061 assert(cache_info->signature == MagickCoreSignature);
2062 if (cache_info->debug != MagickFalse)
2063 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2064 cache_info->filename);
2065 return(cache_info->colorspace);
2069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2073 + G e t P i x e l C a c h e F i l e n a m e %
2077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2079 % GetPixelCacheFilename() returns the filename associated with the pixel
2082 % The format of the GetPixelCacheFilename() method is:
2084 % const char *GetPixelCacheFilename(const Image *image)
2086 % A description of each parameter follows:
2088 % o image: the image.
2091 MagickExport const char *GetPixelCacheFilename(const Image *image)
2094 *magick_restrict cache_info;
2096 assert(image != (const Image *) NULL);
2097 assert(image->signature == MagickCoreSignature);
2098 assert(image->cache != (Cache) NULL);
2099 cache_info=(CacheInfo *) image->cache;
2100 assert(cache_info->signature == MagickCoreSignature);
2101 return(cache_info->cache_filename);
2105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2109 + G e t P i x e l C a c h e M e t h o d s %
2113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2115 % GetPixelCacheMethods() initializes the CacheMethods structure.
2117 % The format of the GetPixelCacheMethods() method is:
2119 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2121 % A description of each parameter follows:
2123 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2126 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2128 assert(cache_methods != (CacheMethods *) NULL);
2129 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2130 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2131 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2132 cache_methods->get_virtual_metacontent_from_handler=
2133 GetVirtualMetacontentFromCache;
2134 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2135 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2136 cache_methods->get_authentic_metacontent_from_handler=
2137 GetAuthenticMetacontentFromCache;
2138 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2139 cache_methods->get_one_authentic_pixel_from_handler=
2140 GetOneAuthenticPixelFromCache;
2141 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2142 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2143 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2151 + G e t P i x e l C a c h e N e x u s E x t e n t %
2155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2158 % corresponding with the last call to SetPixelCacheNexusPixels() or
2159 % GetPixelCacheNexusPixels().
2161 % The format of the GetPixelCacheNexusExtent() method is:
2163 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2164 % NexusInfo *nexus_info)
2166 % A description of each parameter follows:
2168 % o nexus_info: the nexus info.
2171 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2172 NexusInfo *magick_restrict nexus_info)
2175 *magick_restrict cache_info;
2180 assert(cache != NULL);
2181 cache_info=(CacheInfo *) cache;
2182 assert(cache_info->signature == MagickCoreSignature);
2183 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2185 return((MagickSizeType) cache_info->columns*cache_info->rows);
2190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2194 + G e t P i x e l C a c h e P i x e l s %
2198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2200 % GetPixelCachePixels() returns the pixels associated with the specified image.
2202 % The format of the GetPixelCachePixels() method is:
2204 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2205 % ExceptionInfo *exception)
2207 % A description of each parameter follows:
2209 % o image: the image.
2211 % o length: the pixel cache length.
2213 % o exception: return any errors or warnings in this structure.
2216 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2217 ExceptionInfo *exception)
2220 *magick_restrict cache_info;
2222 assert(image != (const Image *) NULL);
2223 assert(image->signature == MagickCoreSignature);
2224 assert(image->cache != (Cache) NULL);
2225 assert(length != (MagickSizeType *) NULL);
2226 assert(exception != (ExceptionInfo *) NULL);
2227 assert(exception->signature == MagickCoreSignature);
2228 cache_info=(CacheInfo *) image->cache;
2229 assert(cache_info->signature == MagickCoreSignature);
2230 *length=cache_info->length;
2231 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2232 return((void *) NULL);
2233 return((void *) cache_info->pixels);
2237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2241 + 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 %
2245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2249 % The format of the GetPixelCacheStorageClass() method is:
2251 % ClassType GetPixelCacheStorageClass(Cache cache)
2253 % A description of each parameter follows:
2255 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2257 % o cache: the pixel cache.
2260 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2263 *magick_restrict cache_info;
2265 assert(cache != (Cache) NULL);
2266 cache_info=(CacheInfo *) cache;
2267 assert(cache_info->signature == MagickCoreSignature);
2268 if (cache_info->debug != MagickFalse)
2269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2270 cache_info->filename);
2271 return(cache_info->storage_class);
2275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279 + G e t P i x e l C a c h e T i l e S i z e %
2283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285 % GetPixelCacheTileSize() returns the pixel cache tile size.
2287 % The format of the GetPixelCacheTileSize() method is:
2289 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2292 % A description of each parameter follows:
2294 % o image: the image.
2296 % o width: the optimize cache tile width in pixels.
2298 % o height: the optimize cache tile height in pixels.
2301 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2305 *magick_restrict cache_info;
2307 assert(image != (Image *) NULL);
2308 assert(image->signature == MagickCoreSignature);
2309 if (image->debug != MagickFalse)
2310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2311 cache_info=(CacheInfo *) image->cache;
2312 assert(cache_info->signature == MagickCoreSignature);
2313 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2314 if (GetImagePixelCacheType(image) == DiskCache)
2315 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2324 + 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 %
2328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2330 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2331 % pixel cache. A virtual pixel is any pixel access that is outside the
2332 % boundaries of the image cache.
2334 % The format of the GetPixelCacheVirtualMethod() method is:
2336 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2338 % A description of each parameter follows:
2340 % o image: the image.
2343 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2346 *magick_restrict cache_info;
2348 assert(image != (Image *) NULL);
2349 assert(image->signature == MagickCoreSignature);
2350 assert(image->cache != (Cache) NULL);
2351 cache_info=(CacheInfo *) image->cache;
2352 assert(cache_info->signature == MagickCoreSignature);
2353 return(cache_info->virtual_pixel_method);
2357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2361 + 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 %
2365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2368 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2370 % The format of the GetVirtualMetacontentFromCache() method is:
2372 % void *GetVirtualMetacontentFromCache(const Image *image)
2374 % A description of each parameter follows:
2376 % o image: the image.
2379 static const void *GetVirtualMetacontentFromCache(const Image *image)
2382 *magick_restrict cache_info;
2385 id = GetOpenMPThreadId();
2388 *magick_restrict metacontent;
2390 assert(image != (const Image *) NULL);
2391 assert(image->signature == MagickCoreSignature);
2392 assert(image->cache != (Cache) NULL);
2393 cache_info=(CacheInfo *) image->cache;
2394 assert(cache_info->signature == MagickCoreSignature);
2395 assert(id < (int) cache_info->number_threads);
2396 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2397 cache_info->nexus_info[id]);
2398 return(metacontent);
2402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2406 + 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 %
2410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2415 % The format of the GetVirtualMetacontentFromNexus() method is:
2417 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2418 % NexusInfo *nexus_info)
2420 % A description of each parameter follows:
2422 % o cache: the pixel cache.
2424 % o nexus_info: the cache nexus to return the meta-content.
2427 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2428 NexusInfo *magick_restrict nexus_info)
2431 *magick_restrict cache_info;
2433 assert(cache != (Cache) NULL);
2434 cache_info=(CacheInfo *) cache;
2435 assert(cache_info->signature == MagickCoreSignature);
2436 if (cache_info->storage_class == UndefinedClass)
2437 return((void *) NULL);
2438 return(nexus_info->metacontent);
2442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2446 % G e t V i r t u a l M e t a c o n t e n t %
2450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2452 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2453 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2454 % returned if the meta-content are not available.
2456 % The format of the GetVirtualMetacontent() method is:
2458 % const void *GetVirtualMetacontent(const Image *image)
2460 % A description of each parameter follows:
2462 % o image: the image.
2465 MagickExport const void *GetVirtualMetacontent(const Image *image)
2468 *magick_restrict cache_info;
2471 id = GetOpenMPThreadId();
2474 *magick_restrict metacontent;
2476 assert(image != (const Image *) NULL);
2477 assert(image->signature == MagickCoreSignature);
2478 assert(image->cache != (Cache) NULL);
2479 cache_info=(CacheInfo *) image->cache;
2480 assert(cache_info->signature == MagickCoreSignature);
2481 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2482 if (metacontent != (void *) NULL)
2483 return(metacontent);
2484 assert(id < (int) cache_info->number_threads);
2485 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2486 cache_info->nexus_info[id]);
2487 return(metacontent);
2491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2495 + 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 %
2499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2502 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2503 % is returned if the pixels are transferred, otherwise a NULL is returned.
2505 % The format of the GetVirtualPixelsFromNexus() method is:
2507 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2508 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2509 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2510 % ExceptionInfo *exception)
2512 % A description of each parameter follows:
2514 % o image: the image.
2516 % o virtual_pixel_method: the virtual pixel method.
2518 % o x,y,columns,rows: These values define the perimeter of a region of
2521 % o nexus_info: the cache nexus to acquire.
2523 % o exception: return any errors or warnings in this structure.
2530 0, 48, 12, 60, 3, 51, 15, 63,
2531 32, 16, 44, 28, 35, 19, 47, 31,
2532 8, 56, 4, 52, 11, 59, 7, 55,
2533 40, 24, 36, 20, 43, 27, 39, 23,
2534 2, 50, 14, 62, 1, 49, 13, 61,
2535 34, 18, 46, 30, 33, 17, 45, 29,
2536 10, 58, 6, 54, 9, 57, 5, 53,
2537 42, 26, 38, 22, 41, 25, 37, 21
2540 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2545 index=x+DitherMatrix[x & 0x07]-32L;
2548 if (index >= (ssize_t) columns)
2549 return((ssize_t) columns-1L);
2553 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2558 index=y+DitherMatrix[y & 0x07]-32L;
2561 if (index >= (ssize_t) rows)
2562 return((ssize_t) rows-1L);
2566 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2570 if (x >= (ssize_t) columns)
2571 return((ssize_t) (columns-1));
2575 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2579 if (y >= (ssize_t) rows)
2580 return((ssize_t) (rows-1));
2584 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2586 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2589 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2591 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2594 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2595 const size_t extent)
2601 Compute the remainder of dividing offset by extent. It returns not only
2602 the quotient (tile the offset falls in) but also the positive remainer
2603 within that tile such that 0 <= remainder < extent. This method is
2604 essentially a ldiv() using a floored modulo division rather than the
2605 normal default truncated modulo division.
2607 modulo.quotient=offset/(ssize_t) extent;
2610 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2614 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2615 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2616 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2617 ExceptionInfo *exception)
2620 *magick_restrict cache_info;
2630 **magick_restrict virtual_nexus;
2633 *magick_restrict pixels,
2634 virtual_pixel[MaxPixelChannels];
2639 register const Quantum
2652 register unsigned char
2659 *magick_restrict virtual_metacontent;
2664 assert(image != (const Image *) NULL);
2665 assert(image->signature == MagickCoreSignature);
2666 assert(image->cache != (Cache) NULL);
2667 cache_info=(CacheInfo *) image->cache;
2668 assert(cache_info->signature == MagickCoreSignature);
2669 if (cache_info->type == UndefinedCache)
2670 return((const Quantum *) NULL);
2671 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2672 CopyOpenCLBuffer(cache_info);
2676 region.width=columns;
2678 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2680 if (pixels == (Quantum *) NULL)
2681 return((const Quantum *) NULL);
2683 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2684 nexus_info->region.x;
2685 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2686 nexus_info->region.width-1L;
2687 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2688 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2689 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2690 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2696 Pixel request is inside cache extents.
2698 if (nexus_info->authentic_pixel_cache != MagickFalse)
2700 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2701 if (status == MagickFalse)
2702 return((const Quantum *) NULL);
2703 if (cache_info->metacontent_extent != 0)
2705 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2706 if (status == MagickFalse)
2707 return((const Quantum *) NULL);
2712 Pixel request is outside cache extents.
2714 s=(unsigned char *) nexus_info->metacontent;
2715 virtual_nexus=AcquirePixelCacheNexus(1);
2716 if (virtual_nexus == (NexusInfo **) NULL)
2718 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2719 "UnableToGetCacheNexus","`%s'",image->filename);
2720 return((const Quantum *) NULL);
2722 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2723 sizeof(*virtual_pixel));
2724 virtual_metacontent=(void *) NULL;
2725 switch (virtual_pixel_method)
2727 case BackgroundVirtualPixelMethod:
2728 case BlackVirtualPixelMethod:
2729 case GrayVirtualPixelMethod:
2730 case TransparentVirtualPixelMethod:
2731 case MaskVirtualPixelMethod:
2732 case WhiteVirtualPixelMethod:
2733 case EdgeVirtualPixelMethod:
2734 case CheckerTileVirtualPixelMethod:
2735 case HorizontalTileVirtualPixelMethod:
2736 case VerticalTileVirtualPixelMethod:
2738 if (cache_info->metacontent_extent != 0)
2741 Acquire a metacontent buffer.
2743 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2744 cache_info->metacontent_extent);
2745 if (virtual_metacontent == (void *) NULL)
2747 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2748 (void) ThrowMagickException(exception,GetMagickModule(),
2749 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2750 return((const Quantum *) NULL);
2752 (void) ResetMagickMemory(virtual_metacontent,0,
2753 cache_info->metacontent_extent);
2755 switch (virtual_pixel_method)
2757 case BlackVirtualPixelMethod:
2759 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2760 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2761 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2764 case GrayVirtualPixelMethod:
2766 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2767 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2769 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2772 case TransparentVirtualPixelMethod:
2774 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2775 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2776 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2779 case MaskVirtualPixelMethod:
2780 case WhiteVirtualPixelMethod:
2782 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2783 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2784 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2789 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2791 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2793 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2795 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2797 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2807 for (v=0; v < (ssize_t) rows; v++)
2813 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2814 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2815 y_offset=EdgeY(y_offset,cache_info->rows);
2816 for (u=0; u < (ssize_t) columns; u+=length)
2822 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2823 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2824 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2832 Transfer a single pixel.
2834 length=(MagickSizeType) 1;
2835 switch (virtual_pixel_method)
2837 case EdgeVirtualPixelMethod:
2840 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2841 EdgeX(x_offset,cache_info->columns),
2842 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2844 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2847 case RandomVirtualPixelMethod:
2849 if (cache_info->random_info == (RandomInfo *) NULL)
2850 cache_info->random_info=AcquireRandomInfo();
2851 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2852 RandomX(cache_info->random_info,cache_info->columns),
2853 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2854 *virtual_nexus,exception);
2855 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2858 case DitherVirtualPixelMethod:
2860 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2861 DitherX(x_offset,cache_info->columns),
2862 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2864 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2867 case TileVirtualPixelMethod:
2869 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2870 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2871 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2872 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2874 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2877 case MirrorVirtualPixelMethod:
2879 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2880 if ((x_modulo.quotient & 0x01) == 1L)
2881 x_modulo.remainder=(ssize_t) cache_info->columns-
2882 x_modulo.remainder-1L;
2883 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2884 if ((y_modulo.quotient & 0x01) == 1L)
2885 y_modulo.remainder=(ssize_t) cache_info->rows-
2886 y_modulo.remainder-1L;
2887 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2888 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2890 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2893 case HorizontalTileEdgeVirtualPixelMethod:
2895 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2896 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2897 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2898 *virtual_nexus,exception);
2899 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2902 case VerticalTileEdgeVirtualPixelMethod:
2904 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2905 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2906 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2907 *virtual_nexus,exception);
2908 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2911 case BackgroundVirtualPixelMethod:
2912 case BlackVirtualPixelMethod:
2913 case GrayVirtualPixelMethod:
2914 case TransparentVirtualPixelMethod:
2915 case MaskVirtualPixelMethod:
2916 case WhiteVirtualPixelMethod:
2919 r=virtual_metacontent;
2922 case CheckerTileVirtualPixelMethod:
2924 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2925 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2926 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2929 r=virtual_metacontent;
2932 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2933 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2935 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2938 case HorizontalTileVirtualPixelMethod:
2940 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2943 r=virtual_metacontent;
2946 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2947 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2948 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2949 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2951 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2954 case VerticalTileVirtualPixelMethod:
2956 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2959 r=virtual_metacontent;
2962 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2963 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2964 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2965 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2967 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2971 if (p == (const Quantum *) NULL)
2973 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2975 q+=cache_info->number_channels;
2976 if ((s != (void *) NULL) && (r != (const void *) NULL))
2978 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2979 s+=cache_info->metacontent_extent;
2984 Transfer a run of pixels.
2986 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2987 (size_t) length,1UL,*virtual_nexus,exception);
2988 if (p == (const Quantum *) NULL)
2990 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2991 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2992 q+=length*cache_info->number_channels;
2993 if ((r != (void *) NULL) && (s != (const void *) NULL))
2995 (void) memcpy(s,r,(size_t) length);
2996 s+=length*cache_info->metacontent_extent;
2999 if (u < (ssize_t) columns)
3005 if (virtual_metacontent != (void *) NULL)
3006 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3007 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3008 if (v < (ssize_t) rows)
3009 return((const Quantum *) NULL);
3014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3018 + G e t V i r t u a l P i x e l C a c h e %
3022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3024 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3025 % cache as defined by the geometry parameters. A pointer to the pixels
3026 % is returned if the pixels are transferred, otherwise a NULL is returned.
3028 % The format of the GetVirtualPixelCache() method is:
3030 % const Quantum *GetVirtualPixelCache(const Image *image,
3031 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3032 % const ssize_t y,const size_t columns,const size_t rows,
3033 % ExceptionInfo *exception)
3035 % A description of each parameter follows:
3037 % o image: the image.
3039 % o virtual_pixel_method: the virtual pixel method.
3041 % o x,y,columns,rows: These values define the perimeter of a region of
3044 % o exception: return any errors or warnings in this structure.
3047 static const Quantum *GetVirtualPixelCache(const Image *image,
3048 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3049 const size_t columns,const size_t rows,ExceptionInfo *exception)
3052 *magick_restrict cache_info;
3055 id = GetOpenMPThreadId();
3060 assert(image != (const Image *) NULL);
3061 assert(image->signature == MagickCoreSignature);
3062 assert(image->cache != (Cache) NULL);
3063 cache_info=(CacheInfo *) image->cache;
3064 assert(cache_info->signature == MagickCoreSignature);
3065 assert(id < (int) cache_info->number_threads);
3066 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3067 cache_info->nexus_info[id],exception);
3072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3076 % G e t V i r t u a l P i x e l Q u e u e %
3080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3082 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3083 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3085 % The format of the GetVirtualPixelQueue() method is:
3087 % const Quantum *GetVirtualPixelQueue(const Image image)
3089 % A description of each parameter follows:
3091 % o image: the image.
3094 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3097 *magick_restrict cache_info;
3100 id = GetOpenMPThreadId();
3102 assert(image != (const Image *) NULL);
3103 assert(image->signature == MagickCoreSignature);
3104 assert(image->cache != (Cache) NULL);
3105 cache_info=(CacheInfo *) image->cache;
3106 assert(cache_info->signature == MagickCoreSignature);
3107 if (cache_info->methods.get_virtual_pixels_handler !=
3108 (GetVirtualPixelsHandler) NULL)
3109 return(cache_info->methods.get_virtual_pixels_handler(image));
3110 assert(id < (int) cache_info->number_threads);
3111 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3119 % G e t V i r t u a l P i x e l s %
3123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3125 % GetVirtualPixels() returns an immutable pixel region. If the
3126 % region is successfully accessed, a pointer to it is returned, otherwise
3127 % NULL is returned. The returned pointer may point to a temporary working
3128 % copy of the pixels or it may point to the original pixels in memory.
3129 % Performance is maximized if the selected region is part of one row, or one
3130 % or more full rows, since there is opportunity to access the pixels in-place
3131 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3132 % returned pointer must *never* be deallocated by the user.
3134 % Pixels accessed via the returned pointer represent a simple array of type
3135 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3136 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3137 % access the meta-content (of type void) corresponding to the the
3140 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3142 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3143 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3144 % GetCacheViewAuthenticPixels() instead.
3146 % The format of the GetVirtualPixels() method is:
3148 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3149 % const ssize_t y,const size_t columns,const size_t rows,
3150 % ExceptionInfo *exception)
3152 % A description of each parameter follows:
3154 % o image: the image.
3156 % o x,y,columns,rows: These values define the perimeter of a region of
3159 % o exception: return any errors or warnings in this structure.
3162 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3163 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3164 ExceptionInfo *exception)
3167 *magick_restrict cache_info;
3170 id = GetOpenMPThreadId();
3175 assert(image != (const Image *) NULL);
3176 assert(image->signature == MagickCoreSignature);
3177 assert(image->cache != (Cache) NULL);
3178 cache_info=(CacheInfo *) image->cache;
3179 assert(cache_info->signature == MagickCoreSignature);
3180 if (cache_info->methods.get_virtual_pixel_handler !=
3181 (GetVirtualPixelHandler) NULL)
3182 return(cache_info->methods.get_virtual_pixel_handler(image,
3183 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3184 assert(id < (int) cache_info->number_threads);
3185 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3186 columns,rows,cache_info->nexus_info[id],exception);
3191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3195 + 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 %
3199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3201 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3202 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3204 % The format of the GetVirtualPixelsCache() method is:
3206 % Quantum *GetVirtualPixelsCache(const Image *image)
3208 % A description of each parameter follows:
3210 % o image: the image.
3213 static const Quantum *GetVirtualPixelsCache(const Image *image)
3216 *magick_restrict cache_info;
3219 id = GetOpenMPThreadId();
3221 assert(image != (const Image *) NULL);
3222 assert(image->signature == MagickCoreSignature);
3223 assert(image->cache != (Cache) NULL);
3224 cache_info=(CacheInfo *) image->cache;
3225 assert(cache_info->signature == MagickCoreSignature);
3226 assert(id < (int) cache_info->number_threads);
3227 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3235 + G e t V i r t u a l P i x e l s N e x u s %
3239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3241 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3244 % The format of the GetVirtualPixelsNexus() method is:
3246 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3247 % NexusInfo *nexus_info)
3249 % A description of each parameter follows:
3251 % o cache: the pixel cache.
3253 % o nexus_info: the cache nexus to return the colormap pixels.
3256 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3257 NexusInfo *magick_restrict nexus_info)
3260 *magick_restrict cache_info;
3262 assert(cache != (Cache) NULL);
3263 cache_info=(CacheInfo *) cache;
3264 assert(cache_info->signature == MagickCoreSignature);
3265 if (cache_info->storage_class == UndefinedClass)
3266 return((Quantum *) NULL);
3267 return((const Quantum *) nexus_info->pixels);
3271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3275 + O p e n P i x e l C a c h e %
3279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3281 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3282 % dimensions, allocating space for the image pixels and optionally the
3283 % metacontent, and memory mapping the cache if it is disk based. The cache
3284 % nexus array is initialized as well.
3286 % The format of the OpenPixelCache() method is:
3288 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3289 % ExceptionInfo *exception)
3291 % A description of each parameter follows:
3293 % o image: the image.
3295 % o mode: ReadMode, WriteMode, or IOMode.
3297 % o exception: return any errors or warnings in this structure.
3301 #if defined(__cplusplus) || defined(c_plusplus)
3306 static void CacheSignalHandler(int status)
3308 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3312 #if defined(__cplusplus) || defined(c_plusplus)
3316 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3323 Open pixel cache on disk.
3325 if ((cache_info->file != -1) && (cache_info->mode == mode))
3326 return(MagickTrue); /* cache already open and in the proper mode */
3327 if (*cache_info->cache_filename == '\0')
3328 file=AcquireUniqueFileResource(cache_info->cache_filename);
3334 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3339 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3340 O_BINARY | O_EXCL,S_MODE);
3342 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3348 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3351 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3356 return(MagickFalse);
3357 (void) AcquireMagickResource(FileResource,1);
3358 if (cache_info->file != -1)
3359 (void) ClosePixelCacheOnDisk(cache_info);
3360 cache_info->file=file;
3364 static inline MagickOffsetType WritePixelCacheRegion(
3365 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3366 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3368 register MagickOffsetType
3374 #if !defined(MAGICKCORE_HAVE_PWRITE)
3375 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3376 return((MagickOffsetType) -1);
3379 for (i=0; i < (MagickOffsetType) length; i+=count)
3381 #if !defined(MAGICKCORE_HAVE_PWRITE)
3382 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3385 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3386 SSIZE_MAX),(off_t) (offset+i));
3398 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3401 *magick_restrict cache_info;
3408 cache_info=(CacheInfo *) image->cache;
3409 if (image->debug != MagickFalse)
3412 format[MagickPathExtent],
3413 message[MagickPathExtent];
3415 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3416 (void) FormatLocaleString(message,MagickPathExtent,
3417 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3418 cache_info->cache_filename,cache_info->file,format);
3419 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3421 if (length != (MagickSizeType) ((MagickOffsetType) length))
3422 return(MagickFalse);
3423 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3425 return(MagickFalse);
3426 if ((MagickSizeType) offset >= length)
3427 count=(MagickOffsetType) 1;
3430 extent=(MagickOffsetType) length-1;
3431 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3434 return(MagickFalse);
3435 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3436 if (cache_info->synchronize != MagickFalse)
3437 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3440 (void) signal(SIGBUS,CacheSignalHandler);
3443 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3445 return(MagickFalse);
3449 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3450 ExceptionInfo *exception)
3453 *magick_restrict cache_info,
3457 format[MagickPathExtent],
3458 message[MagickPathExtent];
3474 assert(image != (const Image *) NULL);
3475 assert(image->signature == MagickCoreSignature);
3476 assert(image->cache != (Cache) NULL);
3477 if (image->debug != MagickFalse)
3478 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3479 if (cache_anonymous_memory < 0)
3485 Does the security policy require anonymous mapping for pixel cache?
3487 cache_anonymous_memory=0;
3488 value=GetPolicyValue("pixel-cache-memory");
3489 if (value == (char *) NULL)
3490 value=GetPolicyValue("cache:memory-map");
3491 if (LocaleCompare(value,"anonymous") == 0)
3493 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3494 cache_anonymous_memory=1;
3496 (void) ThrowMagickException(exception,GetMagickModule(),
3497 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3498 "'%s' (policy requires anonymous memory mapping)",image->filename);
3501 value=DestroyString(value);
3503 if ((image->columns == 0) || (image->rows == 0))
3504 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3505 cache_info=(CacheInfo *) image->cache;
3506 assert(cache_info->signature == MagickCoreSignature);
3507 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3508 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3509 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3511 source_info=(*cache_info);
3512 source_info.file=(-1);
3513 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3514 image->filename,(double) GetImageIndexInList(image));
3515 cache_info->storage_class=image->storage_class;
3516 cache_info->colorspace=image->colorspace;
3517 cache_info->alpha_trait=image->alpha_trait;
3518 cache_info->read_mask=image->read_mask;
3519 cache_info->write_mask=image->write_mask;
3520 cache_info->rows=image->rows;
3521 cache_info->columns=image->columns;
3522 InitializePixelChannelMap(image);
3523 cache_info->number_channels=GetPixelChannels(image);
3524 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3525 sizeof(*image->channel_map));
3526 cache_info->metacontent_extent=image->metacontent_extent;
3527 cache_info->mode=mode;
3528 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3529 packet_size=cache_info->number_channels*sizeof(Quantum);
3530 if (image->metacontent_extent != 0)
3531 packet_size+=cache_info->metacontent_extent;
3532 length=number_pixels*packet_size;
3533 columns=(size_t) (length/cache_info->rows/packet_size);
3534 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3535 ((ssize_t) cache_info->rows < 0))
3536 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3538 cache_info->length=length;
3539 if (image->ping != MagickFalse)
3541 cache_info->storage_class=image->storage_class;
3542 cache_info->colorspace=image->colorspace;
3543 cache_info->type=PingCache;
3546 status=AcquireMagickResource(AreaResource,cache_info->length);
3547 if (cache_info->mode == PersistMode)
3549 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3550 cache_info->metacontent_extent);
3551 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3553 status=AcquireMagickResource(MemoryResource,cache_info->length);
3554 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3555 (cache_info->type == MemoryCache))
3558 if (cache_anonymous_memory <= 0)
3560 cache_info->mapped=MagickFalse;
3561 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3562 AcquireAlignedMemory(1,(size_t) cache_info->length));
3566 cache_info->mapped=MagickTrue;
3567 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3568 cache_info->length);
3570 if (cache_info->pixels == (Quantum *) NULL)
3571 cache_info->pixels=source_info.pixels;
3575 Create memory pixel cache.
3577 cache_info->type=MemoryCache;
3578 cache_info->metacontent=(void *) NULL;
3579 if (cache_info->metacontent_extent != 0)
3580 cache_info->metacontent=(void *) (cache_info->pixels+
3581 number_pixels*cache_info->number_channels);
3582 if ((source_info.storage_class != UndefinedClass) &&
3585 status=ClonePixelCacheRepository(cache_info,&source_info,
3587 RelinquishPixelCachePixels(&source_info);
3589 if (image->debug != MagickFalse)
3591 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3592 MagickPathExtent,format);
3593 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3595 (void) FormatLocaleString(message,MagickPathExtent,
3596 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3597 cache_info->filename,cache_info->mapped != MagickFalse ?
3598 "Anonymous" : "Heap",type,(double) cache_info->columns,
3599 (double) cache_info->rows,(double)
3600 cache_info->number_channels,format);
3601 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3604 return(status == 0 ? MagickFalse : MagickTrue);
3607 RelinquishMagickResource(MemoryResource,cache_info->length);
3610 Create pixel cache on disk.
3612 status=AcquireMagickResource(DiskResource,cache_info->length);
3613 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3618 if (cache_info->type == DistributedCache)
3619 RelinquishMagickResource(DiskResource,cache_info->length);
3620 server_info=AcquireDistributeCacheInfo(exception);
3621 if (server_info != (DistributeCacheInfo *) NULL)
3623 status=OpenDistributePixelCache(server_info,image);
3624 if (status == MagickFalse)
3626 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3627 GetDistributeCacheHostname(server_info));
3628 server_info=DestroyDistributeCacheInfo(server_info);
3633 Create a distributed pixel cache.
3636 cache_info->type=DistributedCache;
3637 cache_info->server_info=server_info;
3638 (void) FormatLocaleString(cache_info->cache_filename,
3639 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3640 (DistributeCacheInfo *) cache_info->server_info),
3641 GetDistributeCachePort((DistributeCacheInfo *)
3642 cache_info->server_info));
3643 if ((source_info.storage_class != UndefinedClass) &&
3646 status=ClonePixelCacheRepository(cache_info,&source_info,
3648 RelinquishPixelCachePixels(&source_info);
3650 if (image->debug != MagickFalse)
3652 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3653 MagickPathExtent,format);
3654 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3656 (void) FormatLocaleString(message,MagickPathExtent,
3657 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3658 cache_info->filename,cache_info->cache_filename,
3659 GetDistributeCacheFile((DistributeCacheInfo *)
3660 cache_info->server_info),type,(double) cache_info->columns,
3661 (double) cache_info->rows,(double)
3662 cache_info->number_channels,format);
3663 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3666 return(status == 0 ? MagickFalse : MagickTrue);
3669 RelinquishMagickResource(DiskResource,cache_info->length);
3670 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3671 "CacheResourcesExhausted","`%s'",image->filename);
3672 return(MagickFalse);
3674 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
3675 (cache_info->mode != PersistMode))
3677 (void) ClosePixelCacheOnDisk(cache_info);
3678 *cache_info->cache_filename='\0';
3680 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3682 RelinquishMagickResource(DiskResource,cache_info->length);
3683 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3685 return(MagickFalse);
3687 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3688 cache_info->length);
3689 if (status == MagickFalse)
3691 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3693 return(MagickFalse);
3695 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3696 cache_info->metacontent_extent);
3697 if (length != (MagickSizeType) ((size_t) length))
3698 cache_info->type=DiskCache;
3701 status=AcquireMagickResource(MapResource,cache_info->length);
3702 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3703 (cache_info->type != MemoryCache))
3706 cache_info->type=DiskCache;
3711 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3712 cache_info->offset,(size_t) cache_info->length);
3713 if (cache_info->pixels == (Quantum *) NULL)
3715 cache_info->type=DiskCache;
3716 cache_info->pixels=source_info.pixels;
3721 Create file-backed memory-mapped pixel cache.
3723 (void) ClosePixelCacheOnDisk(cache_info);
3724 cache_info->type=MapCache;
3725 cache_info->mapped=MagickTrue;
3726 cache_info->metacontent=(void *) NULL;
3727 if (cache_info->metacontent_extent != 0)
3728 cache_info->metacontent=(void *) (cache_info->pixels+
3729 number_pixels*cache_info->number_channels);
3730 if ((source_info.storage_class != UndefinedClass) &&
3733 status=ClonePixelCacheRepository(cache_info,&source_info,
3735 RelinquishPixelCachePixels(&source_info);
3737 if (image->debug != MagickFalse)
3739 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3740 MagickPathExtent,format);
3741 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3743 (void) FormatLocaleString(message,MagickPathExtent,
3744 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3745 cache_info->filename,cache_info->cache_filename,
3746 cache_info->file,type,(double) cache_info->columns,(double)
3747 cache_info->rows,(double) cache_info->number_channels,
3749 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3752 return(status == 0 ? MagickFalse : MagickTrue);
3755 RelinquishMagickResource(MapResource,cache_info->length);
3758 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3760 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3761 RelinquishPixelCachePixels(&source_info);
3763 if (image->debug != MagickFalse)
3765 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3766 MagickPathExtent,format);
3767 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3769 (void) FormatLocaleString(message,MagickPathExtent,
3770 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3771 cache_info->cache_filename,cache_info->file,type,(double)
3772 cache_info->columns,(double) cache_info->rows,(double)
3773 cache_info->number_channels,format);
3774 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3776 return(status == 0 ? MagickFalse : MagickTrue);
3780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3784 + P e r s i s t P i x e l C a c h e %
3788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3790 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3791 % persistent pixel cache is one that resides on disk and is not destroyed
3792 % when the program exits.
3794 % The format of the PersistPixelCache() method is:
3796 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3797 % const MagickBooleanType attach,MagickOffsetType *offset,
3798 % ExceptionInfo *exception)
3800 % A description of each parameter follows:
3802 % o image: the image.
3804 % o filename: the persistent pixel cache filename.
3806 % o attach: A value other than zero initializes the persistent pixel cache.
3808 % o initialize: A value other than zero initializes the persistent pixel
3811 % o offset: the offset in the persistent cache to store pixels.
3813 % o exception: return any errors or warnings in this structure.
3816 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3817 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3818 ExceptionInfo *exception)
3821 *magick_restrict cache_info,
3822 *magick_restrict clone_info;
3833 assert(image != (Image *) NULL);
3834 assert(image->signature == MagickCoreSignature);
3835 if (image->debug != MagickFalse)
3836 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3837 assert(image->cache != (void *) NULL);
3838 assert(filename != (const char *) NULL);
3839 assert(offset != (MagickOffsetType *) NULL);
3840 page_size=GetMagickPageSize();
3841 cache_info=(CacheInfo *) image->cache;
3842 assert(cache_info->signature == MagickCoreSignature);
3843 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3844 CopyOpenCLBuffer(cache_info);
3846 if (attach != MagickFalse)
3849 Attach existing persistent pixel cache.
3851 if (image->debug != MagickFalse)
3852 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3853 "attach persistent cache");
3854 (void) CopyMagickString(cache_info->cache_filename,filename,
3856 cache_info->type=DiskCache;
3857 cache_info->offset=(*offset);
3858 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3859 return(MagickFalse);
3860 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3864 Clone persistent pixel cache.
3866 clone_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
3867 if (clone_image == (Image *) NULL)
3868 return(MagickFalse);
3869 clone_info=(CacheInfo *) clone_image->cache;
3870 (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
3871 clone_info->mode=PersistMode;
3872 clone_info->offset=(*offset);
3873 status=ClonePixelCacheRepository(clone_info,image->cache,exception);
3874 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3875 clone_image=DestroyImage(clone_image);
3880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3884 + 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 %
3888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3890 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3891 % defined by the region rectangle and returns a pointer to the region. This
3892 % region is subsequently transferred from the pixel cache with
3893 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3894 % pixels are transferred, otherwise a NULL is returned.
3896 % The format of the QueueAuthenticPixelCacheNexus() method is:
3898 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3899 % const ssize_t y,const size_t columns,const size_t rows,
3900 % const MagickBooleanType clone,NexusInfo *nexus_info,
3901 % ExceptionInfo *exception)
3903 % A description of each parameter follows:
3905 % o image: the image.
3907 % o x,y,columns,rows: These values define the perimeter of a region of
3910 % o nexus_info: the cache nexus to set.
3912 % o clone: clone the pixel cache.
3914 % o exception: return any errors or warnings in this structure.
3917 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3918 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3919 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3922 *magick_restrict cache_info;
3931 *magick_restrict pixels;
3937 Validate pixel cache geometry.
3939 assert(image != (const Image *) NULL);
3940 assert(image->signature == MagickCoreSignature);
3941 assert(image->cache != (Cache) NULL);
3942 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3943 if (cache_info == (Cache) NULL)
3944 return((Quantum *) NULL);
3945 assert(cache_info->signature == MagickCoreSignature);
3946 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3947 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3948 (y >= (ssize_t) cache_info->rows))
3950 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3951 "PixelsAreNotAuthentic","`%s'",image->filename);
3952 return((Quantum *) NULL);
3954 offset=(MagickOffsetType) y*cache_info->columns+x;
3956 return((Quantum *) NULL);
3957 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3958 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3959 if ((MagickSizeType) offset >= number_pixels)
3960 return((Quantum *) NULL);
3966 region.width=columns;
3968 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3978 + 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 %
3982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3984 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3985 % defined by the region rectangle and returns a pointer to the region. This
3986 % region is subsequently transferred from the pixel cache with
3987 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3988 % pixels are transferred, otherwise a NULL is returned.
3990 % The format of the QueueAuthenticPixelsCache() method is:
3992 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3993 % const ssize_t y,const size_t columns,const size_t rows,
3994 % ExceptionInfo *exception)
3996 % A description of each parameter follows:
3998 % o image: the image.
4000 % o x,y,columns,rows: These values define the perimeter of a region of
4003 % o exception: return any errors or warnings in this structure.
4006 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4007 const ssize_t y,const size_t columns,const size_t rows,
4008 ExceptionInfo *exception)
4011 *magick_restrict cache_info;
4014 id = GetOpenMPThreadId();
4017 *magick_restrict pixels;
4019 assert(image != (const Image *) NULL);
4020 assert(image->signature == MagickCoreSignature);
4021 assert(image->cache != (Cache) NULL);
4022 cache_info=(CacheInfo *) image->cache;
4023 assert(cache_info->signature == MagickCoreSignature);
4024 assert(id < (int) cache_info->number_threads);
4025 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4026 cache_info->nexus_info[id],exception);
4031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4035 % Q u e u e A u t h e n t i c P i x e l s %
4039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4041 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4042 % successfully initialized a pointer to a Quantum array representing the
4043 % region is returned, otherwise NULL is returned. The returned pointer may
4044 % point to a temporary working buffer for the pixels or it may point to the
4045 % final location of the pixels in memory.
4047 % Write-only access means that any existing pixel values corresponding to
4048 % the region are ignored. This is useful if the initial image is being
4049 % created from scratch, or if the existing pixel values are to be
4050 % completely replaced without need to refer to their pre-existing values.
4051 % The application is free to read and write the pixel buffer returned by
4052 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4053 % initialize the pixel array values. Initializing pixel array values is the
4054 % application's responsibility.
4056 % Performance is maximized if the selected region is part of one row, or
4057 % one or more full rows, since then there is opportunity to access the
4058 % pixels in-place (without a copy) if the image is in memory, or in a
4059 % memory-mapped file. The returned pointer must *never* be deallocated
4062 % Pixels accessed via the returned pointer represent a simple array of type
4063 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4064 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4065 % obtain the meta-content (of type void) corresponding to the region.
4066 % Once the Quantum (and/or Quantum) array has been updated, the
4067 % changes must be saved back to the underlying image using
4068 % SyncAuthenticPixels() or they may be lost.
4070 % The format of the QueueAuthenticPixels() method is:
4072 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4073 % const ssize_t y,const size_t columns,const size_t rows,
4074 % ExceptionInfo *exception)
4076 % A description of each parameter follows:
4078 % o image: the image.
4080 % o x,y,columns,rows: These values define the perimeter of a region of
4083 % o exception: return any errors or warnings in this structure.
4086 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4087 const ssize_t y,const size_t columns,const size_t rows,
4088 ExceptionInfo *exception)
4091 *magick_restrict cache_info;
4094 id = GetOpenMPThreadId();
4097 *magick_restrict pixels;
4099 assert(image != (Image *) NULL);
4100 assert(image->signature == MagickCoreSignature);
4101 assert(image->cache != (Cache) NULL);
4102 cache_info=(CacheInfo *) image->cache;
4103 assert(cache_info->signature == MagickCoreSignature);
4104 if (cache_info->methods.queue_authentic_pixels_handler !=
4105 (QueueAuthenticPixelsHandler) NULL)
4107 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4108 columns,rows,exception);
4111 assert(id < (int) cache_info->number_threads);
4112 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4113 cache_info->nexus_info[id],exception);
4118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4122 + 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 %
4126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4128 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4131 % The format of the ReadPixelCacheMetacontent() method is:
4133 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4134 % NexusInfo *nexus_info,ExceptionInfo *exception)
4136 % A description of each parameter follows:
4138 % o cache_info: the pixel cache.
4140 % o nexus_info: the cache nexus to read the metacontent.
4142 % o exception: return any errors or warnings in this structure.
4146 static inline MagickOffsetType ReadPixelCacheRegion(
4147 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4148 const MagickSizeType length,unsigned char *magick_restrict buffer)
4150 register MagickOffsetType
4156 #if !defined(MAGICKCORE_HAVE_PREAD)
4157 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4158 return((MagickOffsetType) -1);
4161 for (i=0; i < (MagickOffsetType) length; i+=count)
4163 #if !defined(MAGICKCORE_HAVE_PREAD)
4164 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4167 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4168 SSIZE_MAX),(off_t) (offset+i));
4180 static MagickBooleanType ReadPixelCacheMetacontent(
4181 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4182 ExceptionInfo *exception)
4195 register unsigned char
4201 if (cache_info->metacontent_extent == 0)
4202 return(MagickFalse);
4203 if (nexus_info->authentic_pixel_cache != MagickFalse)
4205 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4206 nexus_info->region.x;
4207 length=(MagickSizeType) nexus_info->region.width*
4208 cache_info->metacontent_extent;
4209 extent=length*nexus_info->region.height;
4210 rows=nexus_info->region.height;
4212 q=(unsigned char *) nexus_info->metacontent;
4213 switch (cache_info->type)
4218 register unsigned char
4222 Read meta-content from memory.
4224 if ((cache_info->columns == nexus_info->region.width) &&
4225 (extent == (MagickSizeType) ((size_t) extent)))
4230 p=(unsigned char *) cache_info->metacontent+offset*
4231 cache_info->metacontent_extent;
4232 for (y=0; y < (ssize_t) rows; y++)
4234 (void) memcpy(q,p,(size_t) length);
4235 p+=cache_info->metacontent_extent*cache_info->columns;
4236 q+=cache_info->metacontent_extent*nexus_info->region.width;
4243 Read meta content from disk.
4245 LockSemaphoreInfo(cache_info->file_semaphore);
4246 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4248 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4249 cache_info->cache_filename);
4250 UnlockSemaphoreInfo(cache_info->file_semaphore);
4251 return(MagickFalse);
4253 if ((cache_info->columns == nexus_info->region.width) &&
4254 (extent <= MagickMaxBufferExtent))
4259 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4260 for (y=0; y < (ssize_t) rows; y++)
4262 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4263 cache_info->number_channels*sizeof(Quantum)+offset*
4264 cache_info->metacontent_extent,length,(unsigned char *) q);
4265 if (count != (MagickOffsetType) length)
4267 offset+=cache_info->columns;
4268 q+=cache_info->metacontent_extent*nexus_info->region.width;
4270 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4271 (void) ClosePixelCacheOnDisk(cache_info);
4272 UnlockSemaphoreInfo(cache_info->file_semaphore);
4275 case DistributedCache:
4281 Read metacontent from distributed cache.
4283 LockSemaphoreInfo(cache_info->file_semaphore);
4284 region=nexus_info->region;
4285 if ((cache_info->columns != nexus_info->region.width) ||
4286 (extent > MagickMaxBufferExtent))
4293 for (y=0; y < (ssize_t) rows; y++)
4295 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4296 cache_info->server_info,®ion,length,(unsigned char *) q);
4297 if (count != (MagickOffsetType) length)
4299 q+=cache_info->metacontent_extent*nexus_info->region.width;
4302 UnlockSemaphoreInfo(cache_info->file_semaphore);
4308 if (y < (ssize_t) rows)
4310 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4311 cache_info->cache_filename);
4312 return(MagickFalse);
4314 if ((cache_info->debug != MagickFalse) &&
4315 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4316 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4317 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4318 nexus_info->region.width,(double) nexus_info->region.height,(double)
4319 nexus_info->region.x,(double) nexus_info->region.y);
4324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4328 + R e a d P i x e l C a c h e P i x e l s %
4332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4334 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4337 % The format of the ReadPixelCachePixels() method is:
4339 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4340 % NexusInfo *nexus_info,ExceptionInfo *exception)
4342 % A description of each parameter follows:
4344 % o cache_info: the pixel cache.
4346 % o nexus_info: the cache nexus to read the pixels.
4348 % o exception: return any errors or warnings in this structure.
4351 static MagickBooleanType ReadPixelCachePixels(
4352 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4353 ExceptionInfo *exception)
4373 if (nexus_info->authentic_pixel_cache != MagickFalse)
4375 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4376 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4377 return(MagickFalse);
4378 offset+=nexus_info->region.x;
4379 number_channels=cache_info->number_channels;
4380 length=(MagickSizeType) number_channels*nexus_info->region.width*
4382 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4383 return(MagickFalse);
4384 rows=nexus_info->region.height;
4386 if ((extent == 0) || ((extent/length) != rows))
4387 return(MagickFalse);
4389 q=nexus_info->pixels;
4390 switch (cache_info->type)
4399 Read pixels from memory.
4401 if ((cache_info->columns == nexus_info->region.width) &&
4402 (extent == (MagickSizeType) ((size_t) extent)))
4407 p=cache_info->pixels+offset*cache_info->number_channels;
4408 for (y=0; y < (ssize_t) rows; y++)
4410 (void) memcpy(q,p,(size_t) length);
4411 p+=cache_info->number_channels*cache_info->columns;
4412 q+=cache_info->number_channels*nexus_info->region.width;
4419 Read pixels from disk.
4421 LockSemaphoreInfo(cache_info->file_semaphore);
4422 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4424 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4425 cache_info->cache_filename);
4426 UnlockSemaphoreInfo(cache_info->file_semaphore);
4427 return(MagickFalse);
4429 if ((cache_info->columns == nexus_info->region.width) &&
4430 (extent <= MagickMaxBufferExtent))
4435 for (y=0; y < (ssize_t) rows; y++)
4437 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4438 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4439 if (count != (MagickOffsetType) length)
4441 offset+=cache_info->columns;
4442 q+=cache_info->number_channels*nexus_info->region.width;
4444 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4445 (void) ClosePixelCacheOnDisk(cache_info);
4446 UnlockSemaphoreInfo(cache_info->file_semaphore);
4449 case DistributedCache:
4455 Read pixels from distributed cache.
4457 LockSemaphoreInfo(cache_info->file_semaphore);
4458 region=nexus_info->region;
4459 if ((cache_info->columns != nexus_info->region.width) ||
4460 (extent > MagickMaxBufferExtent))
4467 for (y=0; y < (ssize_t) rows; y++)
4469 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4470 cache_info->server_info,®ion,length,(unsigned char *) q);
4471 if (count != (MagickOffsetType) length)
4473 q+=cache_info->number_channels*nexus_info->region.width;
4476 UnlockSemaphoreInfo(cache_info->file_semaphore);
4482 if (y < (ssize_t) rows)
4484 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4485 cache_info->cache_filename);
4486 return(MagickFalse);
4488 if ((cache_info->debug != MagickFalse) &&
4489 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4490 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4491 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4492 nexus_info->region.width,(double) nexus_info->region.height,(double)
4493 nexus_info->region.x,(double) nexus_info->region.y);
4498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4502 + R e f e r e n c e P i x e l C a c h e %
4506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4508 % ReferencePixelCache() increments the reference count associated with the
4509 % pixel cache returning a pointer to the cache.
4511 % The format of the ReferencePixelCache method is:
4513 % Cache ReferencePixelCache(Cache cache_info)
4515 % A description of each parameter follows:
4517 % o cache_info: the pixel cache.
4520 MagickPrivate Cache ReferencePixelCache(Cache cache)
4523 *magick_restrict cache_info;
4525 assert(cache != (Cache *) NULL);
4526 cache_info=(CacheInfo *) cache;
4527 assert(cache_info->signature == MagickCoreSignature);
4528 LockSemaphoreInfo(cache_info->semaphore);
4529 cache_info->reference_count++;
4530 UnlockSemaphoreInfo(cache_info->semaphore);
4535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4539 + R e s e t P i x e l C a c h e C h a n n e l s %
4543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4545 % ResetPixelCacheChannels() resets the pixel cache channels.
4547 % The format of the ResetPixelCacheChannels method is:
4549 % void ResetPixelCacheChannels(Image *)
4551 % A description of each parameter follows:
4553 % o image: the image.
4556 MagickPrivate void ResetPixelCacheChannels(Image *image)
4559 *magick_restrict cache_info;
4561 assert(image != (const Image *) NULL);
4562 assert(image->signature == MagickCoreSignature);
4563 assert(image->cache != (Cache) NULL);
4564 cache_info=(CacheInfo *) image->cache;
4565 assert(cache_info->signature == MagickCoreSignature);
4566 cache_info->number_channels=GetPixelChannels(image);
4570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4574 + R e s e t P i x e l C a c h e E p o c h %
4578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4580 % ResetPixelCacheEpoch() resets the pixel cache epoch.
4582 % The format of the ResetPixelCacheEpoch method is:
4584 % void ResetPixelCacheEpoch(void)
4587 MagickPrivate void ResetPixelCacheEpoch(void)
4593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4597 + S e t P i x e l C a c h e M e t h o d s %
4601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4603 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4605 % The format of the SetPixelCacheMethods() method is:
4607 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4609 % A description of each parameter follows:
4611 % o cache: the pixel cache.
4613 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4616 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4619 *magick_restrict cache_info;
4621 GetOneAuthenticPixelFromHandler
4622 get_one_authentic_pixel_from_handler;
4624 GetOneVirtualPixelFromHandler
4625 get_one_virtual_pixel_from_handler;
4628 Set cache pixel methods.
4630 assert(cache != (Cache) NULL);
4631 assert(cache_methods != (CacheMethods *) NULL);
4632 cache_info=(CacheInfo *) cache;
4633 assert(cache_info->signature == MagickCoreSignature);
4634 if (cache_info->debug != MagickFalse)
4635 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4636 cache_info->filename);
4637 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4638 cache_info->methods.get_virtual_pixel_handler=
4639 cache_methods->get_virtual_pixel_handler;
4640 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4641 cache_info->methods.destroy_pixel_handler=
4642 cache_methods->destroy_pixel_handler;
4643 if (cache_methods->get_virtual_metacontent_from_handler !=
4644 (GetVirtualMetacontentFromHandler) NULL)
4645 cache_info->methods.get_virtual_metacontent_from_handler=
4646 cache_methods->get_virtual_metacontent_from_handler;
4647 if (cache_methods->get_authentic_pixels_handler !=
4648 (GetAuthenticPixelsHandler) NULL)
4649 cache_info->methods.get_authentic_pixels_handler=
4650 cache_methods->get_authentic_pixels_handler;
4651 if (cache_methods->queue_authentic_pixels_handler !=
4652 (QueueAuthenticPixelsHandler) NULL)
4653 cache_info->methods.queue_authentic_pixels_handler=
4654 cache_methods->queue_authentic_pixels_handler;
4655 if (cache_methods->sync_authentic_pixels_handler !=
4656 (SyncAuthenticPixelsHandler) NULL)
4657 cache_info->methods.sync_authentic_pixels_handler=
4658 cache_methods->sync_authentic_pixels_handler;
4659 if (cache_methods->get_authentic_pixels_from_handler !=
4660 (GetAuthenticPixelsFromHandler) NULL)
4661 cache_info->methods.get_authentic_pixels_from_handler=
4662 cache_methods->get_authentic_pixels_from_handler;
4663 if (cache_methods->get_authentic_metacontent_from_handler !=
4664 (GetAuthenticMetacontentFromHandler) NULL)
4665 cache_info->methods.get_authentic_metacontent_from_handler=
4666 cache_methods->get_authentic_metacontent_from_handler;
4667 get_one_virtual_pixel_from_handler=
4668 cache_info->methods.get_one_virtual_pixel_from_handler;
4669 if (get_one_virtual_pixel_from_handler !=
4670 (GetOneVirtualPixelFromHandler) NULL)
4671 cache_info->methods.get_one_virtual_pixel_from_handler=
4672 cache_methods->get_one_virtual_pixel_from_handler;
4673 get_one_authentic_pixel_from_handler=
4674 cache_methods->get_one_authentic_pixel_from_handler;
4675 if (get_one_authentic_pixel_from_handler !=
4676 (GetOneAuthenticPixelFromHandler) NULL)
4677 cache_info->methods.get_one_authentic_pixel_from_handler=
4678 cache_methods->get_one_authentic_pixel_from_handler;
4682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4686 + S e t P i x e l C a c h e N e x u s P i x e l s %
4690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4692 % SetPixelCacheNexusPixels() defines the region of the cache for the
4693 % specified cache nexus.
4695 % The format of the SetPixelCacheNexusPixels() method is:
4697 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4698 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4699 % ExceptionInfo *exception)
4701 % A description of each parameter follows:
4703 % o cache_info: the pixel cache.
4705 % o mode: ReadMode, WriteMode, or IOMode.
4707 % o region: A pointer to the RectangleInfo structure that defines the
4708 % region of this particular cache nexus.
4710 % o nexus_info: the cache nexus to set.
4712 % o exception: return any errors or warnings in this structure.
4716 static inline MagickBooleanType AcquireCacheNexusPixels(
4717 const CacheInfo *magick_restrict cache_info,NexusInfo *nexus_info,
4718 ExceptionInfo *exception)
4720 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4721 return(MagickFalse);
4722 if (cache_anonymous_memory <= 0)
4724 nexus_info->mapped=MagickFalse;
4725 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4726 (size_t) nexus_info->length));
4727 if (nexus_info->cache != (Quantum *) NULL)
4728 (void) ResetMagickMemory(nexus_info->cache,0,(size_t)
4729 nexus_info->length);
4733 nexus_info->mapped=MagickTrue;
4734 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4735 nexus_info->length);
4737 if (nexus_info->cache == (Quantum *) NULL)
4739 (void) ThrowMagickException(exception,GetMagickModule(),
4740 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4741 cache_info->filename);
4742 return(MagickFalse);
4747 static inline MagickBooleanType IsPixelCacheAuthentic(
4748 const CacheInfo *magick_restrict cache_info,
4749 const NexusInfo *magick_restrict nexus_info)
4758 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4760 if (cache_info->type == PingCache)
4762 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4763 nexus_info->region.x;
4764 status=nexus_info->pixels == (cache_info->pixels+offset*
4765 cache_info->number_channels) ? MagickTrue : MagickFalse;
4769 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4772 if (mode == ReadMode)
4774 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4777 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4780 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4781 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4782 ExceptionInfo *exception)
4791 assert(cache_info != (const CacheInfo *) NULL);
4792 assert(cache_info->signature == MagickCoreSignature);
4793 if (cache_info->type == UndefinedCache)
4794 return((Quantum *) NULL);
4795 nexus_info->region=(*region);
4796 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4802 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4803 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4804 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4805 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4806 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4807 ((nexus_info->region.width == cache_info->columns) ||
4808 ((nexus_info->region.width % cache_info->columns) == 0)))))
4814 Pixels are accessed directly from memory.
4816 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4817 nexus_info->region.x;
4818 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4820 nexus_info->metacontent=(void *) NULL;
4821 if (cache_info->metacontent_extent != 0)
4822 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4823 offset*cache_info->metacontent_extent;
4824 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4825 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4827 return(nexus_info->pixels);
4831 Pixels are stored in a staging region until they are synced to the cache.
4833 number_pixels=(MagickSizeType) nexus_info->region.width*
4834 nexus_info->region.height;
4835 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4836 if (cache_info->metacontent_extent != 0)
4837 length+=number_pixels*cache_info->metacontent_extent;
4838 if (nexus_info->cache == (Quantum *) NULL)
4840 nexus_info->length=length;
4841 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4842 if (status == MagickFalse)
4844 nexus_info->length=0;
4845 return((Quantum *) NULL);
4849 if (nexus_info->length < length)
4851 RelinquishCacheNexusPixels(nexus_info);
4852 nexus_info->length=length;
4853 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4854 if (status == MagickFalse)
4856 nexus_info->length=0;
4857 return((Quantum *) NULL);
4860 nexus_info->pixels=nexus_info->cache;
4861 nexus_info->metacontent=(void *) NULL;
4862 if (cache_info->metacontent_extent != 0)
4863 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4864 cache_info->number_channels);
4865 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4866 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4868 return(nexus_info->pixels);
4872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4876 % 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 %
4880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4882 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4883 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4884 % access that is outside the boundaries of the image cache.
4886 % The format of the SetPixelCacheVirtualMethod() method is:
4888 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4889 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4891 % A description of each parameter follows:
4893 % o image: the image.
4895 % o virtual_pixel_method: choose the type of virtual pixel.
4897 % o exception: return any errors or warnings in this structure.
4901 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4902 ExceptionInfo *exception)
4905 *magick_restrict cache_info;
4908 *magick_restrict image_view;
4916 assert(image != (Image *) NULL);
4917 assert(image->signature == MagickCoreSignature);
4918 if (image->debug != MagickFalse)
4919 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4920 assert(image->cache != (Cache) NULL);
4921 cache_info=(CacheInfo *) image->cache;
4922 assert(cache_info->signature == MagickCoreSignature);
4923 image->alpha_trait=BlendPixelTrait;
4925 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4926 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4927 #pragma omp parallel for schedule(static,4) shared(status) \
4928 magick_threads(image,image,1,1)
4930 for (y=0; y < (ssize_t) image->rows; y++)
4938 if (status == MagickFalse)
4940 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4941 if (q == (Quantum *) NULL)
4946 for (x=0; x < (ssize_t) image->columns; x++)
4948 SetPixelAlpha(image,alpha,q);
4949 q+=GetPixelChannels(image);
4951 status=SyncCacheViewAuthenticPixels(image_view,exception);
4953 image_view=DestroyCacheView(image_view);
4957 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4958 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4961 *magick_restrict cache_info;
4966 assert(image != (Image *) NULL);
4967 assert(image->signature == MagickCoreSignature);
4968 if (image->debug != MagickFalse)
4969 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4970 assert(image->cache != (Cache) NULL);
4971 cache_info=(CacheInfo *) image->cache;
4972 assert(cache_info->signature == MagickCoreSignature);
4973 method=cache_info->virtual_pixel_method;
4974 cache_info->virtual_pixel_method=virtual_pixel_method;
4975 if ((image->columns != 0) && (image->rows != 0))
4976 switch (virtual_pixel_method)
4978 case BackgroundVirtualPixelMethod:
4980 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4981 (image->alpha_trait == UndefinedPixelTrait))
4982 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4983 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4984 (IsGrayColorspace(image->colorspace) != MagickFalse))
4985 (void) SetImageColorspace(image,sRGBColorspace,exception);
4988 case TransparentVirtualPixelMethod:
4990 if (image->alpha_trait == UndefinedPixelTrait)
4991 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5000 #if defined(MAGICKCORE_OPENCL_SUPPORT)
5002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5006 + 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 %
5010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5012 % SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5013 % been completed and updates the host memory.
5015 % The format of the SyncAuthenticOpenCLBuffer() method is:
5017 % void SyncAuthenticOpenCLBuffer(const Image *image)
5019 % A description of each parameter follows:
5021 % o image: the image.
5025 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5027 assert(cache_info != (CacheInfo *) NULL);
5028 assert(cache_info->signature == MagickCoreSignature);
5029 if ((cache_info->type != MemoryCache) ||
5030 (cache_info->opencl == (MagickCLCacheInfo) NULL))
5033 Ensure single threaded access to OpenCL environment.
5035 LockSemaphoreInfo(cache_info->semaphore);
5036 cache_info->opencl=(MagickCLCacheInfo) CopyMagickCLCacheInfo(
5037 cache_info->opencl);
5038 UnlockSemaphoreInfo(cache_info->semaphore);
5041 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5044 *magick_restrict cache_info;
5046 assert(image != (const Image *) NULL);
5047 cache_info=(CacheInfo *) image->cache;
5048 CopyOpenCLBuffer(cache_info);
5053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5057 + 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 %
5061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5063 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5064 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5065 % is synced, otherwise MagickFalse.
5067 % The format of the SyncAuthenticPixelCacheNexus() method is:
5069 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5070 % NexusInfo *nexus_info,ExceptionInfo *exception)
5072 % A description of each parameter follows:
5074 % o image: the image.
5076 % o nexus_info: the cache nexus to sync.
5078 % o exception: return any errors or warnings in this structure.
5081 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5082 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5085 *magick_restrict cache_info;
5091 Transfer pixels to the cache.
5093 assert(image != (Image *) NULL);
5094 assert(image->signature == MagickCoreSignature);
5095 if (image->cache == (Cache) NULL)
5096 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5097 cache_info=(CacheInfo *) image->cache;
5098 assert(cache_info->signature == MagickCoreSignature);
5099 if (cache_info->type == UndefinedCache)
5100 return(MagickFalse);
5101 if (nexus_info->authentic_pixel_cache != MagickFalse)
5103 image->taint=MagickTrue;
5106 assert(cache_info->signature == MagickCoreSignature);
5107 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5108 if ((cache_info->metacontent_extent != 0) &&
5109 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5110 return(MagickFalse);
5111 if (status != MagickFalse)
5112 image->taint=MagickTrue;
5117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5121 + S y n c A u t h e n t i c P i x e l C a c h e %
5125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5127 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5128 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5129 % otherwise MagickFalse.
5131 % The format of the SyncAuthenticPixelsCache() method is:
5133 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5134 % ExceptionInfo *exception)
5136 % A description of each parameter follows:
5138 % o image: the image.
5140 % o exception: return any errors or warnings in this structure.
5143 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5144 ExceptionInfo *exception)
5147 *magick_restrict cache_info;
5150 id = GetOpenMPThreadId();
5155 assert(image != (Image *) NULL);
5156 assert(image->signature == MagickCoreSignature);
5157 assert(image->cache != (Cache) NULL);
5158 cache_info=(CacheInfo *) image->cache;
5159 assert(cache_info->signature == MagickCoreSignature);
5160 assert(id < (int) cache_info->number_threads);
5161 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5171 % S y n c A u t h e n t i c P i x e l s %
5175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5177 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5178 % The method returns MagickTrue if the pixel region is flushed, otherwise
5181 % The format of the SyncAuthenticPixels() method is:
5183 % MagickBooleanType SyncAuthenticPixels(Image *image,
5184 % ExceptionInfo *exception)
5186 % A description of each parameter follows:
5188 % o image: the image.
5190 % o exception: return any errors or warnings in this structure.
5193 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5194 ExceptionInfo *exception)
5197 *magick_restrict cache_info;
5200 id = GetOpenMPThreadId();
5205 assert(image != (Image *) NULL);
5206 assert(image->signature == MagickCoreSignature);
5207 assert(image->cache != (Cache) NULL);
5208 cache_info=(CacheInfo *) image->cache;
5209 assert(cache_info->signature == MagickCoreSignature);
5210 if (cache_info->methods.sync_authentic_pixels_handler !=
5211 (SyncAuthenticPixelsHandler) NULL)
5213 status=cache_info->methods.sync_authentic_pixels_handler(image,
5217 assert(id < (int) cache_info->number_threads);
5218 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228 + S y n c I m a g e P i x e l C a c h e %
5232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5234 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5235 % The method returns MagickTrue if the pixel region is flushed, otherwise
5238 % The format of the SyncImagePixelCache() method is:
5240 % MagickBooleanType SyncImagePixelCache(Image *image,
5241 % ExceptionInfo *exception)
5243 % A description of each parameter follows:
5245 % o image: the image.
5247 % o exception: return any errors or warnings in this structure.
5250 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5251 ExceptionInfo *exception)
5254 *magick_restrict cache_info;
5256 assert(image != (Image *) NULL);
5257 assert(exception != (ExceptionInfo *) NULL);
5258 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5259 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5267 + 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 %
5271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5273 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5274 % of the pixel cache.
5276 % The format of the WritePixelCacheMetacontent() method is:
5278 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5279 % NexusInfo *nexus_info,ExceptionInfo *exception)
5281 % A description of each parameter follows:
5283 % o cache_info: the pixel cache.
5285 % o nexus_info: the cache nexus to write the meta-content.
5287 % o exception: return any errors or warnings in this structure.
5290 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5291 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5301 register const unsigned char
5310 if (cache_info->metacontent_extent == 0)
5311 return(MagickFalse);
5312 if (nexus_info->authentic_pixel_cache != MagickFalse)
5314 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5315 nexus_info->region.x;
5316 length=(MagickSizeType) nexus_info->region.width*
5317 cache_info->metacontent_extent;
5318 extent=(MagickSizeType) length*nexus_info->region.height;
5319 rows=nexus_info->region.height;
5321 p=(unsigned char *) nexus_info->metacontent;
5322 switch (cache_info->type)
5327 register unsigned char
5331 Write associated pixels to memory.
5333 if ((cache_info->columns == nexus_info->region.width) &&
5334 (extent == (MagickSizeType) ((size_t) extent)))
5339 q=(unsigned char *) cache_info->metacontent+offset*
5340 cache_info->metacontent_extent;
5341 for (y=0; y < (ssize_t) rows; y++)
5343 (void) memcpy(q,p,(size_t) length);
5344 p+=nexus_info->region.width*cache_info->metacontent_extent;
5345 q+=cache_info->columns*cache_info->metacontent_extent;
5352 Write associated pixels to disk.
5354 LockSemaphoreInfo(cache_info->file_semaphore);
5355 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5357 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5358 cache_info->cache_filename);
5359 UnlockSemaphoreInfo(cache_info->file_semaphore);
5360 return(MagickFalse);
5362 if ((cache_info->columns == nexus_info->region.width) &&
5363 (extent <= MagickMaxBufferExtent))
5368 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5369 for (y=0; y < (ssize_t) rows; y++)
5371 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5372 cache_info->number_channels*sizeof(Quantum)+offset*
5373 cache_info->metacontent_extent,length,(const unsigned char *) p);
5374 if (count != (MagickOffsetType) length)
5376 p+=cache_info->metacontent_extent*nexus_info->region.width;
5377 offset+=cache_info->columns;
5379 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5380 (void) ClosePixelCacheOnDisk(cache_info);
5381 UnlockSemaphoreInfo(cache_info->file_semaphore);
5384 case DistributedCache:
5390 Write metacontent to distributed cache.
5392 LockSemaphoreInfo(cache_info->file_semaphore);
5393 region=nexus_info->region;
5394 if ((cache_info->columns != nexus_info->region.width) ||
5395 (extent > MagickMaxBufferExtent))
5402 for (y=0; y < (ssize_t) rows; y++)
5404 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5405 cache_info->server_info,®ion,length,(const unsigned char *) p);
5406 if (count != (MagickOffsetType) length)
5408 p+=cache_info->metacontent_extent*nexus_info->region.width;
5411 UnlockSemaphoreInfo(cache_info->file_semaphore);
5417 if (y < (ssize_t) rows)
5419 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5420 cache_info->cache_filename);
5421 return(MagickFalse);
5423 if ((cache_info->debug != MagickFalse) &&
5424 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5425 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5426 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5427 nexus_info->region.width,(double) nexus_info->region.height,(double)
5428 nexus_info->region.x,(double) nexus_info->region.y);
5433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5437 + W r i t e C a c h e P i x e l s %
5441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5443 % WritePixelCachePixels() writes image pixels to the specified region of the
5446 % The format of the WritePixelCachePixels() method is:
5448 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5449 % NexusInfo *nexus_info,ExceptionInfo *exception)
5451 % A description of each parameter follows:
5453 % o cache_info: the pixel cache.
5455 % o nexus_info: the cache nexus to write the pixels.
5457 % o exception: return any errors or warnings in this structure.
5460 static MagickBooleanType WritePixelCachePixels(
5461 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5462 ExceptionInfo *exception)
5472 register const Quantum
5481 if (nexus_info->authentic_pixel_cache != MagickFalse)
5483 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5484 nexus_info->region.x;
5485 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5487 extent=length*nexus_info->region.height;
5488 rows=nexus_info->region.height;
5490 p=nexus_info->pixels;
5491 switch (cache_info->type)
5500 Write pixels to memory.
5502 if ((cache_info->columns == nexus_info->region.width) &&
5503 (extent == (MagickSizeType) ((size_t) extent)))
5508 q=cache_info->pixels+offset*cache_info->number_channels;
5509 for (y=0; y < (ssize_t) rows; y++)
5511 (void) memcpy(q,p,(size_t) length);
5512 p+=cache_info->number_channels*nexus_info->region.width;
5513 q+=cache_info->columns*cache_info->number_channels;
5520 Write pixels to disk.
5522 LockSemaphoreInfo(cache_info->file_semaphore);
5523 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5525 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5526 cache_info->cache_filename);
5527 UnlockSemaphoreInfo(cache_info->file_semaphore);
5528 return(MagickFalse);
5530 if ((cache_info->columns == nexus_info->region.width) &&
5531 (extent <= MagickMaxBufferExtent))
5536 for (y=0; y < (ssize_t) rows; y++)
5538 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5539 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5541 if (count != (MagickOffsetType) length)
5543 p+=cache_info->number_channels*nexus_info->region.width;
5544 offset+=cache_info->columns;
5546 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5547 (void) ClosePixelCacheOnDisk(cache_info);
5548 UnlockSemaphoreInfo(cache_info->file_semaphore);
5551 case DistributedCache:
5557 Write pixels to distributed cache.
5559 LockSemaphoreInfo(cache_info->file_semaphore);
5560 region=nexus_info->region;
5561 if ((cache_info->columns != nexus_info->region.width) ||
5562 (extent > MagickMaxBufferExtent))
5569 for (y=0; y < (ssize_t) rows; y++)
5571 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5572 cache_info->server_info,®ion,length,(const unsigned char *) p);
5573 if (count != (MagickOffsetType) length)
5575 p+=cache_info->number_channels*nexus_info->region.width;
5578 UnlockSemaphoreInfo(cache_info->file_semaphore);
5584 if (y < (ssize_t) rows)
5586 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5587 cache_info->cache_filename);
5588 return(MagickFalse);
5590 if ((cache_info->debug != MagickFalse) &&
5591 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5592 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5593 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5594 nexus_info->region.width,(double) nexus_info->region.height,(double)
5595 nexus_info->region.x,(double) nexus_info->region.y);