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 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
100 #if defined(__cplusplus) || defined(c_plusplus)
105 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
109 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
110 const ssize_t,const size_t,const size_t,ExceptionInfo *),
111 *GetVirtualPixelsCache(const Image *);
114 *GetVirtualMetacontentFromCache(const Image *);
116 static MagickBooleanType
117 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
120 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
122 OpenPixelCacheOnDisk(CacheInfo *,const MapMode),
123 ReadPixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
125 ReadPixelCacheMetacontent(CacheInfo *magick_restrict,
126 NexusInfo *magick_restrict,ExceptionInfo *),
127 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
128 WritePixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
130 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *magick_restrict,
134 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
135 const size_t,ExceptionInfo *),
136 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
137 const size_t,ExceptionInfo *),
138 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
139 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
141 #if defined(MAGICKCORE_OPENCL_SUPPORT)
143 CopyOpenCLBuffer(CacheInfo *magick_restrict);
146 #if defined(__cplusplus) || defined(c_plusplus)
153 static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
157 *cache_semaphore = (SemaphoreInfo *) NULL;
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("synchronize");
221 if (value != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(value);
224 value=DestroyString(value);
226 cache_info->semaphore=AcquireSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AcquireSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickCoreSignature;
231 return((Cache ) cache_info);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % A c q u i r e P i x e l C a c h e N e x u s %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
247 % The format of the AcquirePixelCacheNexus method is:
249 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 % A description of each parameter follows:
253 % o number_threads: the number of nexus threads.
256 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
259 **magick_restrict nexus_info;
264 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
265 number_threads,sizeof(*nexus_info)));
266 if (nexus_info == (NexusInfo **) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
269 sizeof(**nexus_info));
270 if (nexus_info[0] == (NexusInfo *) NULL)
271 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
272 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
273 for (i=0; i < (ssize_t) number_threads; i++)
275 nexus_info[i]=(&nexus_info[0][i]);
276 nexus_info[i]->signature=MagickCoreSignature;
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 + A c q u i r e P i x e l C a c h e P i x e l s %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % AcquirePixelCachePixels() returns the pixels associated with the specified
295 % The format of the AcquirePixelCachePixels() method is:
297 % const void *AcquirePixelCachePixels(const Image *image,
298 % MagickSizeType *length,ExceptionInfo *exception)
300 % A description of each parameter follows:
302 % o image: the image.
304 % o length: the pixel cache length.
306 % o exception: return any errors or warnings in this structure.
309 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
310 MagickSizeType *length,ExceptionInfo *exception)
313 *magick_restrict cache_info;
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickCoreSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickCoreSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickCoreSignature);
323 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
324 return((const void *) NULL);
325 *length=cache_info->length;
326 return((const void *) cache_info->pixels);
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 + C a c h e C o m p o n e n t G e n e s i s %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % CacheComponentGenesis() instantiates the cache component.
342 % The format of the CacheComponentGenesis method is:
344 % MagickBooleanType CacheComponentGenesis(void)
347 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
349 if (cache_semaphore == (SemaphoreInfo *) NULL)
350 cache_semaphore=AcquireSemaphoreInfo();
355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359 + C a c h e C o m p o n e n t T e r m i n u s %
363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 % CacheComponentTerminus() destroys the cache component.
367 % The format of the CacheComponentTerminus() method is:
369 % CacheComponentTerminus(void)
372 MagickPrivate void CacheComponentTerminus(void)
374 if (cache_semaphore == (SemaphoreInfo *) NULL)
375 ActivateSemaphoreInfo(&cache_semaphore);
376 LockSemaphoreInfo(cache_semaphore);
377 instantiate_cache=MagickFalse;
378 UnlockSemaphoreInfo(cache_semaphore);
379 RelinquishSemaphoreInfo(&cache_semaphore);
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387 + C l o n e P i x e l C a c h e %
391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
393 % ClonePixelCache() clones a pixel cache.
395 % The format of the ClonePixelCache() method is:
397 % Cache ClonePixelCache(const Cache cache)
399 % A description of each parameter follows:
401 % o cache: the pixel cache.
404 MagickPrivate Cache ClonePixelCache(const Cache cache)
407 *magick_restrict clone_info;
410 *magick_restrict cache_info;
412 assert(cache != NULL);
413 cache_info=(const CacheInfo *) cache;
414 assert(cache_info->signature == MagickCoreSignature);
415 if (cache_info->debug != MagickFalse)
416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
417 cache_info->filename);
418 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
419 if (clone_info == (Cache) NULL)
420 return((Cache) NULL);
421 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
422 return((Cache ) clone_info);
426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 + C l o n e P i x e l C a c h e M e t h o d s %
434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
439 % The format of the ClonePixelCacheMethods() method is:
441 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
443 % A description of each parameter follows:
445 % o clone: Specifies a pointer to a Cache structure.
447 % o cache: the pixel cache.
450 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
453 *magick_restrict cache_info,
454 *magick_restrict source_info;
456 assert(clone != (Cache) NULL);
457 source_info=(CacheInfo *) clone;
458 assert(source_info->signature == MagickCoreSignature);
459 if (source_info->debug != MagickFalse)
460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
461 source_info->filename);
462 assert(cache != (Cache) NULL);
463 cache_info=(CacheInfo *) cache;
464 assert(cache_info->signature == MagickCoreSignature);
465 source_info->methods=cache_info->methods;
469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 + C l o n e P i x e l C a c h e R e p o s i t o r y %
477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478 % ClonePixelCacheRepository() clones the source pixel cache to the destination
481 % The format of the ClonePixelCacheRepository() method is:
483 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
484 % CacheInfo *source_info,ExceptionInfo *exception)
486 % A description of each parameter follows:
488 % o cache_info: the pixel cache.
490 % o source_info: the source pixel cache.
492 % o exception: return any errors or warnings in this structure.
496 static MagickBooleanType ClonePixelCacheOnDisk(
497 CacheInfo *magick_restrict cache_info,CacheInfo *magick_restrict clone_info)
515 Clone pixel cache on disk with identifcal morphology.
517 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
518 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
520 quantum=(size_t) MagickMaxBufferExtent;
521 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
522 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
523 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
524 if (buffer == (unsigned char *) NULL)
525 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
527 while ((count=read(cache_info->file,buffer,quantum)) > 0)
532 number_bytes=write(clone_info->file,buffer,(size_t) count);
533 if (number_bytes != count)
535 extent+=number_bytes;
537 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
538 if (extent != cache_info->length)
543 static MagickBooleanType ClonePixelCacheRepository(
544 CacheInfo *magick_restrict clone_info,CacheInfo *magick_restrict cache_info,
545 ExceptionInfo *exception)
547 #define MaxCacheThreads 2
548 #define cache_threads(source,destination) \
549 num_threads(((source)->type == DiskCache) || \
550 ((destination)->type == DiskCache) || (((source)->rows) < \
551 (16*GetMagickResourceLimit(ThreadResource))) ? 1 : \
552 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
553 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
560 **magick_restrict cache_nexus,
561 **magick_restrict clone_nexus;
569 assert(cache_info != (CacheInfo *) NULL);
570 assert(clone_info != (CacheInfo *) NULL);
571 assert(exception != (ExceptionInfo *) NULL);
572 if (cache_info->type == PingCache)
574 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
575 if ((cache_info->columns == clone_info->columns) &&
576 (cache_info->rows == clone_info->rows) &&
577 (cache_info->number_channels == clone_info->number_channels) &&
578 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
579 (cache_info->metacontent_extent == clone_info->metacontent_extent))
582 Identical pixel cache morphology.
584 if (((cache_info->type == MemoryCache) ||
585 (cache_info->type == MapCache)) &&
586 ((clone_info->type == MemoryCache) ||
587 (clone_info->type == MapCache)))
589 (void) memcpy(clone_info->pixels,cache_info->pixels,
590 cache_info->columns*cache_info->number_channels*cache_info->rows*
591 sizeof(*cache_info->pixels));
592 if ((cache_info->metacontent_extent != 0) &&
593 (clone_info->metacontent_extent != 0))
594 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
595 cache_info->columns*cache_info->rows*
596 clone_info->metacontent_extent*sizeof(unsigned char));
599 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
600 return(ClonePixelCacheOnDisk(cache_info,clone_info));
603 Mismatched pixel cache morphology.
605 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
606 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
607 if ((cache_nexus == (NexusInfo **) NULL) ||
608 (clone_nexus == (NexusInfo **) NULL))
609 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
610 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
611 optimize=(cache_info->number_channels == clone_info->number_channels) &&
612 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
613 MagickTrue : MagickFalse;
614 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
615 clone_info->columns*clone_info->number_channels);
617 #if defined(MAGICKCORE_OPENMP_SUPPORT)
618 #pragma omp parallel for schedule(static,4) shared(status) \
619 cache_threads(cache_info,clone_info)
621 for (y=0; y < (ssize_t) cache_info->rows; y++)
624 id = GetOpenMPThreadId();
635 if (status == MagickFalse)
637 if (y >= (ssize_t) clone_info->rows)
639 region.width=cache_info->columns;
643 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
644 cache_nexus[id],exception);
645 if (pixels == (Quantum *) NULL)
647 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
648 if (status == MagickFalse)
650 region.width=clone_info->columns;
651 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
652 clone_nexus[id],exception);
653 if (pixels == (Quantum *) NULL)
655 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
656 clone_nexus[id]->length);
657 if (optimize != MagickFalse)
658 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
662 register const Quantum
669 Mismatched pixel channel map.
671 p=cache_nexus[id]->pixels;
672 q=clone_nexus[id]->pixels;
673 for (x=0; x < (ssize_t) cache_info->columns; x++)
678 if (x == (ssize_t) clone_info->columns)
680 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
688 channel=clone_info->channel_map[i].channel;
689 traits=cache_info->channel_map[channel].traits;
690 if (traits != UndefinedPixelTrait)
691 *q=*(p+cache_info->channel_map[channel].offset);
694 p+=cache_info->number_channels;
697 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
699 if ((cache_info->metacontent_extent != 0) &&
700 (clone_info->metacontent_extent != 0))
705 length=(size_t) MagickMin(cache_info->metacontent_extent,
706 clone_info->metacontent_extent);
707 #if defined(MAGICKCORE_OPENMP_SUPPORT)
708 #pragma omp parallel for schedule(static,4) shared(status) \
709 cache_threads(cache_info,clone_info)
711 for (y=0; y < (ssize_t) cache_info->rows; y++)
714 id = GetOpenMPThreadId();
722 if (status == MagickFalse)
724 if (y >= (ssize_t) clone_info->rows)
726 region.width=cache_info->columns;
730 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
731 cache_nexus[id],exception);
732 if (pixels == (Quantum *) NULL)
734 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
735 if (status == MagickFalse)
737 region.width=clone_info->columns;
738 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
739 clone_nexus[id],exception);
740 if (pixels == (Quantum *) NULL)
742 if ((clone_nexus[id]->metacontent != (void *) NULL) &&
743 (cache_nexus[id]->metacontent != (void *) NULL))
744 (void) memcpy(clone_nexus[id]->metacontent,
745 cache_nexus[id]->metacontent,length*sizeof(unsigned char));
746 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
749 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
750 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
751 if (cache_info->debug != MagickFalse)
754 message[MagickPathExtent];
756 (void) FormatLocaleString(message,MagickPathExtent,"%s => %s",
757 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
758 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
759 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769 + D e s t r o y I m a g e P i x e l C a c h e %
773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
775 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
777 % The format of the DestroyImagePixelCache() method is:
779 % void DestroyImagePixelCache(Image *image)
781 % A description of each parameter follows:
783 % o image: the image.
786 static void DestroyImagePixelCache(Image *image)
788 assert(image != (Image *) NULL);
789 assert(image->signature == MagickCoreSignature);
790 if (image->debug != MagickFalse)
791 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
792 if (image->cache == (void *) NULL)
794 image->cache=DestroyPixelCache(image->cache);
798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802 + D e s t r o y I m a g e P i x e l s %
806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
808 % DestroyImagePixels() deallocates memory associated with the pixel cache.
810 % The format of the DestroyImagePixels() method is:
812 % void DestroyImagePixels(Image *image)
814 % A description of each parameter follows:
816 % o image: the image.
819 MagickExport void DestroyImagePixels(Image *image)
822 *magick_restrict cache_info;
824 assert(image != (const Image *) NULL);
825 assert(image->signature == MagickCoreSignature);
826 if (image->debug != MagickFalse)
827 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
828 assert(image->cache != (Cache) NULL);
829 cache_info=(CacheInfo *) image->cache;
830 assert(cache_info->signature == MagickCoreSignature);
831 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
833 cache_info->methods.destroy_pixel_handler(image);
836 image->cache=DestroyPixelCache(image->cache);
840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
844 + D e s t r o y P i x e l C a c h e %
848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850 % DestroyPixelCache() deallocates memory associated with the pixel cache.
852 % The format of the DestroyPixelCache() method is:
854 % Cache DestroyPixelCache(Cache cache)
856 % A description of each parameter follows:
858 % o cache: the pixel cache.
862 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
868 if (cache_info->file != -1)
870 status=close(cache_info->file);
871 cache_info->file=(-1);
872 RelinquishMagickResource(FileResource,1);
874 return(status == -1 ? MagickFalse : MagickTrue);
877 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
879 switch (cache_info->type)
883 #if defined(MAGICKCORE_OPENCL_SUPPORT)
884 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
886 cache_info->opencl=RelinquishMagickCLCacheInfo(cache_info->opencl,
888 cache_info->pixels=(Quantum *) NULL;
892 if (cache_info->mapped == MagickFalse)
893 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
896 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
897 RelinquishMagickResource(MemoryResource,cache_info->length);
902 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
903 cache_info->pixels=(Quantum *) NULL;
904 if (cache_info->mode != ReadMode)
905 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
906 *cache_info->cache_filename='\0';
907 RelinquishMagickResource(MapResource,cache_info->length);
911 if (cache_info->file != -1)
912 (void) ClosePixelCacheOnDisk(cache_info);
913 if (cache_info->mode != ReadMode)
914 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
915 *cache_info->cache_filename='\0';
916 RelinquishMagickResource(DiskResource,cache_info->length);
919 case DistributedCache:
921 *cache_info->cache_filename='\0';
922 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
923 cache_info->server_info);
929 cache_info->type=UndefinedCache;
930 cache_info->mapped=MagickFalse;
931 cache_info->metacontent=(void *) NULL;
934 MagickPrivate Cache DestroyPixelCache(Cache cache)
937 *magick_restrict cache_info;
939 assert(cache != (Cache) NULL);
940 cache_info=(CacheInfo *) cache;
941 assert(cache_info->signature == MagickCoreSignature);
942 if (cache_info->debug != MagickFalse)
943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
944 cache_info->filename);
945 LockSemaphoreInfo(cache_info->semaphore);
946 cache_info->reference_count--;
947 if (cache_info->reference_count != 0)
949 UnlockSemaphoreInfo(cache_info->semaphore);
950 return((Cache) NULL);
952 UnlockSemaphoreInfo(cache_info->semaphore);
953 if (cache_info->debug != MagickFalse)
956 message[MagickPathExtent];
958 (void) FormatLocaleString(message,MagickPathExtent,"destroy %s",
959 cache_info->filename);
960 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
962 RelinquishPixelCachePixels(cache_info);
963 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
964 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
965 cache_info->server_info);
966 if (cache_info->nexus_info != (NexusInfo **) NULL)
967 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
968 cache_info->number_threads);
969 if (cache_info->random_info != (RandomInfo *) NULL)
970 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
971 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
972 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
973 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
974 RelinquishSemaphoreInfo(&cache_info->semaphore);
975 cache_info->signature=(~MagickCoreSignature);
976 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 + D e s t r o y P i x e l C a c h e N e x u s %
990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
994 % The format of the DestroyPixelCacheNexus() method is:
996 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
997 % const size_t number_threads)
999 % A description of each parameter follows:
1001 % o nexus_info: the nexus to destroy.
1003 % o number_threads: the number of nexus threads.
1007 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1009 if (nexus_info->mapped == MagickFalse)
1010 (void) RelinquishAlignedMemory(nexus_info->cache);
1012 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1013 nexus_info->cache=(Quantum *) NULL;
1014 nexus_info->pixels=(Quantum *) NULL;
1015 nexus_info->metacontent=(void *) NULL;
1016 nexus_info->length=0;
1017 nexus_info->mapped=MagickFalse;
1020 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1021 const size_t number_threads)
1026 assert(nexus_info != (NexusInfo **) NULL);
1027 for (i=0; i < (ssize_t) number_threads; i++)
1029 if (nexus_info[i]->cache != (Quantum *) NULL)
1030 RelinquishCacheNexusPixels(nexus_info[i]);
1031 nexus_info[i]->signature=(~MagickCoreSignature);
1033 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1034 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1043 % G e t A u t h e n t i c M e t a c o n t e n t %
1047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1050 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1051 % returned if the associated pixels are not available.
1053 % The format of the GetAuthenticMetacontent() method is:
1055 % void *GetAuthenticMetacontent(const Image *image)
1057 % A description of each parameter follows:
1059 % o image: the image.
1062 MagickExport void *GetAuthenticMetacontent(const Image *image)
1065 *magick_restrict cache_info;
1068 id = GetOpenMPThreadId();
1070 assert(image != (const Image *) NULL);
1071 assert(image->signature == MagickCoreSignature);
1072 assert(image->cache != (Cache) NULL);
1073 cache_info=(CacheInfo *) image->cache;
1074 assert(cache_info->signature == MagickCoreSignature);
1075 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1076 (GetAuthenticMetacontentFromHandler) NULL)
1081 metacontent=cache_info->methods.
1082 get_authentic_metacontent_from_handler(image);
1083 return(metacontent);
1085 assert(id < (int) cache_info->number_threads);
1086 return(cache_info->nexus_info[id]->metacontent);
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094 + G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1101 % with the last call to QueueAuthenticPixelsCache() or
1102 % GetAuthenticPixelsCache().
1104 % The format of the GetAuthenticMetacontentFromCache() method is:
1106 % void *GetAuthenticMetacontentFromCache(const Image *image)
1108 % A description of each parameter follows:
1110 % o image: the image.
1113 static void *GetAuthenticMetacontentFromCache(const Image *image)
1116 *magick_restrict cache_info;
1119 id = GetOpenMPThreadId();
1121 assert(image != (const Image *) NULL);
1122 assert(image->signature == MagickCoreSignature);
1123 assert(image->cache != (Cache) NULL);
1124 cache_info=(CacheInfo *) image->cache;
1125 assert(cache_info->signature == MagickCoreSignature);
1126 assert(id < (int) cache_info->number_threads);
1127 return(cache_info->nexus_info[id]->metacontent);
1130 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136 + G e t A u t h e n t i c O p e n C L B u f f e r %
1140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1142 % GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1145 % The format of the GetAuthenticOpenCLBuffer() method is:
1147 % cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1148 % MagickCLDevice device,ExceptionInfo *exception)
1150 % A description of each parameter follows:
1152 % o image: the image.
1154 % o device: the device to use.
1156 % o exception: return any errors or warnings in this structure.
1159 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1160 MagickCLDevice device,ExceptionInfo *exception)
1163 *magick_restrict cache_info;
1168 assert(image != (const Image *) NULL);
1169 assert(device != (const MagickCLDevice) NULL);
1170 cache_info=(CacheInfo *) image->cache;
1171 if (cache_info->type == UndefinedCache)
1172 SyncImagePixelCache((Image *) image,exception);
1173 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1174 return((cl_mem) NULL);
1175 if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1176 (cache_info->opencl->device->context != device->context))
1177 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1178 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1180 assert(cache_info->pixels != (Quantum *) NULL);
1181 cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1182 cache_info->length);
1183 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1184 return((cl_mem) NULL);
1186 assert(cache_info->opencl->pixels == cache_info->pixels);
1187 return(cache_info->opencl->buffer);
1192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1196 + G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1203 % disk pixel cache as defined by the geometry parameters. A pointer to the
1204 % pixels is returned if the pixels are transferred, otherwise a NULL is
1207 % The format of the GetAuthenticPixelCacheNexus() method is:
1209 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1210 % const ssize_t y,const size_t columns,const size_t rows,
1211 % NexusInfo *nexus_info,ExceptionInfo *exception)
1213 % A description of each parameter follows:
1215 % o image: the image.
1217 % o x,y,columns,rows: These values define the perimeter of a region of
1220 % o nexus_info: the cache nexus to return.
1222 % o exception: return any errors or warnings in this structure.
1226 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1227 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1228 ExceptionInfo *exception)
1231 *magick_restrict cache_info;
1234 *magick_restrict pixels;
1237 Transfer pixels from the cache.
1239 assert(image != (Image *) NULL);
1240 assert(image->signature == MagickCoreSignature);
1241 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1242 nexus_info,exception);
1243 if (pixels == (Quantum *) NULL)
1244 return((Quantum *) NULL);
1245 cache_info=(CacheInfo *) image->cache;
1246 assert(cache_info->signature == MagickCoreSignature);
1247 if (nexus_info->authentic_pixel_cache != MagickFalse)
1249 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1250 return((Quantum *) NULL);
1251 if (cache_info->metacontent_extent != 0)
1252 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1253 return((Quantum *) NULL);
1258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1262 + G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1268 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1269 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1271 % The format of the GetAuthenticPixelsFromCache() method is:
1273 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1275 % A description of each parameter follows:
1277 % o image: the image.
1280 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1283 *magick_restrict cache_info;
1286 id = GetOpenMPThreadId();
1288 assert(image != (const Image *) NULL);
1289 assert(image->signature == MagickCoreSignature);
1290 assert(image->cache != (Cache) NULL);
1291 cache_info=(CacheInfo *) image->cache;
1292 assert(cache_info->signature == MagickCoreSignature);
1293 assert(id < (int) cache_info->number_threads);
1294 return(cache_info->nexus_info[id]->pixels);
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 % G e t A u t h e n t i c P i x e l Q u e u e %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % GetAuthenticPixelQueue() returns the authentic pixels associated
1309 % corresponding with the last call to QueueAuthenticPixels() or
1310 % GetAuthenticPixels().
1312 % The format of the GetAuthenticPixelQueue() method is:
1314 % Quantum *GetAuthenticPixelQueue(const Image image)
1316 % A description of each parameter follows:
1318 % o image: the image.
1321 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1324 *magick_restrict cache_info;
1327 id = GetOpenMPThreadId();
1329 assert(image != (const Image *) NULL);
1330 assert(image->signature == MagickCoreSignature);
1331 assert(image->cache != (Cache) NULL);
1332 cache_info=(CacheInfo *) image->cache;
1333 assert(cache_info->signature == MagickCoreSignature);
1334 if (cache_info->methods.get_authentic_pixels_from_handler !=
1335 (GetAuthenticPixelsFromHandler) NULL)
1336 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1337 assert(id < (int) cache_info->number_threads);
1338 return(cache_info->nexus_info[id]->pixels);
1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346 % G e t A u t h e n t i c P i x e l s %
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1352 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1353 % region is successfully accessed, a pointer to a Quantum array
1354 % representing the region is returned, otherwise NULL is returned.
1356 % The returned pointer may point to a temporary working copy of the pixels
1357 % or it may point to the original pixels in memory. Performance is maximized
1358 % if the selected region is part of one row, or one or more full rows, since
1359 % then there is opportunity to access the pixels in-place (without a copy)
1360 % if the image is in memory, or in a memory-mapped file. The returned pointer
1361 % must *never* be deallocated by the user.
1363 % Pixels accessed via the returned pointer represent a simple array of type
1364 % Quantum. If the image has corresponding metacontent,call
1365 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1366 % meta-content corresponding to the region. Once the Quantum array has
1367 % been updated, the changes must be saved back to the underlying image using
1368 % SyncAuthenticPixels() or they may be lost.
1370 % The format of the GetAuthenticPixels() method is:
1372 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1373 % const ssize_t y,const size_t columns,const size_t rows,
1374 % ExceptionInfo *exception)
1376 % A description of each parameter follows:
1378 % o image: the image.
1380 % o x,y,columns,rows: These values define the perimeter of a region of
1383 % o exception: return any errors or warnings in this structure.
1386 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1387 const ssize_t y,const size_t columns,const size_t rows,
1388 ExceptionInfo *exception)
1391 *magick_restrict cache_info;
1394 id = GetOpenMPThreadId();
1399 assert(image != (Image *) NULL);
1400 assert(image->signature == MagickCoreSignature);
1401 assert(image->cache != (Cache) NULL);
1402 cache_info=(CacheInfo *) image->cache;
1403 assert(cache_info->signature == MagickCoreSignature);
1404 if (cache_info->methods.get_authentic_pixels_handler !=
1405 (GetAuthenticPixelsHandler) NULL)
1407 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1411 assert(id < (int) cache_info->number_threads);
1412 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1413 cache_info->nexus_info[id],exception);
1418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422 + G e t A u t h e n t i c P i x e l s C a c h e %
1426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1429 % as defined by the geometry parameters. A pointer to the pixels is returned
1430 % if the pixels are transferred, otherwise a NULL is returned.
1432 % The format of the GetAuthenticPixelsCache() method is:
1434 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1435 % const ssize_t y,const size_t columns,const size_t rows,
1436 % ExceptionInfo *exception)
1438 % A description of each parameter follows:
1440 % o image: the image.
1442 % o x,y,columns,rows: These values define the perimeter of a region of
1445 % o exception: return any errors or warnings in this structure.
1448 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1449 const ssize_t y,const size_t columns,const size_t rows,
1450 ExceptionInfo *exception)
1453 *magick_restrict cache_info;
1456 id = GetOpenMPThreadId();
1459 *magick_restrict pixels;
1461 assert(image != (const Image *) NULL);
1462 assert(image->signature == MagickCoreSignature);
1463 assert(image->cache != (Cache) NULL);
1464 cache_info=(CacheInfo *) image->cache;
1465 if (cache_info == (Cache) NULL)
1466 return((Quantum *) NULL);
1467 assert(cache_info->signature == MagickCoreSignature);
1468 assert(id < (int) cache_info->number_threads);
1469 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1470 cache_info->nexus_info[id],exception);
1475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1479 + G e t I m a g e E x t e n t %
1483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1485 % GetImageExtent() returns the extent of the pixels associated corresponding
1486 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1488 % The format of the GetImageExtent() method is:
1490 % MagickSizeType GetImageExtent(const Image *image)
1492 % A description of each parameter follows:
1494 % o image: the image.
1497 MagickExport MagickSizeType GetImageExtent(const Image *image)
1500 *magick_restrict cache_info;
1503 id = GetOpenMPThreadId();
1505 assert(image != (Image *) NULL);
1506 assert(image->signature == MagickCoreSignature);
1507 if (image->debug != MagickFalse)
1508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1509 assert(image->cache != (Cache) NULL);
1510 cache_info=(CacheInfo *) image->cache;
1511 assert(cache_info->signature == MagickCoreSignature);
1512 assert(id < (int) cache_info->number_threads);
1513 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521 + G e t I m a g e P i x e l C a c h e %
1525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527 % GetImagePixelCache() ensures that there is only a single reference to the
1528 % pixel cache to be modified, updating the provided cache pointer to point to
1529 % a clone of the original pixel cache if necessary.
1531 % The format of the GetImagePixelCache method is:
1533 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1534 % ExceptionInfo *exception)
1536 % A description of each parameter follows:
1538 % o image: the image.
1540 % o clone: any value other than MagickFalse clones the cache pixels.
1542 % o exception: return any errors or warnings in this structure.
1546 static inline MagickBooleanType ValidatePixelCacheMorphology(
1547 const Image *magick_restrict image)
1550 *magick_restrict cache_info;
1552 const PixelChannelMap
1557 Does the image match the pixel cache morphology?
1559 cache_info=(CacheInfo *) image->cache;
1560 p=image->channel_map;
1561 q=cache_info->channel_map;
1562 if ((image->storage_class != cache_info->storage_class) ||
1563 (image->colorspace != cache_info->colorspace) ||
1564 (image->alpha_trait != cache_info->alpha_trait) ||
1565 (image->read_mask != cache_info->read_mask) ||
1566 (image->write_mask != cache_info->write_mask) ||
1567 (image->columns != cache_info->columns) ||
1568 (image->rows != cache_info->rows) ||
1569 (image->number_channels != cache_info->number_channels) ||
1570 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1571 (image->metacontent_extent != cache_info->metacontent_extent) ||
1572 (cache_info->nexus_info == (NexusInfo **) NULL))
1573 return(MagickFalse);
1577 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1578 ExceptionInfo *exception)
1581 *magick_restrict cache_info;
1587 static MagickSizeType
1588 cache_timelimit = MagickResourceInfinity,
1589 cpu_throttle = MagickResourceInfinity,
1593 if (cpu_throttle == MagickResourceInfinity)
1594 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1595 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1596 MagickDelay(cpu_throttle);
1597 if (cache_epoch == 0)
1600 Set the expire time in seconds.
1602 cache_timelimit=GetMagickResourceLimit(TimeResource);
1603 cache_epoch=time((time_t *) NULL);
1605 if ((cache_timelimit != MagickResourceInfinity) &&
1606 ((MagickSizeType) (time((time_t *) NULL)-cache_epoch) >= cache_timelimit))
1608 #if defined(ECANCELED)
1611 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1613 LockSemaphoreInfo(image->semaphore);
1614 assert(image->cache != (Cache) NULL);
1615 cache_info=(CacheInfo *) image->cache;
1616 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1617 CopyOpenCLBuffer(cache_info);
1619 destroy=MagickFalse;
1620 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1622 LockSemaphoreInfo(cache_info->semaphore);
1623 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1634 clone_image=(*image);
1635 clone_image.semaphore=AcquireSemaphoreInfo();
1636 clone_image.reference_count=1;
1637 clone_image.cache=ClonePixelCache(cache_info);
1638 clone_info=(CacheInfo *) clone_image.cache;
1639 status=OpenPixelCache(&clone_image,IOMode,exception);
1640 if (status != MagickFalse)
1642 if (clone != MagickFalse)
1643 status=ClonePixelCacheRepository(clone_info,cache_info,
1645 if (status != MagickFalse)
1647 if (cache_info->reference_count == 1)
1648 cache_info->nexus_info=(NexusInfo **) NULL;
1650 image->cache=clone_image.cache;
1653 RelinquishSemaphoreInfo(&clone_image.semaphore);
1655 UnlockSemaphoreInfo(cache_info->semaphore);
1657 if (destroy != MagickFalse)
1658 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1659 if (status != MagickFalse)
1662 Ensure the image matches the pixel cache morphology.
1664 image->type=UndefinedType;
1665 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1667 status=OpenPixelCache(image,IOMode,exception);
1668 cache_info=(CacheInfo *) image->cache;
1669 if (cache_info->type == DiskCache)
1670 (void) ClosePixelCacheOnDisk(cache_info);
1673 UnlockSemaphoreInfo(image->semaphore);
1674 if (status == MagickFalse)
1675 return((Cache) NULL);
1676 return(image->cache);
1680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684 + G e t I m a g e P i x e l C a c h e T y p e %
1688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1690 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1691 % DiskCache, MemoryCache, MapCache, or PingCache.
1693 % The format of the GetImagePixelCacheType() method is:
1695 % CacheType GetImagePixelCacheType(const Image *image)
1697 % A description of each parameter follows:
1699 % o image: the image.
1702 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1705 *magick_restrict cache_info;
1707 assert(image != (Image *) NULL);
1708 assert(image->signature == MagickCoreSignature);
1709 assert(image->cache != (Cache) NULL);
1710 cache_info=(CacheInfo *) image->cache;
1711 assert(cache_info->signature == MagickCoreSignature);
1712 return(cache_info->type);
1716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1720 % G e t O n e A u t h e n t i c P i x e l %
1724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1726 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1727 % location. The image background color is returned if an error occurs.
1729 % The format of the GetOneAuthenticPixel() method is:
1731 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1732 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1734 % A description of each parameter follows:
1736 % o image: the image.
1738 % o x,y: These values define the location of the pixel to return.
1740 % o pixel: return a pixel at the specified (x,y) location.
1742 % o exception: return any errors or warnings in this structure.
1746 static inline MagickBooleanType CopyPixel(const Image *image,
1747 const Quantum *source,Quantum *destination)
1752 if (source == (const Quantum *) NULL)
1754 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1755 destination[GreenPixelChannel]=ClampToQuantum(
1756 image->background_color.green);
1757 destination[BluePixelChannel]=ClampToQuantum(
1758 image->background_color.blue);
1759 destination[BlackPixelChannel]=ClampToQuantum(
1760 image->background_color.black);
1761 destination[AlphaPixelChannel]=ClampToQuantum(
1762 image->background_color.alpha);
1763 return(MagickFalse);
1765 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1767 PixelChannel channel=GetPixelChannelChannel(image,i);
1768 destination[channel]=source[i];
1773 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1774 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1777 *magick_restrict cache_info;
1782 assert(image != (Image *) NULL);
1783 assert(image->signature == MagickCoreSignature);
1784 assert(image->cache != (Cache) NULL);
1785 cache_info=(CacheInfo *) image->cache;
1786 assert(cache_info->signature == MagickCoreSignature);
1787 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1788 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1789 (GetOneAuthenticPixelFromHandler) NULL)
1790 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1792 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1793 return(CopyPixel(image,q,pixel));
1797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1801 + G e t O n e A u t h e n t i c P i x e l F r o m C a c h e %
1805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1808 % location. The image background color is returned if an error occurs.
1810 % The format of the GetOneAuthenticPixelFromCache() method is:
1812 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1813 % const ssize_t x,const ssize_t y,Quantum *pixel,
1814 % ExceptionInfo *exception)
1816 % A description of each parameter follows:
1818 % o image: the image.
1820 % o x,y: These values define the location of the pixel to return.
1822 % o pixel: return a pixel at the specified (x,y) location.
1824 % o exception: return any errors or warnings in this structure.
1827 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1828 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1831 *magick_restrict cache_info;
1834 id = GetOpenMPThreadId();
1839 assert(image != (const Image *) NULL);
1840 assert(image->signature == MagickCoreSignature);
1841 assert(image->cache != (Cache) NULL);
1842 cache_info=(CacheInfo *) image->cache;
1843 assert(cache_info->signature == MagickCoreSignature);
1844 assert(id < (int) cache_info->number_threads);
1845 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1846 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1848 return(CopyPixel(image,q,pixel));
1852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1856 % G e t O n e V i r t u a l P i x e l %
1860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1863 % (x,y) location. The image background color is returned if an error occurs.
1864 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1866 % The format of the GetOneVirtualPixel() method is:
1868 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1869 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1871 % A description of each parameter follows:
1873 % o image: the image.
1875 % o x,y: These values define the location of the pixel to return.
1877 % o pixel: return a pixel at the specified (x,y) location.
1879 % o exception: return any errors or warnings in this structure.
1882 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1883 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1886 *magick_restrict cache_info;
1889 id = GetOpenMPThreadId();
1894 assert(image != (const Image *) NULL);
1895 assert(image->signature == MagickCoreSignature);
1896 assert(image->cache != (Cache) NULL);
1897 cache_info=(CacheInfo *) image->cache;
1898 assert(cache_info->signature == MagickCoreSignature);
1899 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1900 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1901 (GetOneVirtualPixelFromHandler) NULL)
1902 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1903 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1904 assert(id < (int) cache_info->number_threads);
1905 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1906 1UL,1UL,cache_info->nexus_info[id],exception);
1907 return(CopyPixel(image,p,pixel));
1911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1915 + G e t O n e V i r t u a l P i x e l F r o m C a c h e %
1919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1921 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1922 % specified (x,y) location. The image background color is returned if an
1925 % The format of the GetOneVirtualPixelFromCache() method is:
1927 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1928 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1929 % Quantum *pixel,ExceptionInfo *exception)
1931 % A description of each parameter follows:
1933 % o image: the image.
1935 % o virtual_pixel_method: the virtual pixel method.
1937 % o x,y: These values define the location of the pixel to return.
1939 % o pixel: return a pixel at the specified (x,y) location.
1941 % o exception: return any errors or warnings in this structure.
1944 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1945 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1946 Quantum *pixel,ExceptionInfo *exception)
1949 *magick_restrict cache_info;
1952 id = GetOpenMPThreadId();
1957 assert(image != (const Image *) NULL);
1958 assert(image->signature == MagickCoreSignature);
1959 assert(image->cache != (Cache) NULL);
1960 cache_info=(CacheInfo *) image->cache;
1961 assert(cache_info->signature == MagickCoreSignature);
1962 assert(id < (int) cache_info->number_threads);
1963 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1964 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1965 cache_info->nexus_info[id],exception);
1966 return(CopyPixel(image,p,pixel));
1970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1974 % G e t O n e V i r t u a l P i x e l I n f o %
1978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1981 % location. The image background color is returned if an error occurs. If
1982 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1984 % The format of the GetOneVirtualPixelInfo() method is:
1986 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1987 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1988 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1990 % A description of each parameter follows:
1992 % o image: the image.
1994 % o virtual_pixel_method: the virtual pixel method.
1996 % o x,y: these values define the location of the pixel to return.
1998 % o pixel: return a pixel at the specified (x,y) location.
2000 % o exception: return any errors or warnings in this structure.
2003 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2004 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2005 PixelInfo *pixel,ExceptionInfo *exception)
2008 *magick_restrict cache_info;
2011 id = GetOpenMPThreadId();
2013 register const Quantum
2016 assert(image != (const Image *) NULL);
2017 assert(image->signature == MagickCoreSignature);
2018 assert(image->cache != (Cache) NULL);
2019 cache_info=(CacheInfo *) image->cache;
2020 assert(cache_info->signature == MagickCoreSignature);
2021 assert(id < (int) cache_info->number_threads);
2022 GetPixelInfo(image,pixel);
2023 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2024 cache_info->nexus_info[id],exception);
2025 if (p == (const Quantum *) NULL)
2026 return(MagickFalse);
2027 GetPixelInfoPixel(image,p,pixel);
2032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2036 + G e t P i x e l C a c h e C o l o r s p a c e %
2040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2042 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2044 % The format of the GetPixelCacheColorspace() method is:
2046 % Colorspace GetPixelCacheColorspace(Cache cache)
2048 % A description of each parameter follows:
2050 % o cache: the pixel cache.
2053 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2056 *magick_restrict cache_info;
2058 assert(cache != (Cache) NULL);
2059 cache_info=(CacheInfo *) cache;
2060 assert(cache_info->signature == MagickCoreSignature);
2061 if (cache_info->debug != MagickFalse)
2062 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2063 cache_info->filename);
2064 return(cache_info->colorspace);
2068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072 + G e t P i x e l C a c h e M e t h o d s %
2076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078 % GetPixelCacheMethods() initializes the CacheMethods structure.
2080 % The format of the GetPixelCacheMethods() method is:
2082 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2084 % A description of each parameter follows:
2086 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2089 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2091 assert(cache_methods != (CacheMethods *) NULL);
2092 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2093 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2094 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2095 cache_methods->get_virtual_metacontent_from_handler=
2096 GetVirtualMetacontentFromCache;
2097 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2098 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2099 cache_methods->get_authentic_metacontent_from_handler=
2100 GetAuthenticMetacontentFromCache;
2101 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2102 cache_methods->get_one_authentic_pixel_from_handler=
2103 GetOneAuthenticPixelFromCache;
2104 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2105 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2106 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2114 + G e t P i x e l C a c h e N e x u s E x t e n t %
2118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2120 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2121 % corresponding with the last call to SetPixelCacheNexusPixels() or
2122 % GetPixelCacheNexusPixels().
2124 % The format of the GetPixelCacheNexusExtent() method is:
2126 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2127 % NexusInfo *nexus_info)
2129 % A description of each parameter follows:
2131 % o nexus_info: the nexus info.
2134 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2135 NexusInfo *magick_restrict nexus_info)
2138 *magick_restrict cache_info;
2143 assert(cache != NULL);
2144 cache_info=(CacheInfo *) cache;
2145 assert(cache_info->signature == MagickCoreSignature);
2146 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2148 return((MagickSizeType) cache_info->columns*cache_info->rows);
2153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157 + G e t P i x e l C a c h e P i x e l s %
2161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163 % GetPixelCachePixels() returns the pixels associated with the specified image.
2165 % The format of the GetPixelCachePixels() method is:
2167 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2168 % ExceptionInfo *exception)
2170 % A description of each parameter follows:
2172 % o image: the image.
2174 % o length: the pixel cache length.
2176 % o exception: return any errors or warnings in this structure.
2179 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2180 ExceptionInfo *exception)
2183 *magick_restrict cache_info;
2185 assert(image != (const Image *) NULL);
2186 assert(image->signature == MagickCoreSignature);
2187 assert(image->cache != (Cache) NULL);
2188 assert(length != (MagickSizeType *) NULL);
2189 assert(exception != (ExceptionInfo *) NULL);
2190 assert(exception->signature == MagickCoreSignature);
2191 cache_info=(CacheInfo *) image->cache;
2192 assert(cache_info->signature == MagickCoreSignature);
2194 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2195 return((void *) NULL);
2196 *length=cache_info->length;
2197 return((void *) cache_info->pixels);
2201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205 + G e t P i x e l C a c h e S t o r a g e C l a s s %
2209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2211 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2213 % The format of the GetPixelCacheStorageClass() method is:
2215 % ClassType GetPixelCacheStorageClass(Cache cache)
2217 % A description of each parameter follows:
2219 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2221 % o cache: the pixel cache.
2224 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2227 *magick_restrict cache_info;
2229 assert(cache != (Cache) NULL);
2230 cache_info=(CacheInfo *) cache;
2231 assert(cache_info->signature == MagickCoreSignature);
2232 if (cache_info->debug != MagickFalse)
2233 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2234 cache_info->filename);
2235 return(cache_info->storage_class);
2239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 + G e t P i x e l C a c h e T i l e S i z e %
2247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249 % GetPixelCacheTileSize() returns the pixel cache tile size.
2251 % The format of the GetPixelCacheTileSize() method is:
2253 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2256 % A description of each parameter follows:
2258 % o image: the image.
2260 % o width: the optimize cache tile width in pixels.
2262 % o height: the optimize cache tile height in pixels.
2265 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2269 *magick_restrict cache_info;
2271 assert(image != (Image *) NULL);
2272 assert(image->signature == MagickCoreSignature);
2273 if (image->debug != MagickFalse)
2274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2275 cache_info=(CacheInfo *) image->cache;
2276 assert(cache_info->signature == MagickCoreSignature);
2277 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2278 if (GetImagePixelCacheType(image) == DiskCache)
2279 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2288 + G e t P i x e l C a c h e V i r t u a l M e t h o d %
2292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2294 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2295 % pixel cache. A virtual pixel is any pixel access that is outside the
2296 % boundaries of the image cache.
2298 % The format of the GetPixelCacheVirtualMethod() method is:
2300 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2302 % A description of each parameter follows:
2304 % o image: the image.
2307 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2310 *magick_restrict cache_info;
2312 assert(image != (Image *) NULL);
2313 assert(image->signature == MagickCoreSignature);
2314 assert(image->cache != (Cache) NULL);
2315 cache_info=(CacheInfo *) image->cache;
2316 assert(cache_info->signature == MagickCoreSignature);
2317 return(cache_info->virtual_pixel_method);
2321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2325 + G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
2329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2331 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2332 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2334 % The format of the GetVirtualMetacontentFromCache() method is:
2336 % void *GetVirtualMetacontentFromCache(const Image *image)
2338 % A description of each parameter follows:
2340 % o image: the image.
2343 static const void *GetVirtualMetacontentFromCache(const Image *image)
2346 *magick_restrict cache_info;
2349 id = GetOpenMPThreadId();
2352 *magick_restrict metacontent;
2354 assert(image != (const Image *) NULL);
2355 assert(image->signature == MagickCoreSignature);
2356 assert(image->cache != (Cache) NULL);
2357 cache_info=(CacheInfo *) image->cache;
2358 assert(cache_info->signature == MagickCoreSignature);
2359 assert(id < (int) cache_info->number_threads);
2360 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2361 cache_info->nexus_info[id]);
2362 return(metacontent);
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2370 + G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2379 % The format of the GetVirtualMetacontentFromNexus() method is:
2381 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2382 % NexusInfo *nexus_info)
2384 % A description of each parameter follows:
2386 % o cache: the pixel cache.
2388 % o nexus_info: the cache nexus to return the meta-content.
2391 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2392 NexusInfo *magick_restrict nexus_info)
2395 *magick_restrict cache_info;
2397 assert(cache != (Cache) NULL);
2398 cache_info=(CacheInfo *) cache;
2399 assert(cache_info->signature == MagickCoreSignature);
2400 if (cache_info->storage_class == UndefinedClass)
2401 return((void *) NULL);
2402 return(nexus_info->metacontent);
2406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2410 % G e t V i r t u a l M e t a c o n t e n t %
2414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2416 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2417 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2418 % returned if the meta-content are not available.
2420 % The format of the GetVirtualMetacontent() method is:
2422 % const void *GetVirtualMetacontent(const Image *image)
2424 % A description of each parameter follows:
2426 % o image: the image.
2429 MagickExport const void *GetVirtualMetacontent(const Image *image)
2432 *magick_restrict cache_info;
2435 id = GetOpenMPThreadId();
2438 *magick_restrict metacontent;
2440 assert(image != (const Image *) NULL);
2441 assert(image->signature == MagickCoreSignature);
2442 assert(image->cache != (Cache) NULL);
2443 cache_info=(CacheInfo *) image->cache;
2444 assert(cache_info->signature == MagickCoreSignature);
2445 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2446 if (metacontent != (void *) NULL)
2447 return(metacontent);
2448 assert(id < (int) cache_info->number_threads);
2449 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2450 cache_info->nexus_info[id]);
2451 return(metacontent);
2455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459 + G e t V i r t u a l P i x e l s F r o m N e x u s %
2463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2466 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2467 % is returned if the pixels are transferred, otherwise a NULL is returned.
2469 % The format of the GetVirtualPixelsFromNexus() method is:
2471 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2472 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2473 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2474 % ExceptionInfo *exception)
2476 % A description of each parameter follows:
2478 % o image: the image.
2480 % o virtual_pixel_method: the virtual pixel method.
2482 % o x,y,columns,rows: These values define the perimeter of a region of
2485 % o nexus_info: the cache nexus to acquire.
2487 % o exception: return any errors or warnings in this structure.
2494 0, 48, 12, 60, 3, 51, 15, 63,
2495 32, 16, 44, 28, 35, 19, 47, 31,
2496 8, 56, 4, 52, 11, 59, 7, 55,
2497 40, 24, 36, 20, 43, 27, 39, 23,
2498 2, 50, 14, 62, 1, 49, 13, 61,
2499 34, 18, 46, 30, 33, 17, 45, 29,
2500 10, 58, 6, 54, 9, 57, 5, 53,
2501 42, 26, 38, 22, 41, 25, 37, 21
2504 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2509 index=x+DitherMatrix[x & 0x07]-32L;
2512 if (index >= (ssize_t) columns)
2513 return((ssize_t) columns-1L);
2517 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2522 index=y+DitherMatrix[y & 0x07]-32L;
2525 if (index >= (ssize_t) rows)
2526 return((ssize_t) rows-1L);
2530 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2534 if (x >= (ssize_t) columns)
2535 return((ssize_t) (columns-1));
2539 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2543 if (y >= (ssize_t) rows)
2544 return((ssize_t) (rows-1));
2548 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2550 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2553 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2555 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2558 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2559 const size_t extent)
2565 Compute the remainder of dividing offset by extent. It returns not only
2566 the quotient (tile the offset falls in) but also the positive remainer
2567 within that tile such that 0 <= remainder < extent. This method is
2568 essentially a ldiv() using a floored modulo division rather than the
2569 normal default truncated modulo division.
2571 modulo.quotient=offset/(ssize_t) extent;
2574 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2578 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2579 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2580 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2581 ExceptionInfo *exception)
2584 *magick_restrict cache_info;
2594 **magick_restrict virtual_nexus;
2597 *magick_restrict pixels,
2598 virtual_pixel[MaxPixelChannels];
2603 register const Quantum
2616 register unsigned char
2623 *magick_restrict virtual_metacontent;
2628 assert(image != (const Image *) NULL);
2629 assert(image->signature == MagickCoreSignature);
2630 assert(image->cache != (Cache) NULL);
2631 cache_info=(CacheInfo *) image->cache;
2632 assert(cache_info->signature == MagickCoreSignature);
2633 if (cache_info->type == UndefinedCache)
2634 return((const Quantum *) NULL);
2637 region.width=columns;
2639 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2641 if (pixels == (Quantum *) NULL)
2642 return((const Quantum *) NULL);
2644 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2645 nexus_info->region.x;
2646 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2647 nexus_info->region.width-1L;
2648 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2649 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2650 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2651 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2657 Pixel request is inside cache extents.
2659 if (nexus_info->authentic_pixel_cache != MagickFalse)
2661 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2662 if (status == MagickFalse)
2663 return((const Quantum *) NULL);
2664 if (cache_info->metacontent_extent != 0)
2666 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2667 if (status == MagickFalse)
2668 return((const Quantum *) NULL);
2673 Pixel request is outside cache extents.
2675 s=(unsigned char *) nexus_info->metacontent;
2676 virtual_nexus=AcquirePixelCacheNexus(1);
2677 if (virtual_nexus == (NexusInfo **) NULL)
2679 if (virtual_nexus != (NexusInfo **) NULL)
2680 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2681 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2682 "UnableToGetCacheNexus","`%s'",image->filename);
2683 return((const Quantum *) NULL);
2685 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2686 sizeof(*virtual_pixel));
2687 virtual_metacontent=(void *) NULL;
2688 switch (virtual_pixel_method)
2690 case BackgroundVirtualPixelMethod:
2691 case BlackVirtualPixelMethod:
2692 case GrayVirtualPixelMethod:
2693 case TransparentVirtualPixelMethod:
2694 case MaskVirtualPixelMethod:
2695 case WhiteVirtualPixelMethod:
2696 case EdgeVirtualPixelMethod:
2697 case CheckerTileVirtualPixelMethod:
2698 case HorizontalTileVirtualPixelMethod:
2699 case VerticalTileVirtualPixelMethod:
2701 if (cache_info->metacontent_extent != 0)
2704 Acquire a metacontent buffer.
2706 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2707 cache_info->metacontent_extent);
2708 if (virtual_metacontent == (void *) NULL)
2710 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2711 (void) ThrowMagickException(exception,GetMagickModule(),
2712 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2713 return((const Quantum *) NULL);
2715 (void) ResetMagickMemory(virtual_metacontent,0,
2716 cache_info->metacontent_extent);
2718 switch (virtual_pixel_method)
2720 case BlackVirtualPixelMethod:
2722 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2723 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2724 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2727 case GrayVirtualPixelMethod:
2729 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2730 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2732 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2735 case TransparentVirtualPixelMethod:
2737 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2738 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2739 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2742 case MaskVirtualPixelMethod:
2743 case WhiteVirtualPixelMethod:
2745 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2746 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2747 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2752 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2754 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2756 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2758 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2760 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2770 for (v=0; v < (ssize_t) rows; v++)
2776 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2777 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2778 y_offset=EdgeY(y_offset,cache_info->rows);
2779 for (u=0; u < (ssize_t) columns; u+=length)
2785 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2786 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2787 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2795 Transfer a single pixel.
2797 length=(MagickSizeType) 1;
2798 switch (virtual_pixel_method)
2800 case EdgeVirtualPixelMethod:
2803 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2804 EdgeX(x_offset,cache_info->columns),
2805 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2807 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2810 case RandomVirtualPixelMethod:
2812 if (cache_info->random_info == (RandomInfo *) NULL)
2813 cache_info->random_info=AcquireRandomInfo();
2814 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2815 RandomX(cache_info->random_info,cache_info->columns),
2816 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2817 *virtual_nexus,exception);
2818 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2821 case DitherVirtualPixelMethod:
2823 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2824 DitherX(x_offset,cache_info->columns),
2825 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2827 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2830 case TileVirtualPixelMethod:
2832 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2833 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2834 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2835 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2837 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2840 case MirrorVirtualPixelMethod:
2842 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2843 if ((x_modulo.quotient & 0x01) == 1L)
2844 x_modulo.remainder=(ssize_t) cache_info->columns-
2845 x_modulo.remainder-1L;
2846 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2847 if ((y_modulo.quotient & 0x01) == 1L)
2848 y_modulo.remainder=(ssize_t) cache_info->rows-
2849 y_modulo.remainder-1L;
2850 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2851 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2853 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2856 case HorizontalTileEdgeVirtualPixelMethod:
2858 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2859 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2860 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2861 *virtual_nexus,exception);
2862 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2865 case VerticalTileEdgeVirtualPixelMethod:
2867 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2868 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2869 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2870 *virtual_nexus,exception);
2871 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2874 case BackgroundVirtualPixelMethod:
2875 case BlackVirtualPixelMethod:
2876 case GrayVirtualPixelMethod:
2877 case TransparentVirtualPixelMethod:
2878 case MaskVirtualPixelMethod:
2879 case WhiteVirtualPixelMethod:
2882 r=virtual_metacontent;
2885 case CheckerTileVirtualPixelMethod:
2887 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2888 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2889 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2892 r=virtual_metacontent;
2895 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2896 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2898 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2901 case HorizontalTileVirtualPixelMethod:
2903 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2906 r=virtual_metacontent;
2909 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2910 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2911 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2912 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2914 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2917 case VerticalTileVirtualPixelMethod:
2919 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2922 r=virtual_metacontent;
2925 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2926 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2927 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2928 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2930 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2934 if (p == (const Quantum *) NULL)
2936 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2938 q+=cache_info->number_channels;
2939 if ((s != (void *) NULL) && (r != (const void *) NULL))
2941 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2942 s+=cache_info->metacontent_extent;
2947 Transfer a run of pixels.
2949 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2950 (size_t) length,1UL,*virtual_nexus,exception);
2951 if (p == (const Quantum *) NULL)
2953 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2954 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2955 q+=length*cache_info->number_channels;
2956 if ((r != (void *) NULL) && (s != (const void *) NULL))
2958 (void) memcpy(s,r,(size_t) length);
2959 s+=length*cache_info->metacontent_extent;
2962 if (u < (ssize_t) columns)
2968 if (virtual_metacontent != (void *) NULL)
2969 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2970 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2971 if (v < (ssize_t) rows)
2972 return((const Quantum *) NULL);
2977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2981 + G e t V i r t u a l P i x e l C a c h e %
2985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2987 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2988 % cache as defined by the geometry parameters. A pointer to the pixels
2989 % is returned if the pixels are transferred, otherwise a NULL is returned.
2991 % The format of the GetVirtualPixelCache() method is:
2993 % const Quantum *GetVirtualPixelCache(const Image *image,
2994 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2995 % const ssize_t y,const size_t columns,const size_t rows,
2996 % ExceptionInfo *exception)
2998 % A description of each parameter follows:
3000 % o image: the image.
3002 % o virtual_pixel_method: the virtual pixel method.
3004 % o x,y,columns,rows: These values define the perimeter of a region of
3007 % o exception: return any errors or warnings in this structure.
3010 static const Quantum *GetVirtualPixelCache(const Image *image,
3011 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3012 const size_t columns,const size_t rows,ExceptionInfo *exception)
3015 *magick_restrict cache_info;
3018 id = GetOpenMPThreadId();
3023 assert(image != (const Image *) NULL);
3024 assert(image->signature == MagickCoreSignature);
3025 assert(image->cache != (Cache) NULL);
3026 cache_info=(CacheInfo *) image->cache;
3027 assert(cache_info->signature == MagickCoreSignature);
3028 assert(id < (int) cache_info->number_threads);
3029 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3030 cache_info->nexus_info[id],exception);
3035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3039 % G e t V i r t u a l P i x e l Q u e u e %
3043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3045 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3046 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3048 % The format of the GetVirtualPixelQueue() method is:
3050 % const Quantum *GetVirtualPixelQueue(const Image image)
3052 % A description of each parameter follows:
3054 % o image: the image.
3057 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3060 *magick_restrict cache_info;
3063 id = GetOpenMPThreadId();
3065 assert(image != (const Image *) NULL);
3066 assert(image->signature == MagickCoreSignature);
3067 assert(image->cache != (Cache) NULL);
3068 cache_info=(CacheInfo *) image->cache;
3069 assert(cache_info->signature == MagickCoreSignature);
3070 if (cache_info->methods.get_virtual_pixels_handler !=
3071 (GetVirtualPixelsHandler) NULL)
3072 return(cache_info->methods.get_virtual_pixels_handler(image));
3073 assert(id < (int) cache_info->number_threads);
3074 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3082 % G e t V i r t u a l P i x e l s %
3086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3088 % GetVirtualPixels() returns an immutable pixel region. If the
3089 % region is successfully accessed, a pointer to it is returned, otherwise
3090 % NULL is returned. The returned pointer may point to a temporary working
3091 % copy of the pixels or it may point to the original pixels in memory.
3092 % Performance is maximized if the selected region is part of one row, or one
3093 % or more full rows, since there is opportunity to access the pixels in-place
3094 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3095 % returned pointer must *never* be deallocated by the user.
3097 % Pixels accessed via the returned pointer represent a simple array of type
3098 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3099 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3100 % access the meta-content (of type void) corresponding to the the
3103 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3105 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3106 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3107 % GetCacheViewAuthenticPixels() instead.
3109 % The format of the GetVirtualPixels() method is:
3111 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3112 % const ssize_t y,const size_t columns,const size_t rows,
3113 % ExceptionInfo *exception)
3115 % A description of each parameter follows:
3117 % o image: the image.
3119 % o x,y,columns,rows: These values define the perimeter of a region of
3122 % o exception: return any errors or warnings in this structure.
3125 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3126 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3127 ExceptionInfo *exception)
3130 *magick_restrict cache_info;
3133 id = GetOpenMPThreadId();
3138 assert(image != (const Image *) NULL);
3139 assert(image->signature == MagickCoreSignature);
3140 assert(image->cache != (Cache) NULL);
3141 cache_info=(CacheInfo *) image->cache;
3142 assert(cache_info->signature == MagickCoreSignature);
3143 if (cache_info->methods.get_virtual_pixel_handler !=
3144 (GetVirtualPixelHandler) NULL)
3145 return(cache_info->methods.get_virtual_pixel_handler(image,
3146 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3147 assert(id < (int) cache_info->number_threads);
3148 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3149 columns,rows,cache_info->nexus_info[id],exception);
3154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3158 + 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 %
3162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3164 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3165 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3167 % The format of the GetVirtualPixelsCache() method is:
3169 % Quantum *GetVirtualPixelsCache(const Image *image)
3171 % A description of each parameter follows:
3173 % o image: the image.
3176 static const Quantum *GetVirtualPixelsCache(const Image *image)
3179 *magick_restrict cache_info;
3182 id = GetOpenMPThreadId();
3184 assert(image != (const Image *) NULL);
3185 assert(image->signature == MagickCoreSignature);
3186 assert(image->cache != (Cache) NULL);
3187 cache_info=(CacheInfo *) image->cache;
3188 assert(cache_info->signature == MagickCoreSignature);
3189 assert(id < (int) cache_info->number_threads);
3190 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3198 + G e t V i r t u a l P i x e l s N e x u s %
3202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3204 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3207 % The format of the GetVirtualPixelsNexus() method is:
3209 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3210 % NexusInfo *nexus_info)
3212 % A description of each parameter follows:
3214 % o cache: the pixel cache.
3216 % o nexus_info: the cache nexus to return the colormap pixels.
3219 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3220 NexusInfo *magick_restrict nexus_info)
3223 *magick_restrict cache_info;
3225 assert(cache != (Cache) NULL);
3226 cache_info=(CacheInfo *) cache;
3227 assert(cache_info->signature == MagickCoreSignature);
3228 if (cache_info->storage_class == UndefinedClass)
3229 return((Quantum *) NULL);
3230 return((const Quantum *) nexus_info->pixels);
3234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3238 + O p e n P i x e l C a c h e %
3242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3244 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3245 % dimensions, allocating space for the image pixels and optionally the
3246 % metacontent, and memory mapping the cache if it is disk based. The cache
3247 % nexus array is initialized as well.
3249 % The format of the OpenPixelCache() method is:
3251 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3252 % ExceptionInfo *exception)
3254 % A description of each parameter follows:
3256 % o image: the image.
3258 % o mode: ReadMode, WriteMode, or IOMode.
3260 % o exception: return any errors or warnings in this structure.
3264 #if defined(__cplusplus) || defined(c_plusplus)
3269 static void CacheSignalHandler(int status)
3271 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3275 #if defined(__cplusplus) || defined(c_plusplus)
3279 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3286 Open pixel cache on disk.
3288 if ((cache_info->file != -1) && (cache_info->mode == mode))
3289 return(MagickTrue); /* cache already open and in the proper mode */
3290 if (*cache_info->cache_filename == '\0')
3291 file=AcquireUniqueFileResource(cache_info->cache_filename);
3297 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3302 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3303 O_BINARY | O_EXCL,S_MODE);
3305 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3311 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3314 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3319 return(MagickFalse);
3320 (void) AcquireMagickResource(FileResource,1);
3321 if (cache_info->file != -1)
3322 (void) ClosePixelCacheOnDisk(cache_info);
3323 cache_info->file=file;
3327 static inline MagickOffsetType WritePixelCacheRegion(
3328 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3329 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3331 register MagickOffsetType
3337 #if !defined(MAGICKCORE_HAVE_PWRITE)
3338 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3339 return((MagickOffsetType) -1);
3342 for (i=0; i < (MagickOffsetType) length; i+=count)
3344 #if !defined(MAGICKCORE_HAVE_PWRITE)
3345 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3348 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3349 SSIZE_MAX),(off_t) (offset+i));
3361 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3364 *magick_restrict cache_info;
3371 cache_info=(CacheInfo *) image->cache;
3372 if (image->debug != MagickFalse)
3375 format[MagickPathExtent],
3376 message[MagickPathExtent];
3378 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3379 (void) FormatLocaleString(message,MagickPathExtent,
3380 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3381 cache_info->cache_filename,cache_info->file,format);
3382 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3384 if (length != (MagickSizeType) ((MagickOffsetType) length))
3385 return(MagickFalse);
3386 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3388 return(MagickFalse);
3389 if ((MagickSizeType) offset >= length)
3390 count=(MagickOffsetType) 1;
3393 extent=(MagickOffsetType) length-1;
3394 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3397 return(MagickFalse);
3398 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3399 if (cache_info->synchronize != MagickFalse)
3400 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3403 (void) signal(SIGBUS,CacheSignalHandler);
3406 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3408 return(MagickFalse);
3412 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3413 ExceptionInfo *exception)
3416 *magick_restrict cache_info,
3420 format[MagickPathExtent],
3421 message[MagickPathExtent];
3437 assert(image != (const Image *) NULL);
3438 assert(image->signature == MagickCoreSignature);
3439 assert(image->cache != (Cache) NULL);
3440 if (image->debug != MagickFalse)
3441 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3442 if (cache_anonymous_memory < 0)
3448 Does the security policy require anonymous mapping for pixel cache?
3450 cache_anonymous_memory=0;
3451 value=GetPolicyValue("pixel-cache-memory");
3452 if (LocaleCompare(value,"anonymous") == 0)
3454 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3455 cache_anonymous_memory=1;
3457 (void) ThrowMagickException(exception,GetMagickModule(),
3458 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3459 "'%s' (policy requires anonymous memory mapping)",image->filename);
3462 value=DestroyString(value);
3464 if ((image->columns == 0) || (image->rows == 0))
3465 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3466 cache_info=(CacheInfo *) image->cache;
3467 assert(cache_info->signature == MagickCoreSignature);
3468 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3469 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3470 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3472 source_info=(*cache_info);
3473 source_info.file=(-1);
3474 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3475 image->filename,(double) GetImageIndexInList(image));
3476 cache_info->storage_class=image->storage_class;
3477 cache_info->colorspace=image->colorspace;
3478 cache_info->alpha_trait=image->alpha_trait;
3479 cache_info->read_mask=image->read_mask;
3480 cache_info->write_mask=image->write_mask;
3481 cache_info->rows=image->rows;
3482 cache_info->columns=image->columns;
3483 InitializePixelChannelMap(image);
3484 cache_info->number_channels=GetPixelChannels(image);
3485 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3486 sizeof(*image->channel_map));
3487 cache_info->metacontent_extent=image->metacontent_extent;
3488 cache_info->mode=mode;
3489 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3490 packet_size=cache_info->number_channels*sizeof(Quantum);
3491 if (image->metacontent_extent != 0)
3492 packet_size+=cache_info->metacontent_extent;
3493 length=number_pixels*packet_size;
3494 columns=(size_t) (length/cache_info->rows/packet_size);
3495 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3496 ((ssize_t) cache_info->rows < 0))
3497 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3499 cache_info->length=length;
3500 if (image->ping != MagickFalse)
3502 cache_info->storage_class=image->storage_class;
3503 cache_info->colorspace=image->colorspace;
3504 cache_info->type=PingCache;
3507 status=AcquireMagickResource(AreaResource,cache_info->length);
3508 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3509 cache_info->metacontent_extent);
3510 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3512 status=AcquireMagickResource(MemoryResource,cache_info->length);
3513 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3514 (cache_info->type == MemoryCache))
3517 if (cache_anonymous_memory <= 0)
3519 cache_info->mapped=MagickFalse;
3520 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3521 AcquireAlignedMemory(1,(size_t) cache_info->length));
3525 cache_info->mapped=MagickTrue;
3526 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3527 cache_info->length);
3529 if (cache_info->pixels == (Quantum *) NULL)
3530 cache_info->pixels=source_info.pixels;
3534 Create memory pixel cache.
3536 cache_info->type=MemoryCache;
3537 cache_info->metacontent=(void *) NULL;
3538 if (cache_info->metacontent_extent != 0)
3539 cache_info->metacontent=(void *) (cache_info->pixels+
3540 number_pixels*cache_info->number_channels);
3541 if ((source_info.storage_class != UndefinedClass) &&
3544 status=ClonePixelCacheRepository(cache_info,&source_info,
3546 RelinquishPixelCachePixels(&source_info);
3548 if (image->debug != MagickFalse)
3550 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3551 MagickPathExtent,format);
3552 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3554 (void) FormatLocaleString(message,MagickPathExtent,
3555 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3556 cache_info->filename,cache_info->mapped != MagickFalse ?
3557 "Anonymous" : "Heap",type,(double) cache_info->columns,
3558 (double) cache_info->rows,(double)
3559 cache_info->number_channels,format);
3560 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3563 return(status == 0 ? MagickFalse : MagickTrue);
3566 RelinquishMagickResource(MemoryResource,cache_info->length);
3569 Create pixel cache on disk.
3571 status=AcquireMagickResource(DiskResource,cache_info->length);
3572 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3577 if (cache_info->type == DistributedCache)
3578 RelinquishMagickResource(DiskResource,cache_info->length);
3579 server_info=AcquireDistributeCacheInfo(exception);
3580 if (server_info != (DistributeCacheInfo *) NULL)
3582 status=OpenDistributePixelCache(server_info,image);
3583 if (status == MagickFalse)
3585 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3586 GetDistributeCacheHostname(server_info));
3587 server_info=DestroyDistributeCacheInfo(server_info);
3592 Create a distributed pixel cache.
3595 cache_info->type=DistributedCache;
3596 cache_info->server_info=server_info;
3597 (void) FormatLocaleString(cache_info->cache_filename,
3598 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3599 (DistributeCacheInfo *) cache_info->server_info),
3600 GetDistributeCachePort((DistributeCacheInfo *)
3601 cache_info->server_info));
3602 if ((source_info.storage_class != UndefinedClass) &&
3605 status=ClonePixelCacheRepository(cache_info,&source_info,
3607 RelinquishPixelCachePixels(&source_info);
3609 if (image->debug != MagickFalse)
3611 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3612 MagickPathExtent,format);
3613 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3615 (void) FormatLocaleString(message,MagickPathExtent,
3616 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3617 cache_info->filename,cache_info->cache_filename,
3618 GetDistributeCacheFile((DistributeCacheInfo *)
3619 cache_info->server_info),type,(double) cache_info->columns,
3620 (double) cache_info->rows,(double)
3621 cache_info->number_channels,format);
3622 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3625 return(status == 0 ? MagickFalse : MagickTrue);
3628 RelinquishMagickResource(DiskResource,cache_info->length);
3629 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3630 "CacheResourcesExhausted","`%s'",image->filename);
3631 return(MagickFalse);
3633 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3635 (void) ClosePixelCacheOnDisk(cache_info);
3636 *cache_info->cache_filename='\0';
3638 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3640 RelinquishMagickResource(DiskResource,cache_info->length);
3641 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3643 return(MagickFalse);
3645 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3646 cache_info->length);
3647 if (status == MagickFalse)
3649 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3651 return(MagickFalse);
3653 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3654 cache_info->metacontent_extent);
3655 if (length != (MagickSizeType) ((size_t) length))
3656 cache_info->type=DiskCache;
3659 status=AcquireMagickResource(MapResource,cache_info->length);
3660 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3661 (cache_info->type != MemoryCache))
3664 cache_info->type=DiskCache;
3669 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3670 cache_info->offset,(size_t) cache_info->length);
3671 if (cache_info->pixels == (Quantum *) NULL)
3673 cache_info->type=DiskCache;
3674 cache_info->pixels=source_info.pixels;
3679 Create file-backed memory-mapped pixel cache.
3681 (void) ClosePixelCacheOnDisk(cache_info);
3682 cache_info->type=MapCache;
3683 cache_info->mapped=MagickTrue;
3684 cache_info->metacontent=(void *) NULL;
3685 if (cache_info->metacontent_extent != 0)
3686 cache_info->metacontent=(void *) (cache_info->pixels+
3687 number_pixels*cache_info->number_channels);
3688 if ((source_info.storage_class != UndefinedClass) &&
3691 status=ClonePixelCacheRepository(cache_info,&source_info,
3693 RelinquishPixelCachePixels(&source_info);
3695 if (image->debug != MagickFalse)
3697 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3698 MagickPathExtent,format);
3699 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3701 (void) FormatLocaleString(message,MagickPathExtent,
3702 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3703 cache_info->filename,cache_info->cache_filename,
3704 cache_info->file,type,(double) cache_info->columns,(double)
3705 cache_info->rows,(double) cache_info->number_channels,
3707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3710 return(status == 0 ? MagickFalse : MagickTrue);
3713 RelinquishMagickResource(MapResource,cache_info->length);
3716 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3718 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3719 RelinquishPixelCachePixels(&source_info);
3721 if (image->debug != MagickFalse)
3723 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3724 MagickPathExtent,format);
3725 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3727 (void) FormatLocaleString(message,MagickPathExtent,
3728 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3729 cache_info->cache_filename,cache_info->file,type,(double)
3730 cache_info->columns,(double) cache_info->rows,(double)
3731 cache_info->number_channels,format);
3732 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3734 return(status == 0 ? MagickFalse : MagickTrue);
3738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3742 + P e r s i s t P i x e l C a c h e %
3746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3748 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3749 % persistent pixel cache is one that resides on disk and is not destroyed
3750 % when the program exits.
3752 % The format of the PersistPixelCache() method is:
3754 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3755 % const MagickBooleanType attach,MagickOffsetType *offset,
3756 % ExceptionInfo *exception)
3758 % A description of each parameter follows:
3760 % o image: the image.
3762 % o filename: the persistent pixel cache filename.
3764 % o attach: A value other than zero initializes the persistent pixel cache.
3766 % o initialize: A value other than zero initializes the persistent pixel
3769 % o offset: the offset in the persistent cache to store pixels.
3771 % o exception: return any errors or warnings in this structure.
3774 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3775 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3776 ExceptionInfo *exception)
3779 *magick_restrict cache_info,
3780 *magick_restrict clone_info;
3791 assert(image != (Image *) NULL);
3792 assert(image->signature == MagickCoreSignature);
3793 if (image->debug != MagickFalse)
3794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3795 assert(image->cache != (void *) NULL);
3796 assert(filename != (const char *) NULL);
3797 assert(offset != (MagickOffsetType *) NULL);
3798 page_size=GetMagickPageSize();
3799 cache_info=(CacheInfo *) image->cache;
3800 assert(cache_info->signature == MagickCoreSignature);
3801 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3802 CopyOpenCLBuffer(cache_info);
3804 if (attach != MagickFalse)
3807 Attach existing persistent pixel cache.
3809 if (image->debug != MagickFalse)
3810 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3811 "attach persistent cache");
3812 (void) CopyMagickString(cache_info->cache_filename,filename,
3814 cache_info->type=DiskCache;
3815 cache_info->offset=(*offset);
3816 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3817 return(MagickFalse);
3818 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3821 if ((cache_info->mode != ReadMode) &&
3822 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3823 (cache_info->reference_count == 1))
3825 LockSemaphoreInfo(cache_info->semaphore);
3826 if ((cache_info->mode != ReadMode) &&
3827 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3828 (cache_info->reference_count == 1))
3831 Usurp existing persistent pixel cache.
3833 if (rename_utf8(cache_info->cache_filename, filename) == 0)
3835 (void) CopyMagickString(cache_info->cache_filename,filename,
3837 *offset+=cache_info->length+page_size-(cache_info->length %
3839 UnlockSemaphoreInfo(cache_info->semaphore);
3840 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3841 if (image->debug != MagickFalse)
3842 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3843 "Usurp resident persistent cache");
3847 UnlockSemaphoreInfo(cache_info->semaphore);
3850 Clone persistent pixel cache.
3852 clone_image=(*image);
3853 clone_info=(CacheInfo *) clone_image.cache;
3854 image->cache=ClonePixelCache(cache_info);
3855 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3856 (void) CopyMagickString(cache_info->cache_filename,filename,MagickPathExtent);
3857 cache_info->type=DiskCache;
3858 cache_info->offset=(*offset);
3859 cache_info=(CacheInfo *) image->cache;
3860 status=OpenPixelCache(image,IOMode,exception);
3861 if (status != MagickFalse)
3862 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3863 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3864 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3873 + 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 %
3877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3879 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3880 % defined by the region rectangle and returns a pointer to the region. This
3881 % region is subsequently transferred from the pixel cache with
3882 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3883 % pixels are transferred, otherwise a NULL is returned.
3885 % The format of the QueueAuthenticPixelCacheNexus() method is:
3887 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3888 % const ssize_t y,const size_t columns,const size_t rows,
3889 % const MagickBooleanType clone,NexusInfo *nexus_info,
3890 % ExceptionInfo *exception)
3892 % A description of each parameter follows:
3894 % o image: the image.
3896 % o x,y,columns,rows: These values define the perimeter of a region of
3899 % o nexus_info: the cache nexus to set.
3901 % o clone: clone the pixel cache.
3903 % o exception: return any errors or warnings in this structure.
3906 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3907 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3908 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3911 *magick_restrict cache_info;
3920 *magick_restrict pixels;
3926 Validate pixel cache geometry.
3928 assert(image != (const Image *) NULL);
3929 assert(image->signature == MagickCoreSignature);
3930 assert(image->cache != (Cache) NULL);
3931 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3932 if (cache_info == (Cache) NULL)
3933 return((Quantum *) NULL);
3934 assert(cache_info->signature == MagickCoreSignature);
3935 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3936 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3937 (y >= (ssize_t) cache_info->rows))
3939 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3940 "PixelsAreNotAuthentic","`%s'",image->filename);
3941 return((Quantum *) NULL);
3943 offset=(MagickOffsetType) y*cache_info->columns+x;
3945 return((Quantum *) NULL);
3946 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3947 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3948 if ((MagickSizeType) offset >= number_pixels)
3949 return((Quantum *) NULL);
3955 region.width=columns;
3957 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967 + 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 %
3971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3973 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3974 % defined by the region rectangle and returns a pointer to the region. This
3975 % region is subsequently transferred from the pixel cache with
3976 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3977 % pixels are transferred, otherwise a NULL is returned.
3979 % The format of the QueueAuthenticPixelsCache() method is:
3981 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3982 % const ssize_t y,const size_t columns,const size_t rows,
3983 % ExceptionInfo *exception)
3985 % A description of each parameter follows:
3987 % o image: the image.
3989 % o x,y,columns,rows: These values define the perimeter of a region of
3992 % o exception: return any errors or warnings in this structure.
3995 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3996 const ssize_t y,const size_t columns,const size_t rows,
3997 ExceptionInfo *exception)
4000 *magick_restrict cache_info;
4003 id = GetOpenMPThreadId();
4006 *magick_restrict pixels;
4008 assert(image != (const Image *) NULL);
4009 assert(image->signature == MagickCoreSignature);
4010 assert(image->cache != (Cache) NULL);
4011 cache_info=(CacheInfo *) image->cache;
4012 assert(cache_info->signature == MagickCoreSignature);
4013 assert(id < (int) cache_info->number_threads);
4014 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4015 cache_info->nexus_info[id],exception);
4020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4024 % Q u e u e A u t h e n t i c P i x e l s %
4028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4030 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4031 % successfully initialized a pointer to a Quantum array representing the
4032 % region is returned, otherwise NULL is returned. The returned pointer may
4033 % point to a temporary working buffer for the pixels or it may point to the
4034 % final location of the pixels in memory.
4036 % Write-only access means that any existing pixel values corresponding to
4037 % the region are ignored. This is useful if the initial image is being
4038 % created from scratch, or if the existing pixel values are to be
4039 % completely replaced without need to refer to their pre-existing values.
4040 % The application is free to read and write the pixel buffer returned by
4041 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4042 % initialize the pixel array values. Initializing pixel array values is the
4043 % application's responsibility.
4045 % Performance is maximized if the selected region is part of one row, or
4046 % one or more full rows, since then there is opportunity to access the
4047 % pixels in-place (without a copy) if the image is in memory, or in a
4048 % memory-mapped file. The returned pointer must *never* be deallocated
4051 % Pixels accessed via the returned pointer represent a simple array of type
4052 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4053 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4054 % obtain the meta-content (of type void) corresponding to the region.
4055 % Once the Quantum (and/or Quantum) array has been updated, the
4056 % changes must be saved back to the underlying image using
4057 % SyncAuthenticPixels() or they may be lost.
4059 % The format of the QueueAuthenticPixels() method is:
4061 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4062 % const ssize_t y,const size_t columns,const size_t rows,
4063 % ExceptionInfo *exception)
4065 % A description of each parameter follows:
4067 % o image: the image.
4069 % o x,y,columns,rows: These values define the perimeter of a region of
4072 % o exception: return any errors or warnings in this structure.
4075 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4076 const ssize_t y,const size_t columns,const size_t rows,
4077 ExceptionInfo *exception)
4080 *magick_restrict cache_info;
4083 id = GetOpenMPThreadId();
4086 *magick_restrict pixels;
4088 assert(image != (Image *) NULL);
4089 assert(image->signature == MagickCoreSignature);
4090 assert(image->cache != (Cache) NULL);
4091 cache_info=(CacheInfo *) image->cache;
4092 assert(cache_info->signature == MagickCoreSignature);
4093 if (cache_info->methods.queue_authentic_pixels_handler !=
4094 (QueueAuthenticPixelsHandler) NULL)
4096 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4097 columns,rows,exception);
4100 assert(id < (int) cache_info->number_threads);
4101 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4102 cache_info->nexus_info[id],exception);
4107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4111 + 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 %
4115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4117 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4120 % The format of the ReadPixelCacheMetacontent() method is:
4122 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4123 % NexusInfo *nexus_info,ExceptionInfo *exception)
4125 % A description of each parameter follows:
4127 % o cache_info: the pixel cache.
4129 % o nexus_info: the cache nexus to read the metacontent.
4131 % o exception: return any errors or warnings in this structure.
4135 static inline MagickOffsetType ReadPixelCacheRegion(
4136 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4137 const MagickSizeType length,unsigned char *magick_restrict buffer)
4139 register MagickOffsetType
4145 #if !defined(MAGICKCORE_HAVE_PREAD)
4146 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4147 return((MagickOffsetType) -1);
4150 for (i=0; i < (MagickOffsetType) length; i+=count)
4152 #if !defined(MAGICKCORE_HAVE_PREAD)
4153 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4156 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4157 SSIZE_MAX),(off_t) (offset+i));
4169 static MagickBooleanType ReadPixelCacheMetacontent(
4170 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4171 ExceptionInfo *exception)
4184 register unsigned char
4190 if (cache_info->metacontent_extent == 0)
4191 return(MagickFalse);
4192 if (nexus_info->authentic_pixel_cache != MagickFalse)
4194 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4195 nexus_info->region.x;
4196 length=(MagickSizeType) nexus_info->region.width*
4197 cache_info->metacontent_extent;
4198 extent=length*nexus_info->region.height;
4199 rows=nexus_info->region.height;
4201 q=(unsigned char *) nexus_info->metacontent;
4202 switch (cache_info->type)
4207 register unsigned char
4211 Read meta-content from memory.
4213 if ((cache_info->columns == nexus_info->region.width) &&
4214 (extent == (MagickSizeType) ((size_t) extent)))
4219 p=(unsigned char *) cache_info->metacontent+offset*
4220 cache_info->metacontent_extent;
4221 for (y=0; y < (ssize_t) rows; y++)
4223 (void) memcpy(q,p,(size_t) length);
4224 p+=cache_info->metacontent_extent*cache_info->columns;
4225 q+=cache_info->metacontent_extent*nexus_info->region.width;
4232 Read meta content from disk.
4234 LockSemaphoreInfo(cache_info->file_semaphore);
4235 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4237 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4238 cache_info->cache_filename);
4239 UnlockSemaphoreInfo(cache_info->file_semaphore);
4240 return(MagickFalse);
4242 if ((cache_info->columns == nexus_info->region.width) &&
4243 (extent <= MagickMaxBufferExtent))
4248 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4249 for (y=0; y < (ssize_t) rows; y++)
4251 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4252 cache_info->number_channels*sizeof(Quantum)+offset*
4253 cache_info->metacontent_extent,length,(unsigned char *) q);
4254 if (count != (MagickOffsetType) length)
4256 offset+=cache_info->columns;
4257 q+=cache_info->metacontent_extent*nexus_info->region.width;
4259 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4260 (void) ClosePixelCacheOnDisk(cache_info);
4261 UnlockSemaphoreInfo(cache_info->file_semaphore);
4264 case DistributedCache:
4270 Read metacontent from distributed cache.
4272 LockSemaphoreInfo(cache_info->file_semaphore);
4273 region=nexus_info->region;
4274 if ((cache_info->columns != nexus_info->region.width) ||
4275 (extent > MagickMaxBufferExtent))
4282 for (y=0; y < (ssize_t) rows; y++)
4284 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4285 cache_info->server_info,®ion,length,(unsigned char *) q);
4286 if (count != (MagickOffsetType) length)
4288 q+=cache_info->metacontent_extent*nexus_info->region.width;
4291 UnlockSemaphoreInfo(cache_info->file_semaphore);
4297 if (y < (ssize_t) rows)
4299 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4300 cache_info->cache_filename);
4301 return(MagickFalse);
4303 if ((cache_info->debug != MagickFalse) &&
4304 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4305 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4306 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4307 nexus_info->region.width,(double) nexus_info->region.height,(double)
4308 nexus_info->region.x,(double) nexus_info->region.y);
4313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4317 + R e a d P i x e l C a c h e P i x e l s %
4321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4323 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4326 % The format of the ReadPixelCachePixels() method is:
4328 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4329 % NexusInfo *nexus_info,ExceptionInfo *exception)
4331 % A description of each parameter follows:
4333 % o cache_info: the pixel cache.
4335 % o nexus_info: the cache nexus to read the pixels.
4337 % o exception: return any errors or warnings in this structure.
4340 static MagickBooleanType ReadPixelCachePixels(
4341 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4342 ExceptionInfo *exception)
4362 if (nexus_info->authentic_pixel_cache != MagickFalse)
4364 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4365 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4366 return(MagickFalse);
4367 offset+=nexus_info->region.x;
4368 number_channels=cache_info->number_channels;
4369 length=(MagickSizeType) number_channels*nexus_info->region.width*
4371 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4372 return(MagickFalse);
4373 rows=nexus_info->region.height;
4375 if ((extent == 0) || ((extent/length) != rows))
4376 return(MagickFalse);
4378 q=nexus_info->pixels;
4379 switch (cache_info->type)
4388 Read pixels from memory.
4390 if ((cache_info->columns == nexus_info->region.width) &&
4391 (extent == (MagickSizeType) ((size_t) extent)))
4396 p=cache_info->pixels+offset*cache_info->number_channels;
4397 for (y=0; y < (ssize_t) rows; y++)
4399 (void) memcpy(q,p,(size_t) length);
4400 p+=cache_info->number_channels*cache_info->columns;
4401 q+=cache_info->number_channels*nexus_info->region.width;
4408 Read pixels from disk.
4410 LockSemaphoreInfo(cache_info->file_semaphore);
4411 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4413 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4414 cache_info->cache_filename);
4415 UnlockSemaphoreInfo(cache_info->file_semaphore);
4416 return(MagickFalse);
4418 if ((cache_info->columns == nexus_info->region.width) &&
4419 (extent <= MagickMaxBufferExtent))
4424 for (y=0; y < (ssize_t) rows; y++)
4426 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4427 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4428 if (count != (MagickOffsetType) length)
4430 offset+=cache_info->columns;
4431 q+=cache_info->number_channels*nexus_info->region.width;
4433 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4434 (void) ClosePixelCacheOnDisk(cache_info);
4435 UnlockSemaphoreInfo(cache_info->file_semaphore);
4438 case DistributedCache:
4444 Read pixels from distributed cache.
4446 LockSemaphoreInfo(cache_info->file_semaphore);
4447 region=nexus_info->region;
4448 if ((cache_info->columns != nexus_info->region.width) ||
4449 (extent > MagickMaxBufferExtent))
4456 for (y=0; y < (ssize_t) rows; y++)
4458 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4459 cache_info->server_info,®ion,length,(unsigned char *) q);
4460 if (count != (MagickOffsetType) length)
4462 q+=cache_info->number_channels*nexus_info->region.width;
4465 UnlockSemaphoreInfo(cache_info->file_semaphore);
4471 if (y < (ssize_t) rows)
4473 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4474 cache_info->cache_filename);
4475 return(MagickFalse);
4477 if ((cache_info->debug != MagickFalse) &&
4478 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4479 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4480 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4481 nexus_info->region.width,(double) nexus_info->region.height,(double)
4482 nexus_info->region.x,(double) nexus_info->region.y);
4487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4491 + R e f e r e n c e P i x e l C a c h e %
4495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4497 % ReferencePixelCache() increments the reference count associated with the
4498 % pixel cache returning a pointer to the cache.
4500 % The format of the ReferencePixelCache method is:
4502 % Cache ReferencePixelCache(Cache cache_info)
4504 % A description of each parameter follows:
4506 % o cache_info: the pixel cache.
4509 MagickPrivate Cache ReferencePixelCache(Cache cache)
4512 *magick_restrict cache_info;
4514 assert(cache != (Cache *) NULL);
4515 cache_info=(CacheInfo *) cache;
4516 assert(cache_info->signature == MagickCoreSignature);
4517 LockSemaphoreInfo(cache_info->semaphore);
4518 cache_info->reference_count++;
4519 UnlockSemaphoreInfo(cache_info->semaphore);
4524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4528 + R e s e t P i x e l C a c h e C h a n n e l s %
4532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4534 % ResetPixelCacheChannels() resets the pixel cache channels.
4536 % The format of the ResetPixelCacheChannels method is:
4538 % void ResetPixelCacheChannels(Image *)
4540 % A description of each parameter follows:
4542 % o image: the image.
4545 MagickPrivate void ResetPixelCacheChannels(Image *image)
4548 *magick_restrict cache_info;
4550 assert(image != (const Image *) NULL);
4551 assert(image->signature == MagickCoreSignature);
4552 assert(image->cache != (Cache) NULL);
4553 cache_info=(CacheInfo *) image->cache;
4554 assert(cache_info->signature == MagickCoreSignature);
4555 cache_info->number_channels=GetPixelChannels(image);
4559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4563 + R e s e t P i x e l C a c h e E p o c h %
4567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4569 % ResetPixelCacheEpoch() resets the pixel cache epoch.
4571 % The format of the ResetPixelCacheEpoch method is:
4573 % void ResetPixelCacheEpoch(void)
4576 MagickPrivate void ResetPixelCacheEpoch(void)
4582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4586 + S e t P i x e l C a c h e M e t h o d s %
4590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4592 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4594 % The format of the SetPixelCacheMethods() method is:
4596 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4598 % A description of each parameter follows:
4600 % o cache: the pixel cache.
4602 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4605 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4608 *magick_restrict cache_info;
4610 GetOneAuthenticPixelFromHandler
4611 get_one_authentic_pixel_from_handler;
4613 GetOneVirtualPixelFromHandler
4614 get_one_virtual_pixel_from_handler;
4617 Set cache pixel methods.
4619 assert(cache != (Cache) NULL);
4620 assert(cache_methods != (CacheMethods *) NULL);
4621 cache_info=(CacheInfo *) cache;
4622 assert(cache_info->signature == MagickCoreSignature);
4623 if (cache_info->debug != MagickFalse)
4624 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4625 cache_info->filename);
4626 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4627 cache_info->methods.get_virtual_pixel_handler=
4628 cache_methods->get_virtual_pixel_handler;
4629 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4630 cache_info->methods.destroy_pixel_handler=
4631 cache_methods->destroy_pixel_handler;
4632 if (cache_methods->get_virtual_metacontent_from_handler !=
4633 (GetVirtualMetacontentFromHandler) NULL)
4634 cache_info->methods.get_virtual_metacontent_from_handler=
4635 cache_methods->get_virtual_metacontent_from_handler;
4636 if (cache_methods->get_authentic_pixels_handler !=
4637 (GetAuthenticPixelsHandler) NULL)
4638 cache_info->methods.get_authentic_pixels_handler=
4639 cache_methods->get_authentic_pixels_handler;
4640 if (cache_methods->queue_authentic_pixels_handler !=
4641 (QueueAuthenticPixelsHandler) NULL)
4642 cache_info->methods.queue_authentic_pixels_handler=
4643 cache_methods->queue_authentic_pixels_handler;
4644 if (cache_methods->sync_authentic_pixels_handler !=
4645 (SyncAuthenticPixelsHandler) NULL)
4646 cache_info->methods.sync_authentic_pixels_handler=
4647 cache_methods->sync_authentic_pixels_handler;
4648 if (cache_methods->get_authentic_pixels_from_handler !=
4649 (GetAuthenticPixelsFromHandler) NULL)
4650 cache_info->methods.get_authentic_pixels_from_handler=
4651 cache_methods->get_authentic_pixels_from_handler;
4652 if (cache_methods->get_authentic_metacontent_from_handler !=
4653 (GetAuthenticMetacontentFromHandler) NULL)
4654 cache_info->methods.get_authentic_metacontent_from_handler=
4655 cache_methods->get_authentic_metacontent_from_handler;
4656 get_one_virtual_pixel_from_handler=
4657 cache_info->methods.get_one_virtual_pixel_from_handler;
4658 if (get_one_virtual_pixel_from_handler !=
4659 (GetOneVirtualPixelFromHandler) NULL)
4660 cache_info->methods.get_one_virtual_pixel_from_handler=
4661 cache_methods->get_one_virtual_pixel_from_handler;
4662 get_one_authentic_pixel_from_handler=
4663 cache_methods->get_one_authentic_pixel_from_handler;
4664 if (get_one_authentic_pixel_from_handler !=
4665 (GetOneAuthenticPixelFromHandler) NULL)
4666 cache_info->methods.get_one_authentic_pixel_from_handler=
4667 cache_methods->get_one_authentic_pixel_from_handler;
4671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4675 + S e t P i x e l C a c h e N e x u s P i x e l s %
4679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4681 % SetPixelCacheNexusPixels() defines the region of the cache for the
4682 % specified cache nexus.
4684 % The format of the SetPixelCacheNexusPixels() method is:
4686 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4687 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4688 % ExceptionInfo *exception)
4690 % A description of each parameter follows:
4692 % o cache_info: the pixel cache.
4694 % o mode: ReadMode, WriteMode, or IOMode.
4696 % o region: A pointer to the RectangleInfo structure that defines the
4697 % region of this particular cache nexus.
4699 % o nexus_info: the cache nexus to set.
4701 % o exception: return any errors or warnings in this structure.
4705 static inline MagickBooleanType AcquireCacheNexusPixels(
4706 const CacheInfo *magick_restrict cache_info,NexusInfo *nexus_info,
4707 ExceptionInfo *exception)
4709 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4710 return(MagickFalse);
4711 if (cache_anonymous_memory <= 0)
4713 nexus_info->mapped=MagickFalse;
4714 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4715 (size_t) nexus_info->length));
4716 if (nexus_info->cache != (Quantum *) NULL)
4717 ResetMagickMemory(nexus_info->cache,0,(size_t) nexus_info->length);
4721 nexus_info->mapped=MagickTrue;
4722 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4723 nexus_info->length);
4725 if (nexus_info->cache == (Quantum *) NULL)
4727 (void) ThrowMagickException(exception,GetMagickModule(),
4728 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4729 cache_info->filename);
4730 return(MagickFalse);
4735 static inline MagickBooleanType IsPixelCacheAuthentic(
4736 const CacheInfo *magick_restrict cache_info,
4737 const NexusInfo *magick_restrict nexus_info)
4746 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4748 if (cache_info->type == PingCache)
4750 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4751 nexus_info->region.x;
4752 status=nexus_info->pixels == (cache_info->pixels+offset*
4753 cache_info->number_channels) ? MagickTrue : MagickFalse;
4757 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4760 if (mode == ReadMode)
4762 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4765 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4768 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4769 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4770 ExceptionInfo *exception)
4779 assert(cache_info != (const CacheInfo *) NULL);
4780 assert(cache_info->signature == MagickCoreSignature);
4781 if (cache_info->type == UndefinedCache)
4782 return((Quantum *) NULL);
4783 nexus_info->region=(*region);
4784 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4790 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4791 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4792 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4793 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4794 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4795 ((nexus_info->region.width == cache_info->columns) ||
4796 ((nexus_info->region.width % cache_info->columns) == 0)))))
4802 Pixels are accessed directly from memory.
4804 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4805 nexus_info->region.x;
4806 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4808 nexus_info->metacontent=(void *) NULL;
4809 if (cache_info->metacontent_extent != 0)
4810 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4811 offset*cache_info->metacontent_extent;
4812 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4813 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4815 return(nexus_info->pixels);
4819 Pixels are stored in a staging region until they are synced to the cache.
4821 number_pixels=(MagickSizeType) nexus_info->region.width*
4822 nexus_info->region.height;
4823 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4824 if (cache_info->metacontent_extent != 0)
4825 length+=number_pixels*cache_info->metacontent_extent;
4826 if (nexus_info->cache == (Quantum *) NULL)
4828 nexus_info->length=length;
4829 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4830 if (status == MagickFalse)
4832 nexus_info->length=0;
4833 return((Quantum *) NULL);
4837 if (nexus_info->length < length)
4839 RelinquishCacheNexusPixels(nexus_info);
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);
4848 nexus_info->pixels=nexus_info->cache;
4849 nexus_info->metacontent=(void *) NULL;
4850 if (cache_info->metacontent_extent != 0)
4851 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4852 cache_info->number_channels);
4853 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4854 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4856 return(nexus_info->pixels);
4860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4864 % 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 %
4868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4871 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4872 % access that is outside the boundaries of the image cache.
4874 % The format of the SetPixelCacheVirtualMethod() method is:
4876 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4877 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4879 % A description of each parameter follows:
4881 % o image: the image.
4883 % o virtual_pixel_method: choose the type of virtual pixel.
4885 % o exception: return any errors or warnings in this structure.
4889 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4890 ExceptionInfo *exception)
4893 *magick_restrict cache_info;
4896 *magick_restrict image_view;
4904 assert(image != (Image *) NULL);
4905 assert(image->signature == MagickCoreSignature);
4906 if (image->debug != MagickFalse)
4907 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4908 assert(image->cache != (Cache) NULL);
4909 cache_info=(CacheInfo *) image->cache;
4910 assert(cache_info->signature == MagickCoreSignature);
4911 image->alpha_trait=BlendPixelTrait;
4913 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4914 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4915 #pragma omp parallel for schedule(static,4) shared(status) \
4916 magick_threads(image,image,1,1)
4918 for (y=0; y < (ssize_t) image->rows; y++)
4926 if (status == MagickFalse)
4928 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4929 if (q == (Quantum *) NULL)
4934 for (x=0; x < (ssize_t) image->columns; x++)
4936 SetPixelAlpha(image,alpha,q);
4937 q+=GetPixelChannels(image);
4939 status=SyncCacheViewAuthenticPixels(image_view,exception);
4941 image_view=DestroyCacheView(image_view);
4945 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4946 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4949 *magick_restrict cache_info;
4954 assert(image != (Image *) NULL);
4955 assert(image->signature == MagickCoreSignature);
4956 if (image->debug != MagickFalse)
4957 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4958 assert(image->cache != (Cache) NULL);
4959 cache_info=(CacheInfo *) image->cache;
4960 assert(cache_info->signature == MagickCoreSignature);
4961 method=cache_info->virtual_pixel_method;
4962 cache_info->virtual_pixel_method=virtual_pixel_method;
4963 if ((image->columns != 0) && (image->rows != 0))
4964 switch (virtual_pixel_method)
4966 case BackgroundVirtualPixelMethod:
4968 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4969 (image->alpha_trait == UndefinedPixelTrait))
4970 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4971 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4972 (IsGrayColorspace(image->colorspace) != MagickFalse))
4973 (void) SetImageColorspace(image,sRGBColorspace,exception);
4976 case TransparentVirtualPixelMethod:
4978 if (image->alpha_trait == UndefinedPixelTrait)
4979 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4988 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4994 + 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 %
4998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5000 % SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5001 % been completed and updates the host memory.
5003 % The format of the SyncAuthenticOpenCLBuffer() method is:
5005 % void SyncAuthenticOpenCLBuffer(const Image *image)
5007 % A description of each parameter follows:
5009 % o image: the image.
5013 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5015 assert(cache_info != (CacheInfo *) NULL);
5016 assert(cache_info->signature == MagickCoreSignature);
5017 if ((cache_info->type != MemoryCache) ||
5018 (cache_info->opencl == (MagickCLCacheInfo) NULL))
5021 Ensure single threaded access to OpenCL environment.
5023 LockSemaphoreInfo(cache_info->semaphore);
5024 cache_info->opencl=(MagickCLCacheInfo) CopyMagickCLCacheInfo(
5025 cache_info->opencl);
5026 UnlockSemaphoreInfo(cache_info->semaphore);
5029 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5032 *magick_restrict cache_info;
5034 assert(image != (const Image *) NULL);
5035 cache_info=(CacheInfo *) image->cache;
5036 CopyOpenCLBuffer(cache_info);
5041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5045 + 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 %
5049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5051 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5052 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5053 % is synced, otherwise MagickFalse.
5055 % The format of the SyncAuthenticPixelCacheNexus() method is:
5057 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5058 % NexusInfo *nexus_info,ExceptionInfo *exception)
5060 % A description of each parameter follows:
5062 % o image: the image.
5064 % o nexus_info: the cache nexus to sync.
5066 % o exception: return any errors or warnings in this structure.
5069 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5070 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5073 *magick_restrict cache_info;
5079 Transfer pixels to the cache.
5081 assert(image != (Image *) NULL);
5082 assert(image->signature == MagickCoreSignature);
5083 if (image->cache == (Cache) NULL)
5084 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5085 cache_info=(CacheInfo *) image->cache;
5086 assert(cache_info->signature == MagickCoreSignature);
5087 if (cache_info->type == UndefinedCache)
5088 return(MagickFalse);
5089 if (nexus_info->authentic_pixel_cache != MagickFalse)
5091 image->taint=MagickTrue;
5094 assert(cache_info->signature == MagickCoreSignature);
5095 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5096 if ((cache_info->metacontent_extent != 0) &&
5097 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5098 return(MagickFalse);
5099 if (status != MagickFalse)
5100 image->taint=MagickTrue;
5105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5109 + S y n c A u t h e n t i c P i x e l C a c h e %
5113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5115 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5116 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5117 % otherwise MagickFalse.
5119 % The format of the SyncAuthenticPixelsCache() method is:
5121 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5122 % ExceptionInfo *exception)
5124 % A description of each parameter follows:
5126 % o image: the image.
5128 % o exception: return any errors or warnings in this structure.
5131 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5132 ExceptionInfo *exception)
5135 *magick_restrict cache_info;
5138 id = GetOpenMPThreadId();
5143 assert(image != (Image *) NULL);
5144 assert(image->signature == MagickCoreSignature);
5145 assert(image->cache != (Cache) NULL);
5146 cache_info=(CacheInfo *) image->cache;
5147 assert(cache_info->signature == MagickCoreSignature);
5148 assert(id < (int) cache_info->number_threads);
5149 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5159 % S y n c A u t h e n t i c P i x e l s %
5163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5165 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5166 % The method returns MagickTrue if the pixel region is flushed, otherwise
5169 % The format of the SyncAuthenticPixels() method is:
5171 % MagickBooleanType SyncAuthenticPixels(Image *image,
5172 % ExceptionInfo *exception)
5174 % A description of each parameter follows:
5176 % o image: the image.
5178 % o exception: return any errors or warnings in this structure.
5181 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5182 ExceptionInfo *exception)
5185 *magick_restrict cache_info;
5188 id = GetOpenMPThreadId();
5193 assert(image != (Image *) NULL);
5194 assert(image->signature == MagickCoreSignature);
5195 assert(image->cache != (Cache) NULL);
5196 cache_info=(CacheInfo *) image->cache;
5197 assert(cache_info->signature == MagickCoreSignature);
5198 if (cache_info->methods.sync_authentic_pixels_handler !=
5199 (SyncAuthenticPixelsHandler) NULL)
5201 status=cache_info->methods.sync_authentic_pixels_handler(image,
5205 assert(id < (int) cache_info->number_threads);
5206 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5216 + S y n c I m a g e P i x e l C a c h e %
5220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5223 % The method returns MagickTrue if the pixel region is flushed, otherwise
5226 % The format of the SyncImagePixelCache() method is:
5228 % MagickBooleanType SyncImagePixelCache(Image *image,
5229 % ExceptionInfo *exception)
5231 % A description of each parameter follows:
5233 % o image: the image.
5235 % o exception: return any errors or warnings in this structure.
5238 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5239 ExceptionInfo *exception)
5242 *magick_restrict cache_info;
5244 assert(image != (Image *) NULL);
5245 assert(exception != (ExceptionInfo *) NULL);
5246 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5247 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5255 + 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 %
5259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5261 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5262 % of the pixel cache.
5264 % The format of the WritePixelCacheMetacontent() method is:
5266 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5267 % NexusInfo *nexus_info,ExceptionInfo *exception)
5269 % A description of each parameter follows:
5271 % o cache_info: the pixel cache.
5273 % o nexus_info: the cache nexus to write the meta-content.
5275 % o exception: return any errors or warnings in this structure.
5278 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5279 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5289 register const unsigned char
5298 if (cache_info->metacontent_extent == 0)
5299 return(MagickFalse);
5300 if (nexus_info->authentic_pixel_cache != MagickFalse)
5302 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5303 nexus_info->region.x;
5304 length=(MagickSizeType) nexus_info->region.width*
5305 cache_info->metacontent_extent;
5306 extent=(MagickSizeType) length*nexus_info->region.height;
5307 rows=nexus_info->region.height;
5309 p=(unsigned char *) nexus_info->metacontent;
5310 switch (cache_info->type)
5315 register unsigned char
5319 Write associated pixels to memory.
5321 if ((cache_info->columns == nexus_info->region.width) &&
5322 (extent == (MagickSizeType) ((size_t) extent)))
5327 q=(unsigned char *) cache_info->metacontent+offset*
5328 cache_info->metacontent_extent;
5329 for (y=0; y < (ssize_t) rows; y++)
5331 (void) memcpy(q,p,(size_t) length);
5332 p+=nexus_info->region.width*cache_info->metacontent_extent;
5333 q+=cache_info->columns*cache_info->metacontent_extent;
5340 Write associated pixels to disk.
5342 LockSemaphoreInfo(cache_info->file_semaphore);
5343 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5345 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5346 cache_info->cache_filename);
5347 UnlockSemaphoreInfo(cache_info->file_semaphore);
5348 return(MagickFalse);
5350 if ((cache_info->columns == nexus_info->region.width) &&
5351 (extent <= MagickMaxBufferExtent))
5356 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5357 for (y=0; y < (ssize_t) rows; y++)
5359 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5360 cache_info->number_channels*sizeof(Quantum)+offset*
5361 cache_info->metacontent_extent,length,(const unsigned char *) p);
5362 if (count != (MagickOffsetType) length)
5364 p+=cache_info->metacontent_extent*nexus_info->region.width;
5365 offset+=cache_info->columns;
5367 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5368 (void) ClosePixelCacheOnDisk(cache_info);
5369 UnlockSemaphoreInfo(cache_info->file_semaphore);
5372 case DistributedCache:
5378 Write metacontent to distributed cache.
5380 LockSemaphoreInfo(cache_info->file_semaphore);
5381 region=nexus_info->region;
5382 if ((cache_info->columns != nexus_info->region.width) ||
5383 (extent > MagickMaxBufferExtent))
5390 for (y=0; y < (ssize_t) rows; y++)
5392 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5393 cache_info->server_info,®ion,length,(const unsigned char *) p);
5394 if (count != (MagickOffsetType) length)
5396 p+=cache_info->metacontent_extent*nexus_info->region.width;
5399 UnlockSemaphoreInfo(cache_info->file_semaphore);
5405 if (y < (ssize_t) rows)
5407 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5408 cache_info->cache_filename);
5409 return(MagickFalse);
5411 if ((cache_info->debug != MagickFalse) &&
5412 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5413 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5414 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5415 nexus_info->region.width,(double) nexus_info->region.height,(double)
5416 nexus_info->region.x,(double) nexus_info->region.y);
5421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5425 + W r i t e C a c h e P i x e l s %
5429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5431 % WritePixelCachePixels() writes image pixels to the specified region of the
5434 % The format of the WritePixelCachePixels() method is:
5436 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5437 % NexusInfo *nexus_info,ExceptionInfo *exception)
5439 % A description of each parameter follows:
5441 % o cache_info: the pixel cache.
5443 % o nexus_info: the cache nexus to write the pixels.
5445 % o exception: return any errors or warnings in this structure.
5448 static MagickBooleanType WritePixelCachePixels(
5449 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5450 ExceptionInfo *exception)
5460 register const Quantum
5469 if (nexus_info->authentic_pixel_cache != MagickFalse)
5471 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5472 nexus_info->region.x;
5473 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5475 extent=length*nexus_info->region.height;
5476 rows=nexus_info->region.height;
5478 p=nexus_info->pixels;
5479 switch (cache_info->type)
5488 Write pixels to memory.
5490 if ((cache_info->columns == nexus_info->region.width) &&
5491 (extent == (MagickSizeType) ((size_t) extent)))
5496 q=cache_info->pixels+offset*cache_info->number_channels;
5497 for (y=0; y < (ssize_t) rows; y++)
5499 (void) memcpy(q,p,(size_t) length);
5500 p+=cache_info->number_channels*nexus_info->region.width;
5501 q+=cache_info->columns*cache_info->number_channels;
5508 Write pixels to disk.
5510 LockSemaphoreInfo(cache_info->file_semaphore);
5511 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5513 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5514 cache_info->cache_filename);
5515 UnlockSemaphoreInfo(cache_info->file_semaphore);
5516 return(MagickFalse);
5518 if ((cache_info->columns == nexus_info->region.width) &&
5519 (extent <= MagickMaxBufferExtent))
5524 for (y=0; y < (ssize_t) rows; y++)
5526 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5527 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5529 if (count != (MagickOffsetType) length)
5531 p+=cache_info->number_channels*nexus_info->region.width;
5532 offset+=cache_info->columns;
5534 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5535 (void) ClosePixelCacheOnDisk(cache_info);
5536 UnlockSemaphoreInfo(cache_info->file_semaphore);
5539 case DistributedCache:
5545 Write pixels to distributed cache.
5547 LockSemaphoreInfo(cache_info->file_semaphore);
5548 region=nexus_info->region;
5549 if ((cache_info->columns != nexus_info->region.width) ||
5550 (extent > MagickMaxBufferExtent))
5557 for (y=0; y < (ssize_t) rows; y++)
5559 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5560 cache_info->server_info,®ion,length,(const unsigned char *) p);
5561 if (count != (MagickOffsetType) length)
5563 p+=cache_info->number_channels*nexus_info->region.width;
5566 UnlockSemaphoreInfo(cache_info->file_semaphore);
5572 if (y < (ssize_t) rows)
5574 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5575 cache_info->cache_filename);
5576 return(MagickFalse);
5578 if ((cache_info->debug != MagickFalse) &&
5579 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5580 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5581 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5582 nexus_info->region.width,(double) nexus_info->region.height,(double)
5583 nexus_info->region.x,(double) nexus_info->region.y);