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-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
100 #if defined(__cplusplus) || defined(c_plusplus)
105 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
109 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
110 const ssize_t,const size_t,const size_t,ExceptionInfo *),
111 *GetVirtualPixelsCache(const Image *);
114 *GetVirtualMetacontentFromCache(const Image *);
116 static MagickBooleanType
117 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
120 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
122 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
123 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
124 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
125 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
129 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
130 const size_t,ExceptionInfo *),
131 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
132 const size_t,ExceptionInfo *),
133 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
134 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
136 #if defined(__cplusplus) || defined(c_plusplus)
143 static volatile MagickBooleanType
144 instantiate_cache = MagickFalse;
147 *cache_semaphore = (SemaphoreInfo *) NULL;
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 + A c q u i r e P i x e l C a c h e %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % AcquirePixelCache() acquires a pixel cache.
162 % The format of the AcquirePixelCache() method is:
164 % Cache AcquirePixelCache(const size_t number_threads)
166 % A description of each parameter follows:
168 % o number_threads: the number of nexus threads.
171 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
174 *restrict cache_info;
179 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
180 if (cache_info == (CacheInfo *) NULL)
181 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
182 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
183 cache_info->type=UndefinedCache;
184 cache_info->mode=IOMode;
185 cache_info->colorspace=sRGBColorspace;
186 cache_info->file=(-1);
187 cache_info->id=GetMagickThreadId();
188 cache_info->number_threads=number_threads;
189 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
190 cache_info->number_threads=GetOpenMPMaximumThreads();
191 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
192 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
193 if (cache_info->number_threads == 0)
194 cache_info->number_threads=1;
195 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
196 if (cache_info->nexus_info == (NexusInfo **) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
199 if (synchronize != (const char *) NULL)
201 cache_info->synchronize=IsStringTrue(synchronize);
202 synchronize=DestroyString(synchronize);
204 cache_info->semaphore=AllocateSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->file_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 return((Cache ) cache_info);
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % A c q u i r e P i x e l C a c h e N e x u s %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
225 % The format of the AcquirePixelCacheNexus method is:
227 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
229 % A description of each parameter follows:
231 % o number_threads: the number of nexus threads.
234 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
237 **restrict nexus_info;
242 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
243 number_threads,sizeof(*nexus_info)));
244 if (nexus_info == (NexusInfo **) NULL)
245 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
246 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
247 sizeof(**nexus_info));
248 if (nexus_info[0] == (NexusInfo *) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
251 for (i=0; i < (ssize_t) number_threads; i++)
253 nexus_info[i]=(&nexus_info[0][i]);
254 nexus_info[i]->signature=MagickSignature;
260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264 + A c q u i r e P i x e l C a c h e P i x e l s %
268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 % AcquirePixelCachePixels() returns the pixels associated with the specified
273 % The format of the AcquirePixelCachePixels() method is:
275 % const void *AcquirePixelCachePixels(const Image *image,
276 % MagickSizeType *length,ExceptionInfo *exception)
278 % A description of each parameter follows:
280 % o image: the image.
282 % o length: the pixel cache length.
284 % o exception: return any errors or warnings in this structure.
287 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
288 MagickSizeType *length,ExceptionInfo *exception)
291 *restrict cache_info;
293 assert(image != (const Image *) NULL);
294 assert(image->signature == MagickSignature);
295 assert(exception != (ExceptionInfo *) NULL);
296 assert(exception->signature == MagickSignature);
297 assert(image->cache != (Cache) NULL);
298 cache_info=(CacheInfo *) image->cache;
299 assert(cache_info->signature == MagickSignature);
301 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
302 return((const void *) NULL);
303 *length=cache_info->length;
304 return((const void *) cache_info->pixels);
308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 + C a c h e C o m p o n e n t G e n e s i s %
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 % CacheComponentGenesis() instantiates the cache component.
320 % The format of the CacheComponentGenesis method is:
322 % MagickBooleanType CacheComponentGenesis(void)
325 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
327 AcquireSemaphoreInfo(&cache_semaphore);
332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 + C a c h e C o m p o n e n t T e r m i n u s %
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 % CacheComponentTerminus() destroys the cache component.
344 % The format of the CacheComponentTerminus() method is:
346 % CacheComponentTerminus(void)
349 MagickPrivate void CacheComponentTerminus(void)
351 if (cache_semaphore == (SemaphoreInfo *) NULL)
352 AcquireSemaphoreInfo(&cache_semaphore);
353 LockSemaphoreInfo(cache_semaphore);
354 instantiate_cache=MagickFalse;
355 UnlockSemaphoreInfo(cache_semaphore);
356 DestroySemaphoreInfo(&cache_semaphore);
360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 + C l o n e P i x e l C a c h e %
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 % ClonePixelCache() clones a pixel cache.
372 % The format of the ClonePixelCache() method is:
374 % Cache ClonePixelCache(const Cache cache)
376 % A description of each parameter follows:
378 % o cache: the pixel cache.
381 MagickPrivate Cache ClonePixelCache(const Cache cache)
384 *restrict clone_info;
387 *restrict cache_info;
389 assert(cache != NULL);
390 cache_info=(const CacheInfo *) cache;
391 assert(cache_info->signature == MagickSignature);
392 if (cache_info->debug != MagickFalse)
393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
394 cache_info->filename);
395 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
396 if (clone_info == (Cache) NULL)
397 return((Cache) NULL);
398 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
399 return((Cache ) clone_info);
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 + C l o n e P i x e l C a c h e M e t h o d s %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
416 % The format of the ClonePixelCacheMethods() method is:
418 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
420 % A description of each parameter follows:
422 % o clone: Specifies a pointer to a Cache structure.
424 % o cache: the pixel cache.
427 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
430 *restrict cache_info,
431 *restrict source_info;
433 assert(clone != (Cache) NULL);
434 source_info=(CacheInfo *) clone;
435 assert(source_info->signature == MagickSignature);
436 if (source_info->debug != MagickFalse)
437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
438 source_info->filename);
439 assert(cache != (Cache) NULL);
440 cache_info=(CacheInfo *) cache;
441 assert(cache_info->signature == MagickSignature);
442 source_info->methods=cache_info->methods;
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450 + C l o n e P i x e l C a c h e R e p o s i t o r y %
454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
455 % ClonePixelCacheRepository() clones the source pixel cache to the destination
458 % The format of the ClonePixelCacheRepository() method is:
460 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
461 % CacheInfo *source_info,ExceptionInfo *exception)
463 % A description of each parameter follows:
465 % o cache_info: the pixel cache.
467 % o source_info: the source pixel cache.
469 % o exception: return any errors or warnings in this structure.
473 static inline void CopyPixels(Quantum *destination,const Quantum *source,
474 const MagickSizeType number_pixels)
476 #if !defined(MAGICKCORE_OPENMP_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH <= 8)
477 (void) memcpy(destination,source,(size_t) number_pixels*sizeof(*source));
479 register MagickSizeType
482 #pragma omp parallel for
483 for (i=0; i < number_pixels; i++)
484 destination[i]=source[i];
488 static inline MagickSizeType MagickMin(const MagickSizeType x,
489 const MagickSizeType y)
496 static MagickBooleanType ClonePixelCacheRepository(
497 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
498 ExceptionInfo *exception)
500 #define MaxCacheThreads 2
501 #define cache_threads(source,destination,chunk) \
502 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
503 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
504 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
511 **restrict cache_nexus,
512 **restrict clone_nexus;
520 assert(cache_info != (CacheInfo *) NULL);
521 assert(clone_info != (CacheInfo *) NULL);
522 assert(exception != (ExceptionInfo *) NULL);
523 if (cache_info->type == PingCache)
525 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
526 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
527 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
528 (cache_info->columns == clone_info->columns) &&
529 (cache_info->rows == clone_info->rows) &&
530 (cache_info->number_channels == clone_info->number_channels) &&
531 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
532 (cache_info->metacontent_extent == clone_info->metacontent_extent))
534 CopyPixels(clone_info->pixels,cache_info->pixels,cache_info->columns*
535 cache_info->number_channels*cache_info->rows);
536 if (cache_info->metacontent_extent != 0)
537 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
538 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
539 sizeof(cache_info->metacontent));
543 Mismatched pixel cache morphology.
545 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
546 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
547 if ((cache_nexus == (NexusInfo **) NULL) ||
548 (clone_nexus == (NexusInfo **) NULL))
549 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
550 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
551 optimize=(cache_info->number_channels == clone_info->number_channels) &&
552 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
553 MagickTrue : MagickFalse;
554 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
555 clone_info->columns*clone_info->number_channels);
557 #if defined(MAGICKCORE_OPENMP_SUPPORT)
558 #pragma omp parallel for schedule(static,4) shared(status) \
559 cache_threads(cache_info,clone_info,cache_info->rows)
561 for (y=0; y < (ssize_t) cache_info->rows; y++)
564 id = GetOpenMPThreadId();
575 if (status == MagickFalse)
577 if (y >= (ssize_t) clone_info->rows)
579 region.width=cache_info->columns;
583 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
585 if (pixels == (Quantum *) NULL)
587 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
588 if (status == MagickFalse)
590 region.width=clone_info->columns;
591 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
592 clone_nexus[id],exception);
593 if (pixels == (Quantum *) NULL)
595 if (optimize != MagickFalse)
596 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
600 register const Quantum
607 Mismatched pixel channel map.
609 p=cache_nexus[id]->pixels;
610 q=clone_nexus[id]->pixels;
611 for (x=0; x < (ssize_t) cache_info->columns; x++)
616 if (x == (ssize_t) clone_info->columns)
618 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
626 channel=clone_info->channel_map[i].channel;
627 traits=cache_info->channel_map[channel].traits;
628 if (traits != UndefinedPixelTrait)
629 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
633 p+=cache_info->number_channels;
636 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
638 if ((cache_info->metacontent_extent != 0) &&
639 (clone_info->metacontent_extent != 0))
644 length=(size_t) MagickMin(cache_info->metacontent_extent,
645 clone_info->metacontent_extent);
646 #if defined(MAGICKCORE_OPENMP_SUPPORT)
647 #pragma omp parallel for schedule(static,4) shared(status) \
648 cache_threads(cache_info,clone_info,cache_info->rows)
650 for (y=0; y < (ssize_t) cache_info->rows; y++)
653 id = GetOpenMPThreadId();
661 if (status == MagickFalse)
663 if (y >= (ssize_t) clone_info->rows)
665 region.width=cache_info->columns;
669 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
670 cache_nexus[id],exception);
671 if (pixels == (Quantum *) NULL)
673 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
674 if (status == MagickFalse)
676 region.width=clone_info->columns;
677 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
678 clone_nexus[id],exception);
679 if (pixels == (Quantum *) NULL)
681 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
682 length*sizeof(cache_nexus[id]->metacontent));
683 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
686 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
687 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
688 if (cache_info->debug != MagickFalse)
691 message[MaxTextExtent];
693 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
694 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
695 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
696 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
706 + D e s t r o y I m a g e P i x e l C a c h e %
710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
714 % The format of the DestroyImagePixelCache() method is:
716 % void DestroyImagePixelCache(Image *image)
718 % A description of each parameter follows:
720 % o image: the image.
723 static void DestroyImagePixelCache(Image *image)
725 assert(image != (Image *) NULL);
726 assert(image->signature == MagickSignature);
727 if (image->debug != MagickFalse)
728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
729 if (image->cache == (void *) NULL)
731 image->cache=DestroyPixelCache(image->cache);
735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
739 + D e s t r o y I m a g e P i x e l s %
743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
745 % DestroyImagePixels() deallocates memory associated with the pixel cache.
747 % The format of the DestroyImagePixels() method is:
749 % void DestroyImagePixels(Image *image)
751 % A description of each parameter follows:
753 % o image: the image.
756 MagickExport void DestroyImagePixels(Image *image)
759 *restrict cache_info;
761 assert(image != (const Image *) NULL);
762 assert(image->signature == MagickSignature);
763 if (image->debug != MagickFalse)
764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
765 assert(image->cache != (Cache) NULL);
766 cache_info=(CacheInfo *) image->cache;
767 assert(cache_info->signature == MagickSignature);
768 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
770 cache_info->methods.destroy_pixel_handler(image);
773 image->cache=DestroyPixelCache(image->cache);
777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781 + D e s t r o y P i x e l C a c h e %
785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787 % DestroyPixelCache() deallocates memory associated with the pixel cache.
789 % The format of the DestroyPixelCache() method is:
791 % Cache DestroyPixelCache(Cache cache)
793 % A description of each parameter follows:
795 % o cache: the pixel cache.
799 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
805 if (cache_info->file != -1)
807 status=close(cache_info->file);
808 cache_info->file=(-1);
809 RelinquishMagickResource(FileResource,1);
811 return(status == -1 ? MagickFalse : MagickTrue);
814 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
816 switch (cache_info->type)
820 if (cache_info->mapped == MagickFalse)
821 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
824 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
825 (size_t) cache_info->length);
826 RelinquishMagickResource(MemoryResource,cache_info->length);
831 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
833 if (cache_info->mode != ReadMode)
834 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
835 *cache_info->cache_filename='\0';
836 RelinquishMagickResource(MapResource,cache_info->length);
840 if (cache_info->file != -1)
841 (void) ClosePixelCacheOnDisk(cache_info);
842 if (cache_info->mode != ReadMode)
843 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
844 *cache_info->cache_filename='\0';
845 RelinquishMagickResource(DiskResource,cache_info->length);
848 case DistributedCache:
850 *cache_info->cache_filename='\0';
851 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
852 cache_info->server_info);
858 cache_info->type=UndefinedCache;
859 cache_info->mapped=MagickFalse;
860 cache_info->metacontent=(void *) NULL;
863 MagickPrivate Cache DestroyPixelCache(Cache cache)
866 *restrict cache_info;
868 assert(cache != (Cache) NULL);
869 cache_info=(CacheInfo *) cache;
870 assert(cache_info->signature == MagickSignature);
871 if (cache_info->debug != MagickFalse)
872 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
873 cache_info->filename);
874 LockSemaphoreInfo(cache_info->semaphore);
875 cache_info->reference_count--;
876 if (cache_info->reference_count != 0)
878 UnlockSemaphoreInfo(cache_info->semaphore);
879 return((Cache) NULL);
881 UnlockSemaphoreInfo(cache_info->semaphore);
882 if (cache_info->debug != MagickFalse)
885 message[MaxTextExtent];
887 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
888 cache_info->filename);
889 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
891 RelinquishPixelCachePixels(cache_info);
892 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
893 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
894 cache_info->server_info);
895 if (cache_info->nexus_info != (NexusInfo **) NULL)
896 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
897 cache_info->number_threads);
898 if (cache_info->random_info != (RandomInfo *) NULL)
899 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
900 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
901 DestroySemaphoreInfo(&cache_info->file_semaphore);
902 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
903 DestroySemaphoreInfo(&cache_info->semaphore);
904 cache_info->signature=(~MagickSignature);
905 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
915 + D e s t r o y P i x e l C a c h e N e x u s %
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
921 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
923 % The format of the DestroyPixelCacheNexus() method is:
925 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
926 % const size_t number_threads)
928 % A description of each parameter follows:
930 % o nexus_info: the nexus to destroy.
932 % o number_threads: the number of nexus threads.
936 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
938 if (nexus_info->mapped == MagickFalse)
939 (void) RelinquishAlignedMemory(nexus_info->cache);
941 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
942 nexus_info->cache=(Quantum *) NULL;
943 nexus_info->pixels=(Quantum *) NULL;
944 nexus_info->metacontent=(void *) NULL;
945 nexus_info->length=0;
946 nexus_info->mapped=MagickFalse;
949 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
950 const size_t number_threads)
955 assert(nexus_info != (NexusInfo **) NULL);
956 for (i=0; i < (ssize_t) number_threads; i++)
958 if (nexus_info[i]->cache != (Quantum *) NULL)
959 RelinquishCacheNexusPixels(nexus_info[i]);
960 nexus_info[i]->signature=(~MagickSignature);
962 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
963 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
972 % G e t A u t h e n t i c M e t a c o n t e n t %
976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
978 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
979 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
980 % returned if the associated pixels are not available.
982 % The format of the GetAuthenticMetacontent() method is:
984 % void *GetAuthenticMetacontent(const Image *image)
986 % A description of each parameter follows:
988 % o image: the image.
991 MagickExport void *GetAuthenticMetacontent(const Image *image)
994 *restrict cache_info;
997 id = GetOpenMPThreadId();
999 assert(image != (const Image *) NULL);
1000 assert(image->signature == MagickSignature);
1001 assert(image->cache != (Cache) NULL);
1002 cache_info=(CacheInfo *) image->cache;
1003 assert(cache_info->signature == MagickSignature);
1004 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1005 (GetAuthenticMetacontentFromHandler) NULL)
1010 metacontent=cache_info->methods.
1011 get_authentic_metacontent_from_handler(image);
1012 return(metacontent);
1014 assert(id < (int) cache_info->number_threads);
1015 return(cache_info->nexus_info[id]->metacontent);
1019 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1023 + 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 %
1027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1029 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1030 % with the last call to QueueAuthenticPixelsCache() or
1031 % GetAuthenticPixelsCache().
1033 % The format of the GetAuthenticMetacontentFromCache() method is:
1035 % void *GetAuthenticMetacontentFromCache(const Image *image)
1037 % A description of each parameter follows:
1039 % o image: the image.
1042 static void *GetAuthenticMetacontentFromCache(const Image *image)
1045 *restrict cache_info;
1048 id = GetOpenMPThreadId();
1050 assert(image != (const Image *) NULL);
1051 assert(image->signature == MagickSignature);
1052 assert(image->cache != (Cache) NULL);
1053 cache_info=(CacheInfo *) image->cache;
1054 assert(cache_info->signature == MagickSignature);
1055 assert(id < (int) cache_info->number_threads);
1056 return(cache_info->nexus_info[id]->metacontent);
1060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1064 + 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 %
1068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1070 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1071 % disk pixel cache as defined by the geometry parameters. A pointer to the
1072 % pixels is returned if the pixels are transferred, otherwise a NULL is
1075 % The format of the GetAuthenticPixelCacheNexus() method is:
1077 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1078 % const ssize_t y,const size_t columns,const size_t rows,
1079 % NexusInfo *nexus_info,ExceptionInfo *exception)
1081 % A description of each parameter follows:
1083 % o image: the image.
1085 % o x,y,columns,rows: These values define the perimeter of a region of
1088 % o nexus_info: the cache nexus to return.
1090 % o exception: return any errors or warnings in this structure.
1094 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1095 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1096 ExceptionInfo *exception)
1099 *restrict cache_info;
1105 Transfer pixels from the cache.
1107 assert(image != (Image *) NULL);
1108 assert(image->signature == MagickSignature);
1109 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1110 nexus_info,exception);
1111 if (pixels == (Quantum *) NULL)
1112 return((Quantum *) NULL);
1113 cache_info=(CacheInfo *) image->cache;
1114 assert(cache_info->signature == MagickSignature);
1115 if (nexus_info->authentic_pixel_cache != MagickFalse)
1117 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1118 return((Quantum *) NULL);
1119 if (cache_info->metacontent_extent != 0)
1120 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1121 return((Quantum *) NULL);
1126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130 + 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 %
1134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1137 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1139 % The format of the GetAuthenticPixelsFromCache() method is:
1141 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1143 % A description of each parameter follows:
1145 % o image: the image.
1148 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1151 *restrict cache_info;
1154 id = GetOpenMPThreadId();
1156 assert(image != (const Image *) NULL);
1157 assert(image->signature == MagickSignature);
1158 assert(image->cache != (Cache) NULL);
1159 cache_info=(CacheInfo *) image->cache;
1160 assert(cache_info->signature == MagickSignature);
1161 assert(id < (int) cache_info->number_threads);
1162 return(cache_info->nexus_info[id]->pixels);
1166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1170 % G e t A u t h e n t i c P i x e l Q u e u e %
1174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1176 % GetAuthenticPixelQueue() returns the authentic pixels associated
1177 % corresponding with the last call to QueueAuthenticPixels() or
1178 % GetAuthenticPixels().
1180 % The format of the GetAuthenticPixelQueue() method is:
1182 % Quantum *GetAuthenticPixelQueue(const Image image)
1184 % A description of each parameter follows:
1186 % o image: the image.
1189 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1192 *restrict cache_info;
1195 id = GetOpenMPThreadId();
1197 assert(image != (const Image *) NULL);
1198 assert(image->signature == MagickSignature);
1199 assert(image->cache != (Cache) NULL);
1200 cache_info=(CacheInfo *) image->cache;
1201 assert(cache_info->signature == MagickSignature);
1202 if (cache_info->methods.get_authentic_pixels_from_handler !=
1203 (GetAuthenticPixelsFromHandler) NULL)
1204 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1205 assert(id < (int) cache_info->number_threads);
1206 return(cache_info->nexus_info[id]->pixels);
1210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214 % G e t A u t h e n t i c P i x e l s %
1217 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1219 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1220 % region is successfully accessed, a pointer to a Quantum array
1221 % representing the region is returned, otherwise NULL is returned.
1223 % The returned pointer may point to a temporary working copy of the pixels
1224 % or it may point to the original pixels in memory. Performance is maximized
1225 % if the selected region is part of one row, or one or more full rows, since
1226 % then there is opportunity to access the pixels in-place (without a copy)
1227 % if the image is in memory, or in a memory-mapped file. The returned pointer
1228 % must *never* be deallocated by the user.
1230 % Pixels accessed via the returned pointer represent a simple array of type
1231 % Quantum. If the image has corresponding metacontent,call
1232 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1233 % meta-content corresponding to the region. Once the Quantum array has
1234 % been updated, the changes must be saved back to the underlying image using
1235 % SyncAuthenticPixels() or they may be lost.
1237 % The format of the GetAuthenticPixels() method is:
1239 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1240 % const ssize_t y,const size_t columns,const size_t rows,
1241 % ExceptionInfo *exception)
1243 % A description of each parameter follows:
1245 % o image: the image.
1247 % o x,y,columns,rows: These values define the perimeter of a region of
1250 % o exception: return any errors or warnings in this structure.
1253 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1254 const ssize_t y,const size_t columns,const size_t rows,
1255 ExceptionInfo *exception)
1258 *restrict cache_info;
1261 id = GetOpenMPThreadId();
1266 assert(image != (Image *) NULL);
1267 assert(image->signature == MagickSignature);
1268 assert(image->cache != (Cache) NULL);
1269 cache_info=(CacheInfo *) image->cache;
1270 assert(cache_info->signature == MagickSignature);
1271 if (cache_info->methods.get_authentic_pixels_handler !=
1272 (GetAuthenticPixelsHandler) NULL)
1274 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1278 assert(id < (int) cache_info->number_threads);
1279 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1280 cache_info->nexus_info[id],exception);
1285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1289 + G e t A u t h e n t i c P i x e l s C a c h e %
1293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1295 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1296 % as defined by the geometry parameters. A pointer to the pixels is returned
1297 % if the pixels are transferred, otherwise a NULL is returned.
1299 % The format of the GetAuthenticPixelsCache() method is:
1301 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1302 % const ssize_t y,const size_t columns,const size_t rows,
1303 % ExceptionInfo *exception)
1305 % A description of each parameter follows:
1307 % o image: the image.
1309 % o x,y,columns,rows: These values define the perimeter of a region of
1312 % o exception: return any errors or warnings in this structure.
1315 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1316 const ssize_t y,const size_t columns,const size_t rows,
1317 ExceptionInfo *exception)
1320 *restrict cache_info;
1323 id = GetOpenMPThreadId();
1328 assert(image != (const Image *) NULL);
1329 assert(image->signature == MagickSignature);
1330 assert(image->cache != (Cache) NULL);
1331 cache_info=(CacheInfo *) image->cache;
1332 if (cache_info == (Cache) NULL)
1333 return((Quantum *) NULL);
1334 assert(cache_info->signature == MagickSignature);
1335 assert(id < (int) cache_info->number_threads);
1336 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1337 cache_info->nexus_info[id],exception);
1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346 + G e t I m a g e E x t e n t %
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1352 % GetImageExtent() returns the extent of the pixels associated corresponding
1353 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1355 % The format of the GetImageExtent() method is:
1357 % MagickSizeType GetImageExtent(const Image *image)
1359 % A description of each parameter follows:
1361 % o image: the image.
1364 MagickExport MagickSizeType GetImageExtent(const Image *image)
1367 *restrict cache_info;
1370 id = GetOpenMPThreadId();
1372 assert(image != (Image *) NULL);
1373 assert(image->signature == MagickSignature);
1374 if (image->debug != MagickFalse)
1375 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1376 assert(image->cache != (Cache) NULL);
1377 cache_info=(CacheInfo *) image->cache;
1378 assert(cache_info->signature == MagickSignature);
1379 assert(id < (int) cache_info->number_threads);
1380 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388 + G e t I m a g e P i x e l C a c h e %
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1394 % GetImagePixelCache() ensures that there is only a single reference to the
1395 % pixel cache to be modified, updating the provided cache pointer to point to
1396 % a clone of the original pixel cache if necessary.
1398 % The format of the GetImagePixelCache method is:
1400 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1401 % ExceptionInfo *exception)
1403 % A description of each parameter follows:
1405 % o image: the image.
1407 % o clone: any value other than MagickFalse clones the cache pixels.
1409 % o exception: return any errors or warnings in this structure.
1413 static inline MagickBooleanType ValidatePixelCacheMorphology(
1414 const Image *restrict image)
1417 *restrict cache_info;
1419 const PixelChannelMap
1424 Does the image match the pixel cache morphology?
1426 cache_info=(CacheInfo *) image->cache;
1427 p=image->channel_map;
1428 q=cache_info->channel_map;
1429 if ((image->storage_class != cache_info->storage_class) ||
1430 (image->colorspace != cache_info->colorspace) ||
1431 (image->alpha_trait != cache_info->alpha_trait) ||
1432 (image->read_mask != cache_info->read_mask) ||
1433 (image->write_mask != cache_info->write_mask) ||
1434 (image->columns != cache_info->columns) ||
1435 (image->rows != cache_info->rows) ||
1436 (image->number_channels != cache_info->number_channels) ||
1437 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1438 (image->metacontent_extent != cache_info->metacontent_extent) ||
1439 (cache_info->nexus_info == (NexusInfo **) NULL))
1440 return(MagickFalse);
1444 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1445 ExceptionInfo *exception)
1448 *restrict cache_info;
1454 static MagickSizeType
1460 cache_timestamp = 0;
1463 LockSemaphoreInfo(image->semaphore);
1464 if (cpu_throttle == 0)
1465 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1466 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1467 MagickDelay(cpu_throttle);
1468 if (time_limit == 0)
1471 Set the expire time in seconds.
1473 time_limit=GetMagickResourceLimit(TimeResource);
1474 cache_timestamp=time((time_t *) NULL);
1476 if ((time_limit != MagickResourceInfinity) &&
1477 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1478 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1479 assert(image->cache != (Cache) NULL);
1480 cache_info=(CacheInfo *) image->cache;
1481 destroy=MagickFalse;
1482 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1484 LockSemaphoreInfo(cache_info->semaphore);
1485 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1496 clone_image=(*image);
1497 clone_image.semaphore=AllocateSemaphoreInfo();
1498 clone_image.reference_count=1;
1499 clone_image.cache=ClonePixelCache(cache_info);
1500 clone_info=(CacheInfo *) clone_image.cache;
1501 status=OpenPixelCache(&clone_image,IOMode,exception);
1502 if (status != MagickFalse)
1504 if (clone != MagickFalse)
1505 status=ClonePixelCacheRepository(clone_info,cache_info,
1507 if (status != MagickFalse)
1509 if (cache_info->reference_count == 1)
1510 cache_info->nexus_info=(NexusInfo **) NULL;
1512 image->cache=clone_image.cache;
1515 DestroySemaphoreInfo(&clone_image.semaphore);
1517 UnlockSemaphoreInfo(cache_info->semaphore);
1519 if (destroy != MagickFalse)
1520 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1521 if (status != MagickFalse)
1524 Ensure the image matches the pixel cache morphology.
1526 image->taint=MagickTrue;
1527 image->type=UndefinedType;
1528 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1530 status=OpenPixelCache(image,IOMode,exception);
1531 cache_info=(CacheInfo *) image->cache;
1532 if (cache_info->type == DiskCache)
1533 (void) ClosePixelCacheOnDisk(cache_info);
1536 UnlockSemaphoreInfo(image->semaphore);
1537 if (status == MagickFalse)
1538 return((Cache) NULL);
1539 return(image->cache);
1543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547 + G e t I m a g e P i x e l C a c h e T y p e %
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1554 % DiskCache, MemoryCache, MapCache, or PingCache.
1556 % The format of the GetImagePixelCacheType() method is:
1558 % CacheType GetImagePixelCacheType(const Image *image)
1560 % A description of each parameter follows:
1562 % o image: the image.
1565 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1568 *restrict cache_info;
1570 assert(image != (Image *) NULL);
1571 assert(image->signature == MagickSignature);
1572 assert(image->cache != (Cache) NULL);
1573 cache_info=(CacheInfo *) image->cache;
1574 assert(cache_info->signature == MagickSignature);
1575 return(cache_info->type);
1579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583 % G e t O n e A u t h e n t i c P i x e l %
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1590 % location. The image background color is returned if an error occurs.
1592 % The format of the GetOneAuthenticPixel() method is:
1594 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1595 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1597 % A description of each parameter follows:
1599 % o image: the image.
1601 % o x,y: These values define the location of the pixel to return.
1603 % o pixel: return a pixel at the specified (x,y) location.
1605 % o exception: return any errors or warnings in this structure.
1608 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1609 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1612 *restrict cache_info;
1620 assert(image != (Image *) NULL);
1621 assert(image->signature == MagickSignature);
1622 assert(image->cache != (Cache) NULL);
1623 cache_info=(CacheInfo *) image->cache;
1624 assert(cache_info->signature == MagickSignature);
1625 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1626 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1627 (GetOneAuthenticPixelFromHandler) NULL)
1628 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1630 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1631 if (q == (Quantum *) NULL)
1633 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1634 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1635 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1636 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1637 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1638 return(MagickFalse);
1640 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1642 PixelChannel channel=GetPixelChannelChannel(image,i);
1643 pixel[channel]=q[i];
1649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1653 + 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 %
1657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1659 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1660 % location. The image background color is returned if an error occurs.
1662 % The format of the GetOneAuthenticPixelFromCache() method is:
1664 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1665 % const ssize_t x,const ssize_t y,Quantum *pixel,
1666 % ExceptionInfo *exception)
1668 % A description of each parameter follows:
1670 % o image: the image.
1672 % o x,y: These values define the location of the pixel to return.
1674 % o pixel: return a pixel at the specified (x,y) location.
1676 % o exception: return any errors or warnings in this structure.
1679 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1680 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1683 *restrict cache_info;
1686 id = GetOpenMPThreadId();
1694 assert(image != (const Image *) NULL);
1695 assert(image->signature == MagickSignature);
1696 assert(image->cache != (Cache) NULL);
1697 cache_info=(CacheInfo *) image->cache;
1698 assert(cache_info->signature == MagickSignature);
1699 assert(id < (int) cache_info->number_threads);
1700 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1701 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1703 if (q == (Quantum *) NULL)
1705 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1706 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1707 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1708 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1709 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1710 return(MagickFalse);
1712 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1714 PixelChannel channel=GetPixelChannelChannel(image,i);
1715 pixel[channel]=q[i];
1721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1725 % G e t O n e V i r t u a l P i x e l %
1729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1732 % (x,y) location. The image background color is returned if an error occurs.
1733 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1735 % The format of the GetOneVirtualPixel() method is:
1737 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1738 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1740 % A description of each parameter follows:
1742 % o image: the image.
1744 % o x,y: These values define the location of the pixel to return.
1746 % o pixel: return a pixel at the specified (x,y) location.
1748 % o exception: return any errors or warnings in this structure.
1751 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1752 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1755 *restrict cache_info;
1758 id = GetOpenMPThreadId();
1766 assert(image != (const Image *) NULL);
1767 assert(image->signature == MagickSignature);
1768 assert(image->cache != (Cache) NULL);
1769 cache_info=(CacheInfo *) image->cache;
1770 assert(cache_info->signature == MagickSignature);
1771 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1772 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1773 (GetOneVirtualPixelFromHandler) NULL)
1774 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1775 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1776 assert(id < (int) cache_info->number_threads);
1777 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1778 1UL,1UL,cache_info->nexus_info[id],exception);
1779 if (p == (const Quantum *) NULL)
1781 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1782 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1783 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1784 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1785 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1786 return(MagickFalse);
1788 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1790 PixelChannel channel=GetPixelChannelChannel(image,i);
1791 pixel[channel]=p[i];
1797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1801 + 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 %
1805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1808 % specified (x,y) location. The image background color is returned if an
1811 % The format of the GetOneVirtualPixelFromCache() method is:
1813 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1814 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1815 % Quantum *pixel,ExceptionInfo *exception)
1817 % A description of each parameter follows:
1819 % o image: the image.
1821 % o virtual_pixel_method: the virtual pixel method.
1823 % o x,y: These values define the location of the pixel to return.
1825 % o pixel: return a pixel at the specified (x,y) location.
1827 % o exception: return any errors or warnings in this structure.
1830 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1831 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1832 Quantum *pixel,ExceptionInfo *exception)
1835 *restrict cache_info;
1838 id = GetOpenMPThreadId();
1846 assert(image != (const Image *) NULL);
1847 assert(image->signature == MagickSignature);
1848 assert(image->cache != (Cache) NULL);
1849 cache_info=(CacheInfo *) image->cache;
1850 assert(cache_info->signature == MagickSignature);
1851 assert(id < (int) cache_info->number_threads);
1852 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1853 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1854 cache_info->nexus_info[id],exception);
1855 if (p == (const Quantum *) NULL)
1857 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1858 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1859 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1860 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1861 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1862 return(MagickFalse);
1864 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1866 PixelChannel channel=GetPixelChannelChannel(image,i);
1867 pixel[channel]=p[i];
1873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1877 % G e t O n e V i r t u a l P i x e l I n f o %
1881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1883 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1884 % location. The image background color is returned if an error occurs. If
1885 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1887 % The format of the GetOneVirtualPixelInfo() method is:
1889 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1890 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1891 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1893 % A description of each parameter follows:
1895 % o image: the image.
1897 % o virtual_pixel_method: the virtual pixel method.
1899 % o x,y: these values define the location of the pixel to return.
1901 % o pixel: return a pixel at the specified (x,y) location.
1903 % o exception: return any errors or warnings in this structure.
1906 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1907 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1908 PixelInfo *pixel,ExceptionInfo *exception)
1911 *restrict cache_info;
1914 id = GetOpenMPThreadId();
1916 register const Quantum
1919 assert(image != (const Image *) NULL);
1920 assert(image->signature == MagickSignature);
1921 assert(image->cache != (Cache) NULL);
1922 cache_info=(CacheInfo *) image->cache;
1923 assert(cache_info->signature == MagickSignature);
1924 assert(id < (int) cache_info->number_threads);
1925 GetPixelInfo(image,pixel);
1926 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1927 cache_info->nexus_info[id],exception);
1928 if (p == (const Quantum *) NULL)
1929 return(MagickFalse);
1930 GetPixelInfoPixel(image,p,pixel);
1935 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1939 + G e t P i x e l C a c h e C o l o r s p a c e %
1943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1945 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1947 % The format of the GetPixelCacheColorspace() method is:
1949 % Colorspace GetPixelCacheColorspace(Cache cache)
1951 % A description of each parameter follows:
1953 % o cache: the pixel cache.
1956 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1959 *restrict cache_info;
1961 assert(cache != (Cache) NULL);
1962 cache_info=(CacheInfo *) cache;
1963 assert(cache_info->signature == MagickSignature);
1964 if (cache_info->debug != MagickFalse)
1965 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1966 cache_info->filename);
1967 return(cache_info->colorspace);
1971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975 + G e t P i x e l C a c h e M e t h o d s %
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981 % GetPixelCacheMethods() initializes the CacheMethods structure.
1983 % The format of the GetPixelCacheMethods() method is:
1985 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1987 % A description of each parameter follows:
1989 % o cache_methods: Specifies a pointer to a CacheMethods structure.
1992 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
1994 assert(cache_methods != (CacheMethods *) NULL);
1995 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
1996 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
1997 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
1998 cache_methods->get_virtual_metacontent_from_handler=
1999 GetVirtualMetacontentFromCache;
2000 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2001 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2002 cache_methods->get_authentic_metacontent_from_handler=
2003 GetAuthenticMetacontentFromCache;
2004 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2005 cache_methods->get_one_authentic_pixel_from_handler=
2006 GetOneAuthenticPixelFromCache;
2007 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2008 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2009 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2017 + G e t P i x e l C a c h e N e x u s E x t e n t %
2021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2023 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2024 % corresponding with the last call to SetPixelCacheNexusPixels() or
2025 % GetPixelCacheNexusPixels().
2027 % The format of the GetPixelCacheNexusExtent() method is:
2029 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2030 % NexusInfo *nexus_info)
2032 % A description of each parameter follows:
2034 % o nexus_info: the nexus info.
2037 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2038 NexusInfo *restrict nexus_info)
2041 *restrict cache_info;
2046 assert(cache != NULL);
2047 cache_info=(CacheInfo *) cache;
2048 assert(cache_info->signature == MagickSignature);
2049 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2051 return((MagickSizeType) cache_info->columns*cache_info->rows);
2056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2060 + G e t P i x e l C a c h e P i x e l s %
2064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2066 % GetPixelCachePixels() returns the pixels associated with the specified image.
2068 % The format of the GetPixelCachePixels() method is:
2070 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2071 % ExceptionInfo *exception)
2073 % A description of each parameter follows:
2075 % o image: the image.
2077 % o length: the pixel cache length.
2079 % o exception: return any errors or warnings in this structure.
2082 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2083 ExceptionInfo *exception)
2086 *restrict cache_info;
2088 assert(image != (const Image *) NULL);
2089 assert(image->signature == MagickSignature);
2090 assert(image->cache != (Cache) NULL);
2091 assert(length != (MagickSizeType *) NULL);
2092 assert(exception != (ExceptionInfo *) NULL);
2093 assert(exception->signature == MagickSignature);
2094 cache_info=(CacheInfo *) image->cache;
2095 assert(cache_info->signature == MagickSignature);
2097 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2098 return((void *) NULL);
2099 *length=cache_info->length;
2100 return((void *) cache_info->pixels);
2104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2108 + 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 %
2112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2114 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2116 % The format of the GetPixelCacheStorageClass() method is:
2118 % ClassType GetPixelCacheStorageClass(Cache cache)
2120 % A description of each parameter follows:
2122 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2124 % o cache: the pixel cache.
2127 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2130 *restrict cache_info;
2132 assert(cache != (Cache) NULL);
2133 cache_info=(CacheInfo *) cache;
2134 assert(cache_info->signature == MagickSignature);
2135 if (cache_info->debug != MagickFalse)
2136 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2137 cache_info->filename);
2138 return(cache_info->storage_class);
2142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2146 + G e t P i x e l C a c h e T i l e S i z e %
2150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2152 % GetPixelCacheTileSize() returns the pixel cache tile size.
2154 % The format of the GetPixelCacheTileSize() method is:
2156 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2159 % A description of each parameter follows:
2161 % o image: the image.
2163 % o width: the optimize cache tile width in pixels.
2165 % o height: the optimize cache tile height in pixels.
2168 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2172 *restrict cache_info;
2174 assert(image != (Image *) NULL);
2175 assert(image->signature == MagickSignature);
2176 if (image->debug != MagickFalse)
2177 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2178 cache_info=(CacheInfo *) image->cache;
2179 assert(cache_info->signature == MagickSignature);
2180 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2181 if (GetImagePixelCacheType(image) == DiskCache)
2182 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2191 + 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 %
2195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2197 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2198 % pixel cache. A virtual pixel is any pixel access that is outside the
2199 % boundaries of the image cache.
2201 % The format of the GetPixelCacheVirtualMethod() method is:
2203 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2205 % A description of each parameter follows:
2207 % o image: the image.
2210 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2213 *restrict cache_info;
2215 assert(image != (Image *) NULL);
2216 assert(image->signature == MagickSignature);
2217 assert(image->cache != (Cache) NULL);
2218 cache_info=(CacheInfo *) image->cache;
2219 assert(cache_info->signature == MagickSignature);
2220 return(cache_info->virtual_pixel_method);
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2228 + 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 %
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2234 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2235 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2237 % The format of the GetVirtualMetacontentFromCache() method is:
2239 % void *GetVirtualMetacontentFromCache(const Image *image)
2241 % A description of each parameter follows:
2243 % o image: the image.
2246 static const void *GetVirtualMetacontentFromCache(const Image *image)
2249 *restrict cache_info;
2252 id = GetOpenMPThreadId();
2255 *restrict metacontent;
2257 assert(image != (const Image *) NULL);
2258 assert(image->signature == MagickSignature);
2259 assert(image->cache != (Cache) NULL);
2260 cache_info=(CacheInfo *) image->cache;
2261 assert(cache_info->signature == MagickSignature);
2262 assert(id < (int) cache_info->number_threads);
2263 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2264 cache_info->nexus_info[id]);
2265 return(metacontent);
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273 + 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 %
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2282 % The format of the GetVirtualMetacontentFromNexus() method is:
2284 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2285 % NexusInfo *nexus_info)
2287 % A description of each parameter follows:
2289 % o cache: the pixel cache.
2291 % o nexus_info: the cache nexus to return the meta-content.
2294 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2295 NexusInfo *restrict nexus_info)
2298 *restrict cache_info;
2300 assert(cache != (Cache) NULL);
2301 cache_info=(CacheInfo *) cache;
2302 assert(cache_info->signature == MagickSignature);
2303 if (cache_info->storage_class == UndefinedClass)
2304 return((void *) NULL);
2305 return(nexus_info->metacontent);
2309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2313 % G e t V i r t u a l M e t a c o n t e n t %
2317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2320 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2321 % returned if the meta-content are not available.
2323 % The format of the GetVirtualMetacontent() method is:
2325 % const void *GetVirtualMetacontent(const Image *image)
2327 % A description of each parameter follows:
2329 % o image: the image.
2332 MagickExport const void *GetVirtualMetacontent(const Image *image)
2335 *restrict cache_info;
2338 id = GetOpenMPThreadId();
2341 *restrict metacontent;
2343 assert(image != (const Image *) NULL);
2344 assert(image->signature == MagickSignature);
2345 assert(image->cache != (Cache) NULL);
2346 cache_info=(CacheInfo *) image->cache;
2347 assert(cache_info->signature == MagickSignature);
2348 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2349 if (metacontent != (void *) NULL)
2350 return(metacontent);
2351 assert(id < (int) cache_info->number_threads);
2352 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2353 cache_info->nexus_info[id]);
2354 return(metacontent);
2358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2362 + 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 %
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2368 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2369 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2370 % is returned if the pixels are transferred, otherwise a NULL is returned.
2372 % The format of the GetVirtualPixelsFromNexus() method is:
2374 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2375 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2376 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2377 % ExceptionInfo *exception)
2379 % A description of each parameter follows:
2381 % o image: the image.
2383 % o virtual_pixel_method: the virtual pixel method.
2385 % o x,y,columns,rows: These values define the perimeter of a region of
2388 % o nexus_info: the cache nexus to acquire.
2390 % o exception: return any errors or warnings in this structure.
2397 0, 48, 12, 60, 3, 51, 15, 63,
2398 32, 16, 44, 28, 35, 19, 47, 31,
2399 8, 56, 4, 52, 11, 59, 7, 55,
2400 40, 24, 36, 20, 43, 27, 39, 23,
2401 2, 50, 14, 62, 1, 49, 13, 61,
2402 34, 18, 46, 30, 33, 17, 45, 29,
2403 10, 58, 6, 54, 9, 57, 5, 53,
2404 42, 26, 38, 22, 41, 25, 37, 21
2407 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2412 index=x+DitherMatrix[x & 0x07]-32L;
2415 if (index >= (ssize_t) columns)
2416 return((ssize_t) columns-1L);
2420 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2425 index=y+DitherMatrix[y & 0x07]-32L;
2428 if (index >= (ssize_t) rows)
2429 return((ssize_t) rows-1L);
2433 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2437 if (x >= (ssize_t) columns)
2438 return((ssize_t) (columns-1));
2442 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2446 if (y >= (ssize_t) rows)
2447 return((ssize_t) (rows-1));
2451 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2453 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2456 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2458 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2461 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2462 const size_t extent)
2468 Compute the remainder of dividing offset by extent. It returns not only
2469 the quotient (tile the offset falls in) but also the positive remainer
2470 within that tile such that 0 <= remainder < extent. This method is
2471 essentially a ldiv() using a floored modulo division rather than the
2472 normal default truncated modulo division.
2474 modulo.quotient=offset/(ssize_t) extent;
2477 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2481 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2482 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2483 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2484 ExceptionInfo *exception)
2487 *restrict cache_info;
2497 **restrict virtual_nexus;
2501 virtual_pixel[MaxPixelChannels];
2506 register const Quantum
2519 register unsigned char
2526 *restrict virtual_metacontent;
2531 assert(image != (const Image *) NULL);
2532 assert(image->signature == MagickSignature);
2533 assert(image->cache != (Cache) NULL);
2534 cache_info=(CacheInfo *) image->cache;
2535 assert(cache_info->signature == MagickSignature);
2536 if (cache_info->type == UndefinedCache)
2537 return((const Quantum *) NULL);
2540 region.width=columns;
2542 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2544 if (pixels == (Quantum *) NULL)
2545 return((const Quantum *) NULL);
2547 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2548 nexus_info->region.x;
2549 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2550 nexus_info->region.width-1L;
2551 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2552 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2553 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2554 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2560 Pixel request is inside cache extents.
2562 if (nexus_info->authentic_pixel_cache != MagickFalse)
2564 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2565 if (status == MagickFalse)
2566 return((const Quantum *) NULL);
2567 if (cache_info->metacontent_extent != 0)
2569 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2570 if (status == MagickFalse)
2571 return((const Quantum *) NULL);
2576 Pixel request is outside cache extents.
2578 s=(unsigned char *) nexus_info->metacontent;
2579 virtual_nexus=AcquirePixelCacheNexus(1);
2580 if (virtual_nexus == (NexusInfo **) NULL)
2582 if (virtual_nexus != (NexusInfo **) NULL)
2583 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2584 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2585 "UnableToGetCacheNexus","`%s'",image->filename);
2586 return((const Quantum *) NULL);
2588 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2589 sizeof(*virtual_pixel));
2590 virtual_metacontent=(void *) NULL;
2591 switch (virtual_pixel_method)
2593 case BackgroundVirtualPixelMethod:
2594 case BlackVirtualPixelMethod:
2595 case GrayVirtualPixelMethod:
2596 case TransparentVirtualPixelMethod:
2597 case MaskVirtualPixelMethod:
2598 case WhiteVirtualPixelMethod:
2599 case EdgeVirtualPixelMethod:
2600 case CheckerTileVirtualPixelMethod:
2601 case HorizontalTileVirtualPixelMethod:
2602 case VerticalTileVirtualPixelMethod:
2604 if (cache_info->metacontent_extent != 0)
2607 Acquire a metacontent buffer.
2609 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2610 cache_info->metacontent_extent);
2611 if (virtual_metacontent == (void *) NULL)
2613 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2614 (void) ThrowMagickException(exception,GetMagickModule(),
2615 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2616 return((const Quantum *) NULL);
2618 (void) ResetMagickMemory(virtual_metacontent,0,
2619 cache_info->metacontent_extent);
2621 switch (virtual_pixel_method)
2623 case BlackVirtualPixelMethod:
2625 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2626 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2627 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2630 case GrayVirtualPixelMethod:
2632 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2633 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2635 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2638 case TransparentVirtualPixelMethod:
2640 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2641 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2642 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2645 case MaskVirtualPixelMethod:
2646 case WhiteVirtualPixelMethod:
2648 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2649 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2650 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2655 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2657 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2659 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2661 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2663 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2673 for (v=0; v < (ssize_t) rows; v++)
2679 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2680 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2681 y_offset=EdgeY(y_offset,cache_info->rows);
2682 for (u=0; u < (ssize_t) columns; u+=length)
2688 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2689 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2690 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2698 Transfer a single pixel.
2700 length=(MagickSizeType) 1;
2701 switch (virtual_pixel_method)
2703 case EdgeVirtualPixelMethod:
2706 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2707 EdgeX(x_offset,cache_info->columns),
2708 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2710 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2713 case RandomVirtualPixelMethod:
2715 if (cache_info->random_info == (RandomInfo *) NULL)
2716 cache_info->random_info=AcquireRandomInfo();
2717 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2718 RandomX(cache_info->random_info,cache_info->columns),
2719 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2720 *virtual_nexus,exception);
2721 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2724 case DitherVirtualPixelMethod:
2726 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2727 DitherX(x_offset,cache_info->columns),
2728 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2730 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2733 case TileVirtualPixelMethod:
2735 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2736 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2737 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2738 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2740 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2743 case MirrorVirtualPixelMethod:
2745 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2746 if ((x_modulo.quotient & 0x01) == 1L)
2747 x_modulo.remainder=(ssize_t) cache_info->columns-
2748 x_modulo.remainder-1L;
2749 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2750 if ((y_modulo.quotient & 0x01) == 1L)
2751 y_modulo.remainder=(ssize_t) cache_info->rows-
2752 y_modulo.remainder-1L;
2753 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2754 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2756 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2759 case HorizontalTileEdgeVirtualPixelMethod:
2761 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2762 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2763 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2764 *virtual_nexus,exception);
2765 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2768 case VerticalTileEdgeVirtualPixelMethod:
2770 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2771 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2772 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2773 *virtual_nexus,exception);
2774 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2777 case BackgroundVirtualPixelMethod:
2778 case BlackVirtualPixelMethod:
2779 case GrayVirtualPixelMethod:
2780 case TransparentVirtualPixelMethod:
2781 case MaskVirtualPixelMethod:
2782 case WhiteVirtualPixelMethod:
2785 r=virtual_metacontent;
2788 case CheckerTileVirtualPixelMethod:
2790 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2791 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2792 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2795 r=virtual_metacontent;
2798 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2799 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2801 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2804 case HorizontalTileVirtualPixelMethod:
2806 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2809 r=virtual_metacontent;
2812 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2813 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2814 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2815 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2817 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2820 case VerticalTileVirtualPixelMethod:
2822 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2825 r=virtual_metacontent;
2828 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2829 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2830 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2831 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2833 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2837 if (p == (const Quantum *) NULL)
2839 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2841 q+=cache_info->number_channels;
2842 if ((s != (void *) NULL) && (r != (const void *) NULL))
2844 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2845 s+=cache_info->metacontent_extent;
2850 Transfer a run of pixels.
2852 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2853 (size_t) length,1UL,*virtual_nexus,exception);
2854 if (p == (const Quantum *) NULL)
2856 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2857 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2858 q+=length*cache_info->number_channels;
2859 if ((r != (void *) NULL) && (s != (const void *) NULL))
2861 (void) memcpy(s,r,(size_t) length);
2862 s+=length*cache_info->metacontent_extent;
2869 if (virtual_metacontent != (void *) NULL)
2870 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2871 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2880 + G e t V i r t u a l P i x e l C a c h e %
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2887 % cache as defined by the geometry parameters. A pointer to the pixels
2888 % is returned if the pixels are transferred, otherwise a NULL is returned.
2890 % The format of the GetVirtualPixelCache() method is:
2892 % const Quantum *GetVirtualPixelCache(const Image *image,
2893 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2894 % const ssize_t y,const size_t columns,const size_t rows,
2895 % ExceptionInfo *exception)
2897 % A description of each parameter follows:
2899 % o image: the image.
2901 % o virtual_pixel_method: the virtual pixel method.
2903 % o x,y,columns,rows: These values define the perimeter of a region of
2906 % o exception: return any errors or warnings in this structure.
2909 static const Quantum *GetVirtualPixelCache(const Image *image,
2910 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2911 const size_t columns,const size_t rows,ExceptionInfo *exception)
2914 *restrict cache_info;
2917 id = GetOpenMPThreadId();
2922 assert(image != (const Image *) NULL);
2923 assert(image->signature == MagickSignature);
2924 assert(image->cache != (Cache) NULL);
2925 cache_info=(CacheInfo *) image->cache;
2926 assert(cache_info->signature == MagickSignature);
2927 assert(id < (int) cache_info->number_threads);
2928 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2929 cache_info->nexus_info[id],exception);
2934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2938 % G e t V i r t u a l P i x e l Q u e u e %
2942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2944 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2945 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2947 % The format of the GetVirtualPixelQueue() method is:
2949 % const Quantum *GetVirtualPixelQueue(const Image image)
2951 % A description of each parameter follows:
2953 % o image: the image.
2956 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2959 *restrict cache_info;
2962 id = GetOpenMPThreadId();
2964 assert(image != (const Image *) NULL);
2965 assert(image->signature == MagickSignature);
2966 assert(image->cache != (Cache) NULL);
2967 cache_info=(CacheInfo *) image->cache;
2968 assert(cache_info->signature == MagickSignature);
2969 if (cache_info->methods.get_virtual_pixels_handler !=
2970 (GetVirtualPixelsHandler) NULL)
2971 return(cache_info->methods.get_virtual_pixels_handler(image));
2972 assert(id < (int) cache_info->number_threads);
2973 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2981 % G e t V i r t u a l P i x e l s %
2985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2987 % GetVirtualPixels() returns an immutable pixel region. If the
2988 % region is successfully accessed, a pointer to it is returned, otherwise
2989 % NULL is returned. The returned pointer may point to a temporary working
2990 % copy of the pixels or it may point to the original pixels in memory.
2991 % Performance is maximized if the selected region is part of one row, or one
2992 % or more full rows, since there is opportunity to access the pixels in-place
2993 % (without a copy) if the image is in memory, or in a memory-mapped file. The
2994 % returned pointer must *never* be deallocated by the user.
2996 % Pixels accessed via the returned pointer represent a simple array of type
2997 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
2998 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
2999 % access the meta-content (of type void) corresponding to the the
3002 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3004 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3005 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3006 % GetCacheViewAuthenticPixels() instead.
3008 % The format of the GetVirtualPixels() method is:
3010 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3011 % const ssize_t y,const size_t columns,const size_t rows,
3012 % ExceptionInfo *exception)
3014 % A description of each parameter follows:
3016 % o image: the image.
3018 % o x,y,columns,rows: These values define the perimeter of a region of
3021 % o exception: return any errors or warnings in this structure.
3024 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3025 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3026 ExceptionInfo *exception)
3029 *restrict cache_info;
3032 id = GetOpenMPThreadId();
3037 assert(image != (const Image *) NULL);
3038 assert(image->signature == MagickSignature);
3039 assert(image->cache != (Cache) NULL);
3040 cache_info=(CacheInfo *) image->cache;
3041 assert(cache_info->signature == MagickSignature);
3042 if (cache_info->methods.get_virtual_pixel_handler !=
3043 (GetVirtualPixelHandler) NULL)
3044 return(cache_info->methods.get_virtual_pixel_handler(image,
3045 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3046 assert(id < (int) cache_info->number_threads);
3047 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3048 columns,rows,cache_info->nexus_info[id],exception);
3053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3057 + 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 %
3061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3063 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3064 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3066 % The format of the GetVirtualPixelsCache() method is:
3068 % Quantum *GetVirtualPixelsCache(const Image *image)
3070 % A description of each parameter follows:
3072 % o image: the image.
3075 static const Quantum *GetVirtualPixelsCache(const Image *image)
3078 *restrict cache_info;
3081 id = GetOpenMPThreadId();
3083 assert(image != (const Image *) NULL);
3084 assert(image->signature == MagickSignature);
3085 assert(image->cache != (Cache) NULL);
3086 cache_info=(CacheInfo *) image->cache;
3087 assert(cache_info->signature == MagickSignature);
3088 assert(id < (int) cache_info->number_threads);
3089 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3097 + G e t V i r t u a l P i x e l s N e x u s %
3101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3103 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3106 % The format of the GetVirtualPixelsNexus() method is:
3108 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3109 % NexusInfo *nexus_info)
3111 % A description of each parameter follows:
3113 % o cache: the pixel cache.
3115 % o nexus_info: the cache nexus to return the colormap pixels.
3118 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3119 NexusInfo *restrict nexus_info)
3122 *restrict cache_info;
3124 assert(cache != (Cache) NULL);
3125 cache_info=(CacheInfo *) cache;
3126 assert(cache_info->signature == MagickSignature);
3127 if (cache_info->storage_class == UndefinedClass)
3128 return((Quantum *) NULL);
3129 return((const Quantum *) nexus_info->pixels);
3133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3137 + O p e n P i x e l C a c h e %
3141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3143 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3144 % dimensions, allocating space for the image pixels and optionally the
3145 % metacontent, and memory mapping the cache if it is disk based. The cache
3146 % nexus array is initialized as well.
3148 % The format of the OpenPixelCache() method is:
3150 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3151 % ExceptionInfo *exception)
3153 % A description of each parameter follows:
3155 % o image: the image.
3157 % o mode: ReadMode, WriteMode, or IOMode.
3159 % o exception: return any errors or warnings in this structure.
3163 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3165 cache_info->mapped=MagickFalse;
3166 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3167 (size_t) cache_info->length));
3168 if (cache_info->pixels == (Quantum *) NULL)
3170 cache_info->mapped=MagickTrue;
3171 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3172 cache_info->length);
3176 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3183 Open pixel cache on disk.
3185 if (cache_info->file != -1)
3186 return(MagickTrue); /* cache already open */
3187 if (*cache_info->cache_filename == '\0')
3188 file=AcquireUniqueFileResource(cache_info->cache_filename);
3194 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3199 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3200 O_BINARY | O_EXCL,S_MODE);
3202 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3208 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3211 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3216 return(MagickFalse);
3217 (void) AcquireMagickResource(FileResource,1);
3218 cache_info->file=file;
3219 cache_info->mode=mode;
3223 static inline MagickOffsetType WritePixelCacheRegion(
3224 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3225 const MagickSizeType length,const unsigned char *restrict buffer)
3227 register MagickOffsetType
3233 #if !defined(MAGICKCORE_HAVE_PWRITE)
3234 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3235 return((MagickOffsetType) -1);
3238 for (i=0; i < (MagickOffsetType) length; i+=count)
3240 #if !defined(MAGICKCORE_HAVE_PWRITE)
3241 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3242 (MagickSizeType) SSIZE_MAX));
3244 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3245 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3257 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3260 *restrict cache_info;
3267 cache_info=(CacheInfo *) image->cache;
3268 if (image->debug != MagickFalse)
3271 format[MaxTextExtent],
3272 message[MaxTextExtent];
3274 (void) FormatMagickSize(length,MagickFalse,format);
3275 (void) FormatLocaleString(message,MaxTextExtent,
3276 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3277 cache_info->cache_filename,cache_info->file,format);
3278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3280 if (length != (MagickSizeType) ((MagickOffsetType) length))
3281 return(MagickFalse);
3282 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3284 return(MagickFalse);
3285 if ((MagickSizeType) offset >= length)
3287 extent=(MagickOffsetType) length-1;
3288 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3289 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3290 if (cache_info->synchronize != MagickFalse)
3295 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3297 return(MagickFalse);
3300 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3303 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3304 ExceptionInfo *exception)
3307 *restrict cache_info,
3311 format[MaxTextExtent],
3312 message[MaxTextExtent];
3328 assert(image != (const Image *) NULL);
3329 assert(image->signature == MagickSignature);
3330 assert(image->cache != (Cache) NULL);
3331 if (image->debug != MagickFalse)
3332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3333 if ((image->columns == 0) || (image->rows == 0))
3334 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3335 cache_info=(CacheInfo *) image->cache;
3336 assert(cache_info->signature == MagickSignature);
3337 source_info=(*cache_info);
3338 source_info.file=(-1);
3339 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3340 image->filename,(double) GetImageIndexInList(image));
3341 cache_info->storage_class=image->storage_class;
3342 cache_info->colorspace=image->colorspace;
3343 cache_info->alpha_trait=image->alpha_trait;
3344 cache_info->read_mask=image->read_mask;
3345 cache_info->write_mask=image->write_mask;
3346 cache_info->rows=image->rows;
3347 cache_info->columns=image->columns;
3348 InitializePixelChannelMap(image);
3349 cache_info->number_channels=GetPixelChannels(image);
3350 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3351 sizeof(*image->channel_map));
3352 cache_info->metacontent_extent=image->metacontent_extent;
3353 cache_info->mode=mode;
3354 if (image->ping != MagickFalse)
3356 cache_info->type=PingCache;
3357 cache_info->pixels=(Quantum *) NULL;
3358 cache_info->metacontent=(void *) NULL;
3359 cache_info->length=0;
3362 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3363 packet_size=cache_info->number_channels*sizeof(Quantum);
3364 if (image->metacontent_extent != 0)
3365 packet_size+=cache_info->metacontent_extent;
3366 length=number_pixels*packet_size;
3367 columns=(size_t) (length/cache_info->rows/packet_size);
3368 if (cache_info->columns != columns)
3369 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3371 cache_info->length=length;
3372 status=AcquireMagickResource(AreaResource,cache_info->length);
3373 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3374 cache_info->metacontent_extent);
3375 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3377 status=AcquireMagickResource(MemoryResource,cache_info->length);
3378 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3379 (cache_info->type == MemoryCache))
3381 AllocatePixelCachePixels(cache_info);
3382 if (cache_info->pixels == (Quantum *) NULL)
3383 cache_info->pixels=source_info.pixels;
3387 Create memory pixel cache.
3390 cache_info->type=MemoryCache;
3391 cache_info->metacontent=(void *) NULL;
3392 if (cache_info->metacontent_extent != 0)
3393 cache_info->metacontent=(void *) (cache_info->pixels+
3394 number_pixels*cache_info->number_channels);
3395 if ((source_info.storage_class != UndefinedClass) &&
3398 status=ClonePixelCacheRepository(cache_info,&source_info,
3400 RelinquishPixelCachePixels(&source_info);
3402 if (image->debug != MagickFalse)
3404 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3405 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3407 (void) FormatLocaleString(message,MaxTextExtent,
3408 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3409 cache_info->filename,cache_info->mapped != MagickFalse ?
3410 "Anonymous" : "Heap",type,(double) cache_info->columns,
3411 (double) cache_info->rows,(double)
3412 cache_info->number_channels,format);
3413 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3419 RelinquishMagickResource(MemoryResource,cache_info->length);
3422 Create pixel cache on disk.
3424 status=AcquireMagickResource(DiskResource,cache_info->length);
3425 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3430 if (cache_info->type == DistributedCache)
3431 RelinquishMagickResource(DiskResource,cache_info->length);
3432 server_info=AcquireDistributeCacheInfo(exception);
3433 if (server_info != (DistributeCacheInfo *) NULL)
3435 status=OpenDistributePixelCache(server_info,image);
3436 if (status == MagickFalse)
3438 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3439 GetDistributeCacheHostname(server_info));
3440 server_info=DestroyDistributeCacheInfo(server_info);
3445 Create a distributed pixel cache.
3447 cache_info->type=DistributedCache;
3448 cache_info->server_info=server_info;
3449 (void) FormatLocaleString(cache_info->cache_filename,
3450 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3451 (DistributeCacheInfo *) cache_info->server_info),
3452 GetDistributeCachePort((DistributeCacheInfo *)
3453 cache_info->server_info));
3454 if ((source_info.storage_class != UndefinedClass) &&
3457 status=ClonePixelCacheRepository(cache_info,&source_info,
3459 RelinquishPixelCachePixels(&source_info);
3461 if (image->debug != MagickFalse)
3463 (void) FormatMagickSize(cache_info->length,MagickFalse,
3465 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3467 (void) FormatLocaleString(message,MaxTextExtent,
3468 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3469 cache_info->filename,cache_info->cache_filename,
3470 GetDistributeCacheFile((DistributeCacheInfo *)
3471 cache_info->server_info),type,(double) cache_info->columns,
3472 (double) cache_info->rows,(double)
3473 cache_info->number_channels,format);
3474 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3480 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3481 "CacheResourcesExhausted","`%s'",image->filename);
3482 return(MagickFalse);
3484 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3486 (void) ClosePixelCacheOnDisk(cache_info);
3487 *cache_info->cache_filename='\0';
3489 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3491 RelinquishMagickResource(DiskResource,cache_info->length);
3492 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3494 return(MagickFalse);
3496 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3497 cache_info->length);
3498 if (status == MagickFalse)
3500 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3502 return(MagickFalse);
3504 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3505 cache_info->metacontent_extent);
3506 if (length != (MagickSizeType) ((size_t) length))
3507 cache_info->type=DiskCache;
3510 status=AcquireMagickResource(MapResource,cache_info->length);
3511 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3512 (cache_info->type != MemoryCache))
3513 cache_info->type=DiskCache;
3516 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3517 cache_info->offset,(size_t) cache_info->length);
3518 if (cache_info->pixels == (Quantum *) NULL)
3520 cache_info->type=DiskCache;
3521 cache_info->pixels=source_info.pixels;
3526 Create file-backed memory-mapped pixel cache.
3529 (void) ClosePixelCacheOnDisk(cache_info);
3530 cache_info->type=MapCache;
3531 cache_info->mapped=MagickTrue;
3532 cache_info->metacontent=(void *) NULL;
3533 if (cache_info->metacontent_extent != 0)
3534 cache_info->metacontent=(void *) (cache_info->pixels+
3535 number_pixels*cache_info->number_channels);
3536 if ((source_info.storage_class != UndefinedClass) &&
3539 status=ClonePixelCacheRepository(cache_info,&source_info,
3541 RelinquishPixelCachePixels(&source_info);
3543 if (image->debug != MagickFalse)
3545 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3546 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3548 (void) FormatLocaleString(message,MaxTextExtent,
3549 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3550 cache_info->filename,cache_info->cache_filename,
3551 cache_info->file,type,(double) cache_info->columns,(double)
3552 cache_info->rows,(double) cache_info->number_channels,
3554 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3560 RelinquishMagickResource(MapResource,cache_info->length);
3563 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3565 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3566 RelinquishPixelCachePixels(&source_info);
3568 if (image->debug != MagickFalse)
3570 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3571 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3573 (void) FormatLocaleString(message,MaxTextExtent,
3574 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3575 cache_info->cache_filename,cache_info->file,type,(double)
3576 cache_info->columns,(double) cache_info->rows,(double)
3577 cache_info->number_channels,format);
3578 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3584 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3588 + P e r s i s t P i x e l C a c h e %
3592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3594 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3595 % persistent pixel cache is one that resides on disk and is not destroyed
3596 % when the program exits.
3598 % The format of the PersistPixelCache() method is:
3600 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3601 % const MagickBooleanType attach,MagickOffsetType *offset,
3602 % ExceptionInfo *exception)
3604 % A description of each parameter follows:
3606 % o image: the image.
3608 % o filename: the persistent pixel cache filename.
3610 % o attach: A value other than zero initializes the persistent pixel cache.
3612 % o initialize: A value other than zero initializes the persistent pixel
3615 % o offset: the offset in the persistent cache to store pixels.
3617 % o exception: return any errors or warnings in this structure.
3620 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3621 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3622 ExceptionInfo *exception)
3625 *restrict cache_info,
3626 *restrict clone_info;
3637 assert(image != (Image *) NULL);
3638 assert(image->signature == MagickSignature);
3639 if (image->debug != MagickFalse)
3640 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3641 assert(image->cache != (void *) NULL);
3642 assert(filename != (const char *) NULL);
3643 assert(offset != (MagickOffsetType *) NULL);
3644 page_size=GetMagickPageSize();
3645 cache_info=(CacheInfo *) image->cache;
3646 assert(cache_info->signature == MagickSignature);
3647 if (attach != MagickFalse)
3650 Attach existing persistent pixel cache.
3652 if (image->debug != MagickFalse)
3653 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3654 "attach persistent cache");
3655 (void) CopyMagickString(cache_info->cache_filename,filename,
3657 cache_info->type=DiskCache;
3658 cache_info->offset=(*offset);
3659 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3660 return(MagickFalse);
3661 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3664 if ((cache_info->mode != ReadMode) &&
3665 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3666 (cache_info->reference_count == 1))
3668 LockSemaphoreInfo(cache_info->semaphore);
3669 if ((cache_info->mode != ReadMode) &&
3670 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3671 (cache_info->reference_count == 1))
3677 Usurp existing persistent pixel cache.
3679 status=rename_utf8(cache_info->cache_filename,filename);
3682 (void) CopyMagickString(cache_info->cache_filename,filename,
3684 *offset+=cache_info->length+page_size-(cache_info->length %
3686 UnlockSemaphoreInfo(cache_info->semaphore);
3687 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3688 if (image->debug != MagickFalse)
3689 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3690 "Usurp resident persistent cache");
3694 UnlockSemaphoreInfo(cache_info->semaphore);
3697 Clone persistent pixel cache.
3699 clone_image=(*image);
3700 clone_info=(CacheInfo *) clone_image.cache;
3701 image->cache=ClonePixelCache(cache_info);
3702 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3703 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3704 cache_info->type=DiskCache;
3705 cache_info->offset=(*offset);
3706 cache_info=(CacheInfo *) image->cache;
3707 status=OpenPixelCache(image,IOMode,exception);
3708 if (status != MagickFalse)
3709 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3710 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3711 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3720 + 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 %
3724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3726 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3727 % defined by the region rectangle and returns a pointer to the region. This
3728 % region is subsequently transferred from the pixel cache with
3729 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3730 % pixels are transferred, otherwise a NULL is returned.
3732 % The format of the QueueAuthenticPixelCacheNexus() method is:
3734 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3735 % const ssize_t y,const size_t columns,const size_t rows,
3736 % const MagickBooleanType clone,NexusInfo *nexus_info,
3737 % ExceptionInfo *exception)
3739 % A description of each parameter follows:
3741 % o image: the image.
3743 % o x,y,columns,rows: These values define the perimeter of a region of
3746 % o nexus_info: the cache nexus to set.
3748 % o clone: clone the pixel cache.
3750 % o exception: return any errors or warnings in this structure.
3753 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3754 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3755 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3758 *restrict cache_info;
3773 Validate pixel cache geometry.
3775 assert(image != (const Image *) NULL);
3776 assert(image->signature == MagickSignature);
3777 assert(image->cache != (Cache) NULL);
3778 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3779 if (cache_info == (Cache) NULL)
3780 return((Quantum *) NULL);
3781 assert(cache_info->signature == MagickSignature);
3782 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3783 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3784 (y >= (ssize_t) cache_info->rows))
3786 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3787 "PixelsAreNotAuthentic","`%s'",image->filename);
3788 return((Quantum *) NULL);
3790 offset=(MagickOffsetType) y*cache_info->columns+x;
3792 return((Quantum *) NULL);
3793 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3794 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3795 if ((MagickSizeType) offset >= number_pixels)
3796 return((Quantum *) NULL);
3802 region.width=columns;
3804 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3814 + 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 %
3818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3820 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3821 % defined by the region rectangle and returns a pointer to the region. This
3822 % region is subsequently transferred from the pixel cache with
3823 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3824 % pixels are transferred, otherwise a NULL is returned.
3826 % The format of the QueueAuthenticPixelsCache() method is:
3828 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3829 % const ssize_t y,const size_t columns,const size_t rows,
3830 % ExceptionInfo *exception)
3832 % A description of each parameter follows:
3834 % o image: the image.
3836 % o x,y,columns,rows: These values define the perimeter of a region of
3839 % o exception: return any errors or warnings in this structure.
3842 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3843 const ssize_t y,const size_t columns,const size_t rows,
3844 ExceptionInfo *exception)
3847 *restrict cache_info;
3850 id = GetOpenMPThreadId();
3855 assert(image != (const Image *) NULL);
3856 assert(image->signature == MagickSignature);
3857 assert(image->cache != (Cache) NULL);
3858 cache_info=(CacheInfo *) image->cache;
3859 assert(cache_info->signature == MagickSignature);
3860 assert(id < (int) cache_info->number_threads);
3861 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3862 cache_info->nexus_info[id],exception);
3867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3871 % Q u e u e A u t h e n t i c P i x e l s %
3875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3877 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3878 % successfully initialized a pointer to a Quantum array representing the
3879 % region is returned, otherwise NULL is returned. The returned pointer may
3880 % point to a temporary working buffer for the pixels or it may point to the
3881 % final location of the pixels in memory.
3883 % Write-only access means that any existing pixel values corresponding to
3884 % the region are ignored. This is useful if the initial image is being
3885 % created from scratch, or if the existing pixel values are to be
3886 % completely replaced without need to refer to their pre-existing values.
3887 % The application is free to read and write the pixel buffer returned by
3888 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3889 % initialize the pixel array values. Initializing pixel array values is the
3890 % application's responsibility.
3892 % Performance is maximized if the selected region is part of one row, or
3893 % one or more full rows, since then there is opportunity to access the
3894 % pixels in-place (without a copy) if the image is in memory, or in a
3895 % memory-mapped file. The returned pointer must *never* be deallocated
3898 % Pixels accessed via the returned pointer represent a simple array of type
3899 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3900 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3901 % obtain the meta-content (of type void) corresponding to the region.
3902 % Once the Quantum (and/or Quantum) array has been updated, the
3903 % changes must be saved back to the underlying image using
3904 % SyncAuthenticPixels() or they may be lost.
3906 % The format of the QueueAuthenticPixels() method is:
3908 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3909 % const ssize_t y,const size_t columns,const size_t rows,
3910 % ExceptionInfo *exception)
3912 % A description of each parameter follows:
3914 % o image: the image.
3916 % o x,y,columns,rows: These values define the perimeter of a region of
3919 % o exception: return any errors or warnings in this structure.
3922 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3923 const ssize_t y,const size_t columns,const size_t rows,
3924 ExceptionInfo *exception)
3927 *restrict cache_info;
3930 id = GetOpenMPThreadId();
3935 assert(image != (Image *) NULL);
3936 assert(image->signature == MagickSignature);
3937 assert(image->cache != (Cache) NULL);
3938 cache_info=(CacheInfo *) image->cache;
3939 assert(cache_info->signature == MagickSignature);
3940 if (cache_info->methods.queue_authentic_pixels_handler !=
3941 (QueueAuthenticPixelsHandler) NULL)
3943 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3944 columns,rows,exception);
3947 assert(id < (int) cache_info->number_threads);
3948 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3949 cache_info->nexus_info[id],exception);
3954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3958 + 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 %
3962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3964 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3967 % The format of the ReadPixelCacheMetacontent() method is:
3969 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
3970 % NexusInfo *nexus_info,ExceptionInfo *exception)
3972 % A description of each parameter follows:
3974 % o cache_info: the pixel cache.
3976 % o nexus_info: the cache nexus to read the metacontent.
3978 % o exception: return any errors or warnings in this structure.
3982 static inline MagickOffsetType ReadPixelCacheRegion(
3983 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3984 const MagickSizeType length,unsigned char *restrict buffer)
3986 register MagickOffsetType
3992 #if !defined(MAGICKCORE_HAVE_PREAD)
3993 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3994 return((MagickOffsetType) -1);
3997 for (i=0; i < (MagickOffsetType) length; i+=count)
3999 #if !defined(MAGICKCORE_HAVE_PREAD)
4000 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4001 (MagickSizeType) SSIZE_MAX));
4003 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4004 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4016 static MagickBooleanType ReadPixelCacheMetacontent(
4017 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4018 ExceptionInfo *exception)
4031 register unsigned char
4037 if (cache_info->metacontent_extent == 0)
4038 return(MagickFalse);
4039 if (nexus_info->authentic_pixel_cache != MagickFalse)
4041 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4042 nexus_info->region.x;
4043 length=(MagickSizeType) nexus_info->region.width*
4044 cache_info->metacontent_extent;
4045 extent=length*nexus_info->region.height;
4046 rows=nexus_info->region.height;
4048 q=(unsigned char *) nexus_info->metacontent;
4049 switch (cache_info->type)
4054 register unsigned char
4058 Read meta-content from memory.
4060 if ((cache_info->columns == nexus_info->region.width) &&
4061 (extent == (MagickSizeType) ((size_t) extent)))
4066 p=(unsigned char *) cache_info->metacontent+offset*
4067 cache_info->metacontent_extent;
4068 for (y=0; y < (ssize_t) rows; y++)
4070 (void) memcpy(q,p,(size_t) length);
4071 p+=cache_info->metacontent_extent*cache_info->columns;
4072 q+=cache_info->metacontent_extent*nexus_info->region.width;
4079 Read meta content from disk.
4081 LockSemaphoreInfo(cache_info->file_semaphore);
4082 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4084 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4085 cache_info->cache_filename);
4086 UnlockSemaphoreInfo(cache_info->file_semaphore);
4087 return(MagickFalse);
4089 if ((cache_info->columns == nexus_info->region.width) &&
4090 (extent <= MagickMaxBufferExtent))
4095 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4096 for (y=0; y < (ssize_t) rows; y++)
4098 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4099 cache_info->number_channels*sizeof(Quantum)+offset*
4100 cache_info->metacontent_extent,length,(unsigned char *) q);
4101 if (count != (MagickOffsetType) length)
4103 offset+=cache_info->columns;
4104 q+=cache_info->metacontent_extent*nexus_info->region.width;
4106 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4107 (void) ClosePixelCacheOnDisk(cache_info);
4108 UnlockSemaphoreInfo(cache_info->file_semaphore);
4111 case DistributedCache:
4117 Read metacontent from distributed cache.
4119 LockSemaphoreInfo(cache_info->file_semaphore);
4120 region=nexus_info->region;
4121 if ((cache_info->columns != nexus_info->region.width) ||
4122 (extent > MagickMaxBufferExtent))
4129 for (y=0; y < (ssize_t) rows; y++)
4131 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4132 cache_info->server_info,®ion,length,(unsigned char *) q);
4133 if (count != (MagickOffsetType) length)
4135 q+=cache_info->metacontent_extent*nexus_info->region.width;
4138 UnlockSemaphoreInfo(cache_info->file_semaphore);
4144 if (y < (ssize_t) rows)
4146 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4147 cache_info->cache_filename);
4148 return(MagickFalse);
4150 if ((cache_info->debug != MagickFalse) &&
4151 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4152 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4153 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4154 nexus_info->region.width,(double) nexus_info->region.height,(double)
4155 nexus_info->region.x,(double) nexus_info->region.y);
4160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4164 + R e a d P i x e l C a c h e P i x e l s %
4168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4170 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4173 % The format of the ReadPixelCachePixels() method is:
4175 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4176 % NexusInfo *nexus_info,ExceptionInfo *exception)
4178 % A description of each parameter follows:
4180 % o cache_info: the pixel cache.
4182 % o nexus_info: the cache nexus to read the pixels.
4184 % o exception: return any errors or warnings in this structure.
4187 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4188 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4207 if (nexus_info->authentic_pixel_cache != MagickFalse)
4209 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4210 nexus_info->region.x;
4211 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4213 extent=length*nexus_info->region.height;
4214 rows=nexus_info->region.height;
4216 q=nexus_info->pixels;
4217 switch (cache_info->type)
4226 Read pixels from memory.
4228 if ((cache_info->columns == nexus_info->region.width) &&
4229 (extent == (MagickSizeType) ((size_t) extent)))
4234 p=cache_info->pixels+offset*cache_info->number_channels;
4235 for (y=0; y < (ssize_t) rows; y++)
4237 (void) memcpy(q,p,(size_t) length);
4238 p+=cache_info->number_channels*cache_info->columns;
4239 q+=cache_info->number_channels*nexus_info->region.width;
4246 Read pixels from disk.
4248 LockSemaphoreInfo(cache_info->file_semaphore);
4249 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4251 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4252 cache_info->cache_filename);
4253 UnlockSemaphoreInfo(cache_info->file_semaphore);
4254 return(MagickFalse);
4256 if ((cache_info->columns == nexus_info->region.width) &&
4257 (extent <= MagickMaxBufferExtent))
4262 for (y=0; y < (ssize_t) rows; y++)
4264 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4265 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4266 if (count != (MagickOffsetType) length)
4268 offset+=cache_info->columns;
4269 q+=cache_info->number_channels*nexus_info->region.width;
4271 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4272 (void) ClosePixelCacheOnDisk(cache_info);
4273 UnlockSemaphoreInfo(cache_info->file_semaphore);
4276 case DistributedCache:
4282 Read pixels from distributed cache.
4284 LockSemaphoreInfo(cache_info->file_semaphore);
4285 region=nexus_info->region;
4286 if ((cache_info->columns != nexus_info->region.width) ||
4287 (extent > MagickMaxBufferExtent))
4294 for (y=0; y < (ssize_t) rows; y++)
4296 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4297 cache_info->server_info,®ion,length,(unsigned char *) q);
4298 if (count != (MagickOffsetType) length)
4300 q+=cache_info->number_channels*nexus_info->region.width;
4303 UnlockSemaphoreInfo(cache_info->file_semaphore);
4309 if (y < (ssize_t) rows)
4311 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4312 cache_info->cache_filename);
4313 return(MagickFalse);
4315 if ((cache_info->debug != MagickFalse) &&
4316 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4317 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4318 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4319 nexus_info->region.width,(double) nexus_info->region.height,(double)
4320 nexus_info->region.x,(double) nexus_info->region.y);
4325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4329 + R e f e r e n c e P i x e l C a c h e %
4333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4335 % ReferencePixelCache() increments the reference count associated with the
4336 % pixel cache returning a pointer to the cache.
4338 % The format of the ReferencePixelCache method is:
4340 % Cache ReferencePixelCache(Cache cache_info)
4342 % A description of each parameter follows:
4344 % o cache_info: the pixel cache.
4347 MagickPrivate Cache ReferencePixelCache(Cache cache)
4350 *restrict cache_info;
4352 assert(cache != (Cache *) NULL);
4353 cache_info=(CacheInfo *) cache;
4354 assert(cache_info->signature == MagickSignature);
4355 LockSemaphoreInfo(cache_info->semaphore);
4356 cache_info->reference_count++;
4357 UnlockSemaphoreInfo(cache_info->semaphore);
4362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4366 + S e t P i x e l C a c h e M e t h o d s %
4370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4372 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4374 % The format of the SetPixelCacheMethods() method is:
4376 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4378 % A description of each parameter follows:
4380 % o cache: the pixel cache.
4382 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4385 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4388 *restrict cache_info;
4390 GetOneAuthenticPixelFromHandler
4391 get_one_authentic_pixel_from_handler;
4393 GetOneVirtualPixelFromHandler
4394 get_one_virtual_pixel_from_handler;
4397 Set cache pixel methods.
4399 assert(cache != (Cache) NULL);
4400 assert(cache_methods != (CacheMethods *) NULL);
4401 cache_info=(CacheInfo *) cache;
4402 assert(cache_info->signature == MagickSignature);
4403 if (cache_info->debug != MagickFalse)
4404 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4405 cache_info->filename);
4406 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4407 cache_info->methods.get_virtual_pixel_handler=
4408 cache_methods->get_virtual_pixel_handler;
4409 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4410 cache_info->methods.destroy_pixel_handler=
4411 cache_methods->destroy_pixel_handler;
4412 if (cache_methods->get_virtual_metacontent_from_handler !=
4413 (GetVirtualMetacontentFromHandler) NULL)
4414 cache_info->methods.get_virtual_metacontent_from_handler=
4415 cache_methods->get_virtual_metacontent_from_handler;
4416 if (cache_methods->get_authentic_pixels_handler !=
4417 (GetAuthenticPixelsHandler) NULL)
4418 cache_info->methods.get_authentic_pixels_handler=
4419 cache_methods->get_authentic_pixels_handler;
4420 if (cache_methods->queue_authentic_pixels_handler !=
4421 (QueueAuthenticPixelsHandler) NULL)
4422 cache_info->methods.queue_authentic_pixels_handler=
4423 cache_methods->queue_authentic_pixels_handler;
4424 if (cache_methods->sync_authentic_pixels_handler !=
4425 (SyncAuthenticPixelsHandler) NULL)
4426 cache_info->methods.sync_authentic_pixels_handler=
4427 cache_methods->sync_authentic_pixels_handler;
4428 if (cache_methods->get_authentic_pixels_from_handler !=
4429 (GetAuthenticPixelsFromHandler) NULL)
4430 cache_info->methods.get_authentic_pixels_from_handler=
4431 cache_methods->get_authentic_pixels_from_handler;
4432 if (cache_methods->get_authentic_metacontent_from_handler !=
4433 (GetAuthenticMetacontentFromHandler) NULL)
4434 cache_info->methods.get_authentic_metacontent_from_handler=
4435 cache_methods->get_authentic_metacontent_from_handler;
4436 get_one_virtual_pixel_from_handler=
4437 cache_info->methods.get_one_virtual_pixel_from_handler;
4438 if (get_one_virtual_pixel_from_handler !=
4439 (GetOneVirtualPixelFromHandler) NULL)
4440 cache_info->methods.get_one_virtual_pixel_from_handler=
4441 cache_methods->get_one_virtual_pixel_from_handler;
4442 get_one_authentic_pixel_from_handler=
4443 cache_methods->get_one_authentic_pixel_from_handler;
4444 if (get_one_authentic_pixel_from_handler !=
4445 (GetOneAuthenticPixelFromHandler) NULL)
4446 cache_info->methods.get_one_authentic_pixel_from_handler=
4447 cache_methods->get_one_authentic_pixel_from_handler;
4451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4455 + S e t P i x e l C a c h e N e x u s P i x e l s %
4459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4461 % SetPixelCacheNexusPixels() defines the region of the cache for the
4462 % specified cache nexus.
4464 % The format of the SetPixelCacheNexusPixels() method is:
4466 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4467 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4468 % ExceptionInfo *exception)
4470 % A description of each parameter follows:
4472 % o cache_info: the pixel cache.
4474 % o mode: ReadMode, WriteMode, or IOMode.
4476 % o region: A pointer to the RectangleInfo structure that defines the
4477 % region of this particular cache nexus.
4479 % o nexus_info: the cache nexus to set.
4481 % o exception: return any errors or warnings in this structure.
4485 static inline MagickBooleanType AcquireCacheNexusPixels(
4486 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4487 ExceptionInfo *exception)
4489 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4490 return(MagickFalse);
4491 nexus_info->mapped=MagickFalse;
4492 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4493 (size_t) nexus_info->length));
4494 if (nexus_info->cache == (Quantum *) NULL)
4496 nexus_info->mapped=MagickTrue;
4497 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4498 nexus_info->length);
4500 if (nexus_info->cache == (Quantum *) NULL)
4502 (void) ThrowMagickException(exception,GetMagickModule(),
4503 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4504 cache_info->filename);
4505 return(MagickFalse);
4510 static inline MagickBooleanType IsPixelCacheAuthentic(
4511 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4520 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4522 if (cache_info->type == PingCache)
4524 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4525 nexus_info->region.x;
4526 status=nexus_info->pixels == (cache_info->pixels+offset*
4527 cache_info->number_channels) ? MagickTrue : MagickFalse;
4531 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4534 if (mode == ReadMode)
4536 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4539 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4542 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4543 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4544 ExceptionInfo *exception)
4553 assert(cache_info != (const CacheInfo *) NULL);
4554 assert(cache_info->signature == MagickSignature);
4555 if (cache_info->type == UndefinedCache)
4556 return((Quantum *) NULL);
4557 nexus_info->region=(*region);
4558 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4564 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4565 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4566 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4567 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4568 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4569 ((nexus_info->region.width == cache_info->columns) ||
4570 ((nexus_info->region.width % cache_info->columns) == 0)))))
4576 Pixels are accessed directly from memory.
4578 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4579 nexus_info->region.x;
4580 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4582 nexus_info->metacontent=(void *) NULL;
4583 if (cache_info->metacontent_extent != 0)
4584 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4585 offset*cache_info->metacontent_extent;
4586 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4587 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4589 return(nexus_info->pixels);
4593 Pixels are stored in a staging region until they are synced to the cache.
4595 number_pixels=(MagickSizeType) nexus_info->region.width*
4596 nexus_info->region.height;
4597 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4598 if (cache_info->metacontent_extent != 0)
4599 length+=number_pixels*cache_info->metacontent_extent;
4600 if (nexus_info->cache == (Quantum *) NULL)
4602 nexus_info->length=length;
4603 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4604 if (status == MagickFalse)
4606 nexus_info->length=0;
4607 return((Quantum *) NULL);
4611 if (nexus_info->length < length)
4613 RelinquishCacheNexusPixels(nexus_info);
4614 nexus_info->length=length;
4615 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4616 if (status == MagickFalse)
4618 nexus_info->length=0;
4619 return((Quantum *) NULL);
4622 nexus_info->pixels=nexus_info->cache;
4623 nexus_info->metacontent=(void *) NULL;
4624 if (cache_info->metacontent_extent != 0)
4625 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4626 cache_info->number_channels);
4627 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4628 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4630 return(nexus_info->pixels);
4634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4638 % 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 %
4642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4644 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4645 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4646 % access that is outside the boundaries of the image cache.
4648 % The format of the SetPixelCacheVirtualMethod() method is:
4650 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4651 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4653 % A description of each parameter follows:
4655 % o image: the image.
4657 % o virtual_pixel_method: choose the type of virtual pixel.
4659 % o exception: return any errors or warnings in this structure.
4663 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4664 ExceptionInfo *exception)
4667 *restrict cache_info;
4670 *restrict image_view;
4678 assert(image != (Image *) NULL);
4679 assert(image->signature == MagickSignature);
4680 if (image->debug != MagickFalse)
4681 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4682 assert(image->cache != (Cache) NULL);
4683 cache_info=(CacheInfo *) image->cache;
4684 assert(cache_info->signature == MagickSignature);
4685 image->alpha_trait=BlendPixelTrait;
4687 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4688 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4689 #pragma omp parallel for schedule(static,4) shared(status) \
4690 magick_threads(image,image,1,1)
4692 for (y=0; y < (ssize_t) image->rows; y++)
4700 if (status == MagickFalse)
4702 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4703 if (q == (Quantum *) NULL)
4708 for (x=0; x < (ssize_t) image->columns; x++)
4710 SetPixelAlpha(image,alpha,q);
4711 q+=GetPixelChannels(image);
4713 status=SyncCacheViewAuthenticPixels(image_view,exception);
4715 image_view=DestroyCacheView(image_view);
4719 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4720 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4723 *restrict cache_info;
4728 assert(image != (Image *) NULL);
4729 assert(image->signature == MagickSignature);
4730 if (image->debug != MagickFalse)
4731 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4732 assert(image->cache != (Cache) NULL);
4733 cache_info=(CacheInfo *) image->cache;
4734 assert(cache_info->signature == MagickSignature);
4735 method=cache_info->virtual_pixel_method;
4736 cache_info->virtual_pixel_method=virtual_pixel_method;
4737 if ((image->columns != 0) && (image->rows != 0))
4738 switch (virtual_pixel_method)
4740 case BackgroundVirtualPixelMethod:
4742 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4743 (image->alpha_trait != BlendPixelTrait))
4744 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4745 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4746 (IsGrayColorspace(image->colorspace) != MagickFalse))
4747 (void) SetImageColorspace(image,sRGBColorspace,exception);
4750 case TransparentVirtualPixelMethod:
4752 if (image->alpha_trait != BlendPixelTrait)
4753 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4767 + 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 %
4771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4773 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4774 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4775 % is synced, otherwise MagickFalse.
4777 % The format of the SyncAuthenticPixelCacheNexus() method is:
4779 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4780 % NexusInfo *nexus_info,ExceptionInfo *exception)
4782 % A description of each parameter follows:
4784 % o image: the image.
4786 % o nexus_info: the cache nexus to sync.
4788 % o exception: return any errors or warnings in this structure.
4791 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4792 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4795 *restrict cache_info;
4801 Transfer pixels to the cache.
4803 assert(image != (Image *) NULL);
4804 assert(image->signature == MagickSignature);
4805 if (image->cache == (Cache) NULL)
4806 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4807 cache_info=(CacheInfo *) image->cache;
4808 assert(cache_info->signature == MagickSignature);
4809 if (cache_info->type == UndefinedCache)
4810 return(MagickFalse);
4811 if (nexus_info->authentic_pixel_cache != MagickFalse)
4813 assert(cache_info->signature == MagickSignature);
4814 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4815 if ((cache_info->metacontent_extent != 0) &&
4816 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4817 return(MagickFalse);
4822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4826 + S y n c A u t h e n t i c P i x e l C a c h e %
4830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4832 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4833 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4834 % otherwise MagickFalse.
4836 % The format of the SyncAuthenticPixelsCache() method is:
4838 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4839 % ExceptionInfo *exception)
4841 % A description of each parameter follows:
4843 % o image: the image.
4845 % o exception: return any errors or warnings in this structure.
4848 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4849 ExceptionInfo *exception)
4852 *restrict cache_info;
4855 id = GetOpenMPThreadId();
4860 assert(image != (Image *) NULL);
4861 assert(image->signature == MagickSignature);
4862 assert(image->cache != (Cache) NULL);
4863 cache_info=(CacheInfo *) image->cache;
4864 assert(cache_info->signature == MagickSignature);
4865 assert(id < (int) cache_info->number_threads);
4866 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4876 % S y n c A u t h e n t i c P i x e l s %
4880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4882 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4883 % The method returns MagickTrue if the pixel region is flushed, otherwise
4886 % The format of the SyncAuthenticPixels() method is:
4888 % MagickBooleanType SyncAuthenticPixels(Image *image,
4889 % ExceptionInfo *exception)
4891 % A description of each parameter follows:
4893 % o image: the image.
4895 % o exception: return any errors or warnings in this structure.
4898 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4899 ExceptionInfo *exception)
4902 *restrict cache_info;
4905 id = GetOpenMPThreadId();
4910 assert(image != (Image *) NULL);
4911 assert(image->signature == MagickSignature);
4912 assert(image->cache != (Cache) NULL);
4913 cache_info=(CacheInfo *) image->cache;
4914 assert(cache_info->signature == MagickSignature);
4915 if (cache_info->methods.sync_authentic_pixels_handler !=
4916 (SyncAuthenticPixelsHandler) NULL)
4918 status=cache_info->methods.sync_authentic_pixels_handler(image,
4922 assert(id < (int) cache_info->number_threads);
4923 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4933 + S y n c I m a g e P i x e l C a c h e %
4937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4939 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4940 % The method returns MagickTrue if the pixel region is flushed, otherwise
4943 % The format of the SyncImagePixelCache() method is:
4945 % MagickBooleanType SyncImagePixelCache(Image *image,
4946 % ExceptionInfo *exception)
4948 % A description of each parameter follows:
4950 % o image: the image.
4952 % o exception: return any errors or warnings in this structure.
4955 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4956 ExceptionInfo *exception)
4959 *restrict cache_info;
4961 assert(image != (Image *) NULL);
4962 assert(exception != (ExceptionInfo *) NULL);
4963 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4964 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4972 + 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 %
4976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4978 % WritePixelCacheMetacontent() writes the meta-content to the specified region
4979 % of the pixel cache.
4981 % The format of the WritePixelCacheMetacontent() method is:
4983 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4984 % NexusInfo *nexus_info,ExceptionInfo *exception)
4986 % A description of each parameter follows:
4988 % o cache_info: the pixel cache.
4990 % o nexus_info: the cache nexus to write the meta-content.
4992 % o exception: return any errors or warnings in this structure.
4995 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4996 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5006 register const unsigned char
5015 if (cache_info->metacontent_extent == 0)
5016 return(MagickFalse);
5017 if (nexus_info->authentic_pixel_cache != MagickFalse)
5019 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5020 nexus_info->region.x;
5021 length=(MagickSizeType) nexus_info->region.width*
5022 cache_info->metacontent_extent;
5023 extent=(MagickSizeType) length*nexus_info->region.height;
5024 rows=nexus_info->region.height;
5026 p=(unsigned char *) nexus_info->metacontent;
5027 switch (cache_info->type)
5032 register unsigned char
5036 Write associated pixels to memory.
5038 if ((cache_info->columns == nexus_info->region.width) &&
5039 (extent == (MagickSizeType) ((size_t) extent)))
5044 q=(unsigned char *) cache_info->metacontent+offset*
5045 cache_info->metacontent_extent;
5046 for (y=0; y < (ssize_t) rows; y++)
5048 (void) memcpy(q,p,(size_t) length);
5049 p+=nexus_info->region.width*cache_info->metacontent_extent;
5050 q+=cache_info->columns*cache_info->metacontent_extent;
5057 Write associated pixels to disk.
5059 LockSemaphoreInfo(cache_info->file_semaphore);
5060 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5062 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5063 cache_info->cache_filename);
5064 UnlockSemaphoreInfo(cache_info->file_semaphore);
5065 return(MagickFalse);
5067 if ((cache_info->columns == nexus_info->region.width) &&
5068 (extent <= MagickMaxBufferExtent))
5073 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5074 for (y=0; y < (ssize_t) rows; y++)
5076 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5077 cache_info->number_channels*sizeof(Quantum)+offset*
5078 cache_info->metacontent_extent,length,(const unsigned char *) p);
5079 if (count != (MagickOffsetType) length)
5081 p+=cache_info->metacontent_extent*nexus_info->region.width;
5082 offset+=cache_info->columns;
5084 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5085 (void) ClosePixelCacheOnDisk(cache_info);
5086 UnlockSemaphoreInfo(cache_info->file_semaphore);
5089 case DistributedCache:
5095 Write metacontent to distributed cache.
5097 LockSemaphoreInfo(cache_info->file_semaphore);
5098 region=nexus_info->region;
5099 if ((cache_info->columns != nexus_info->region.width) ||
5100 (extent > MagickMaxBufferExtent))
5107 for (y=0; y < (ssize_t) rows; y++)
5109 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5110 cache_info->server_info,®ion,length,(const unsigned char *) p);
5111 if (count != (MagickOffsetType) length)
5113 p+=cache_info->metacontent_extent*nexus_info->region.width;
5116 UnlockSemaphoreInfo(cache_info->file_semaphore);
5122 if (y < (ssize_t) rows)
5124 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5125 cache_info->cache_filename);
5126 return(MagickFalse);
5128 if ((cache_info->debug != MagickFalse) &&
5129 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5130 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5131 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5132 nexus_info->region.width,(double) nexus_info->region.height,(double)
5133 nexus_info->region.x,(double) nexus_info->region.y);
5138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5142 + W r i t e C a c h e P i x e l s %
5146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5148 % WritePixelCachePixels() writes image pixels to the specified region of the
5151 % The format of the WritePixelCachePixels() method is:
5153 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5154 % NexusInfo *nexus_info,ExceptionInfo *exception)
5156 % A description of each parameter follows:
5158 % o cache_info: the pixel cache.
5160 % o nexus_info: the cache nexus to write the pixels.
5162 % o exception: return any errors or warnings in this structure.
5165 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5166 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5176 register const Quantum
5185 if (nexus_info->authentic_pixel_cache != MagickFalse)
5187 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5188 nexus_info->region.x;
5189 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5191 extent=length*nexus_info->region.height;
5192 rows=nexus_info->region.height;
5194 p=nexus_info->pixels;
5195 switch (cache_info->type)
5204 Write pixels to memory.
5206 if ((cache_info->columns == nexus_info->region.width) &&
5207 (extent == (MagickSizeType) ((size_t) extent)))
5212 q=cache_info->pixels+offset*cache_info->number_channels;
5213 for (y=0; y < (ssize_t) rows; y++)
5215 (void) memcpy(q,p,(size_t) length);
5216 p+=cache_info->number_channels*nexus_info->region.width;
5217 q+=cache_info->columns*cache_info->number_channels;
5224 Write pixels to disk.
5226 LockSemaphoreInfo(cache_info->file_semaphore);
5227 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5229 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5230 cache_info->cache_filename);
5231 UnlockSemaphoreInfo(cache_info->file_semaphore);
5232 return(MagickFalse);
5234 if ((cache_info->columns == nexus_info->region.width) &&
5235 (extent <= MagickMaxBufferExtent))
5240 for (y=0; y < (ssize_t) rows; y++)
5242 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5243 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5245 if (count != (MagickOffsetType) length)
5247 p+=cache_info->number_channels*nexus_info->region.width;
5248 offset+=cache_info->columns;
5250 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5251 (void) ClosePixelCacheOnDisk(cache_info);
5252 UnlockSemaphoreInfo(cache_info->file_semaphore);
5255 case DistributedCache:
5261 Write pixels to distributed cache.
5263 LockSemaphoreInfo(cache_info->file_semaphore);
5264 region=nexus_info->region;
5265 if ((cache_info->columns != nexus_info->region.width) ||
5266 (extent > MagickMaxBufferExtent))
5273 for (y=0; y < (ssize_t) rows; y++)
5275 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5276 cache_info->server_info,®ion,length,(const unsigned char *) p);
5277 if (count != (MagickOffsetType) length)
5279 p+=cache_info->number_channels*nexus_info->region.width;
5282 UnlockSemaphoreInfo(cache_info->file_semaphore);
5288 if (y < (ssize_t) rows)
5290 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5291 cache_info->cache_filename);
5292 return(MagickFalse);
5294 if ((cache_info->debug != MagickFalse) &&
5295 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5296 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5297 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5298 nexus_info->region.width,(double) nexus_info->region.height,(double)
5299 nexus_info->region.x,(double) nexus_info->region.y);