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));
480 register MagickOffsetType
483 if ((number_pixels*sizeof(*source)) < MagickMaxBufferExtent)
485 (void) memcpy(destination,source,(size_t) number_pixels*
489 #pragma omp parallel for
490 for (i=0; i < (MagickOffsetType) number_pixels; i++)
491 destination[i]=source[i];
496 static inline MagickSizeType MagickMin(const MagickSizeType x,
497 const MagickSizeType y)
504 static MagickBooleanType ClonePixelCacheRepository(
505 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
506 ExceptionInfo *exception)
508 #define MaxCacheThreads 2
509 #define cache_threads(source,destination,chunk) \
510 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
511 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
512 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
519 **restrict cache_nexus,
520 **restrict clone_nexus;
528 assert(cache_info != (CacheInfo *) NULL);
529 assert(clone_info != (CacheInfo *) NULL);
530 assert(exception != (ExceptionInfo *) NULL);
531 if (cache_info->type == PingCache)
533 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
534 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
535 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
536 (cache_info->columns == clone_info->columns) &&
537 (cache_info->rows == clone_info->rows) &&
538 (cache_info->number_channels == clone_info->number_channels) &&
539 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
540 (cache_info->metacontent_extent == clone_info->metacontent_extent))
542 CopyPixels(clone_info->pixels,cache_info->pixels,cache_info->columns*
543 cache_info->number_channels*cache_info->rows);
544 if (cache_info->metacontent_extent != 0)
545 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
546 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
547 sizeof(cache_info->metacontent));
551 Mismatched pixel cache morphology.
553 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
554 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
555 if ((cache_nexus == (NexusInfo **) NULL) ||
556 (clone_nexus == (NexusInfo **) NULL))
557 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
558 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
559 optimize=(cache_info->number_channels == clone_info->number_channels) &&
560 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
561 MagickTrue : MagickFalse;
562 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
563 clone_info->columns*clone_info->number_channels);
565 #if defined(MAGICKCORE_OPENMP_SUPPORT)
566 #pragma omp parallel for schedule(static,4) shared(status) \
567 cache_threads(cache_info,clone_info,cache_info->rows)
569 for (y=0; y < (ssize_t) cache_info->rows; y++)
572 id = GetOpenMPThreadId();
583 if (status == MagickFalse)
585 if (y >= (ssize_t) clone_info->rows)
587 region.width=cache_info->columns;
591 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
593 if (pixels == (Quantum *) NULL)
595 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
596 if (status == MagickFalse)
598 region.width=clone_info->columns;
599 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
600 clone_nexus[id],exception);
601 if (pixels == (Quantum *) NULL)
603 if (optimize != MagickFalse)
604 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
608 register const Quantum
615 Mismatched pixel channel map.
617 p=cache_nexus[id]->pixels;
618 q=clone_nexus[id]->pixels;
619 for (x=0; x < (ssize_t) cache_info->columns; x++)
624 if (x == (ssize_t) clone_info->columns)
626 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
634 channel=clone_info->channel_map[i].channel;
635 traits=cache_info->channel_map[channel].traits;
636 if (traits != UndefinedPixelTrait)
637 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
641 p+=cache_info->number_channels;
644 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
646 if ((cache_info->metacontent_extent != 0) &&
647 (clone_info->metacontent_extent != 0))
652 length=(size_t) MagickMin(cache_info->metacontent_extent,
653 clone_info->metacontent_extent);
654 #if defined(MAGICKCORE_OPENMP_SUPPORT)
655 #pragma omp parallel for schedule(static,4) shared(status) \
656 cache_threads(cache_info,clone_info,cache_info->rows)
658 for (y=0; y < (ssize_t) cache_info->rows; y++)
661 id = GetOpenMPThreadId();
669 if (status == MagickFalse)
671 if (y >= (ssize_t) clone_info->rows)
673 region.width=cache_info->columns;
677 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
678 cache_nexus[id],exception);
679 if (pixels == (Quantum *) NULL)
681 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
682 if (status == MagickFalse)
684 region.width=clone_info->columns;
685 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
686 clone_nexus[id],exception);
687 if (pixels == (Quantum *) NULL)
689 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
690 length*sizeof(cache_nexus[id]->metacontent));
691 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
694 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
695 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
696 if (cache_info->debug != MagickFalse)
699 message[MaxTextExtent];
701 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
702 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
703 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
704 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 + D e s t r o y I m a g e P i x e l C a c h e %
718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
722 % The format of the DestroyImagePixelCache() method is:
724 % void DestroyImagePixelCache(Image *image)
726 % A description of each parameter follows:
728 % o image: the image.
731 static void DestroyImagePixelCache(Image *image)
733 assert(image != (Image *) NULL);
734 assert(image->signature == MagickSignature);
735 if (image->debug != MagickFalse)
736 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
737 if (image->cache == (void *) NULL)
739 image->cache=DestroyPixelCache(image->cache);
743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747 + D e s t r o y I m a g e P i x e l s %
751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753 % DestroyImagePixels() deallocates memory associated with the pixel cache.
755 % The format of the DestroyImagePixels() method is:
757 % void DestroyImagePixels(Image *image)
759 % A description of each parameter follows:
761 % o image: the image.
764 MagickExport void DestroyImagePixels(Image *image)
767 *restrict cache_info;
769 assert(image != (const Image *) NULL);
770 assert(image->signature == MagickSignature);
771 if (image->debug != MagickFalse)
772 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
773 assert(image->cache != (Cache) NULL);
774 cache_info=(CacheInfo *) image->cache;
775 assert(cache_info->signature == MagickSignature);
776 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
778 cache_info->methods.destroy_pixel_handler(image);
781 image->cache=DestroyPixelCache(image->cache);
785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789 + D e s t r o y P i x e l C a c h e %
793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795 % DestroyPixelCache() deallocates memory associated with the pixel cache.
797 % The format of the DestroyPixelCache() method is:
799 % Cache DestroyPixelCache(Cache cache)
801 % A description of each parameter follows:
803 % o cache: the pixel cache.
807 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
813 if (cache_info->file != -1)
815 status=close(cache_info->file);
816 cache_info->file=(-1);
817 RelinquishMagickResource(FileResource,1);
819 return(status == -1 ? MagickFalse : MagickTrue);
822 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
824 switch (cache_info->type)
828 if (cache_info->mapped == MagickFalse)
829 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
832 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
833 (size_t) cache_info->length);
834 RelinquishMagickResource(MemoryResource,cache_info->length);
839 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
841 if (cache_info->mode != ReadMode)
842 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
843 *cache_info->cache_filename='\0';
844 RelinquishMagickResource(MapResource,cache_info->length);
848 if (cache_info->file != -1)
849 (void) ClosePixelCacheOnDisk(cache_info);
850 if (cache_info->mode != ReadMode)
851 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
852 *cache_info->cache_filename='\0';
853 RelinquishMagickResource(DiskResource,cache_info->length);
856 case DistributedCache:
858 *cache_info->cache_filename='\0';
859 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
860 cache_info->server_info);
866 cache_info->type=UndefinedCache;
867 cache_info->mapped=MagickFalse;
868 cache_info->metacontent=(void *) NULL;
871 MagickPrivate Cache DestroyPixelCache(Cache cache)
874 *restrict cache_info;
876 assert(cache != (Cache) NULL);
877 cache_info=(CacheInfo *) cache;
878 assert(cache_info->signature == MagickSignature);
879 if (cache_info->debug != MagickFalse)
880 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
881 cache_info->filename);
882 LockSemaphoreInfo(cache_info->semaphore);
883 cache_info->reference_count--;
884 if (cache_info->reference_count != 0)
886 UnlockSemaphoreInfo(cache_info->semaphore);
887 return((Cache) NULL);
889 UnlockSemaphoreInfo(cache_info->semaphore);
890 if (cache_info->debug != MagickFalse)
893 message[MaxTextExtent];
895 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
896 cache_info->filename);
897 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
899 RelinquishPixelCachePixels(cache_info);
900 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
901 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
902 cache_info->server_info);
903 if (cache_info->nexus_info != (NexusInfo **) NULL)
904 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
905 cache_info->number_threads);
906 if (cache_info->random_info != (RandomInfo *) NULL)
907 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
908 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
909 DestroySemaphoreInfo(&cache_info->file_semaphore);
910 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
911 DestroySemaphoreInfo(&cache_info->semaphore);
912 cache_info->signature=(~MagickSignature);
913 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923 + D e s t r o y P i x e l C a c h e N e x u s %
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
931 % The format of the DestroyPixelCacheNexus() method is:
933 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
934 % const size_t number_threads)
936 % A description of each parameter follows:
938 % o nexus_info: the nexus to destroy.
940 % o number_threads: the number of nexus threads.
944 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
946 if (nexus_info->mapped == MagickFalse)
947 (void) RelinquishAlignedMemory(nexus_info->cache);
949 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
950 nexus_info->cache=(Quantum *) NULL;
951 nexus_info->pixels=(Quantum *) NULL;
952 nexus_info->metacontent=(void *) NULL;
953 nexus_info->length=0;
954 nexus_info->mapped=MagickFalse;
957 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
958 const size_t number_threads)
963 assert(nexus_info != (NexusInfo **) NULL);
964 for (i=0; i < (ssize_t) number_threads; i++)
966 if (nexus_info[i]->cache != (Quantum *) NULL)
967 RelinquishCacheNexusPixels(nexus_info[i]);
968 nexus_info[i]->signature=(~MagickSignature);
970 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
971 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980 % G e t A u t h e n t i c M e t a c o n t e n t %
984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
987 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
988 % returned if the associated pixels are not available.
990 % The format of the GetAuthenticMetacontent() method is:
992 % void *GetAuthenticMetacontent(const Image *image)
994 % A description of each parameter follows:
996 % o image: the image.
999 MagickExport void *GetAuthenticMetacontent(const Image *image)
1002 *restrict cache_info;
1005 id = GetOpenMPThreadId();
1007 assert(image != (const Image *) NULL);
1008 assert(image->signature == MagickSignature);
1009 assert(image->cache != (Cache) NULL);
1010 cache_info=(CacheInfo *) image->cache;
1011 assert(cache_info->signature == MagickSignature);
1012 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1013 (GetAuthenticMetacontentFromHandler) NULL)
1018 metacontent=cache_info->methods.
1019 get_authentic_metacontent_from_handler(image);
1020 return(metacontent);
1022 assert(id < (int) cache_info->number_threads);
1023 return(cache_info->nexus_info[id]->metacontent);
1027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1031 + 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 %
1035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1037 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1038 % with the last call to QueueAuthenticPixelsCache() or
1039 % GetAuthenticPixelsCache().
1041 % The format of the GetAuthenticMetacontentFromCache() method is:
1043 % void *GetAuthenticMetacontentFromCache(const Image *image)
1045 % A description of each parameter follows:
1047 % o image: the image.
1050 static void *GetAuthenticMetacontentFromCache(const Image *image)
1053 *restrict cache_info;
1056 id = GetOpenMPThreadId();
1058 assert(image != (const Image *) NULL);
1059 assert(image->signature == MagickSignature);
1060 assert(image->cache != (Cache) NULL);
1061 cache_info=(CacheInfo *) image->cache;
1062 assert(cache_info->signature == MagickSignature);
1063 assert(id < (int) cache_info->number_threads);
1064 return(cache_info->nexus_info[id]->metacontent);
1068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072 + 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 %
1076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1079 % disk pixel cache as defined by the geometry parameters. A pointer to the
1080 % pixels is returned if the pixels are transferred, otherwise a NULL is
1083 % The format of the GetAuthenticPixelCacheNexus() method is:
1085 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1086 % const ssize_t y,const size_t columns,const size_t rows,
1087 % NexusInfo *nexus_info,ExceptionInfo *exception)
1089 % A description of each parameter follows:
1091 % o image: the image.
1093 % o x,y,columns,rows: These values define the perimeter of a region of
1096 % o nexus_info: the cache nexus to return.
1098 % o exception: return any errors or warnings in this structure.
1102 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1103 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1104 ExceptionInfo *exception)
1107 *restrict cache_info;
1113 Transfer pixels from the cache.
1115 assert(image != (Image *) NULL);
1116 assert(image->signature == MagickSignature);
1117 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1118 nexus_info,exception);
1119 if (pixels == (Quantum *) NULL)
1120 return((Quantum *) NULL);
1121 cache_info=(CacheInfo *) image->cache;
1122 assert(cache_info->signature == MagickSignature);
1123 if (nexus_info->authentic_pixel_cache != MagickFalse)
1125 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1126 return((Quantum *) NULL);
1127 if (cache_info->metacontent_extent != 0)
1128 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1129 return((Quantum *) NULL);
1134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138 + 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 %
1142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1144 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1145 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1147 % The format of the GetAuthenticPixelsFromCache() method is:
1149 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1151 % A description of each parameter follows:
1153 % o image: the image.
1156 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1159 *restrict cache_info;
1162 id = GetOpenMPThreadId();
1164 assert(image != (const Image *) NULL);
1165 assert(image->signature == MagickSignature);
1166 assert(image->cache != (Cache) NULL);
1167 cache_info=(CacheInfo *) image->cache;
1168 assert(cache_info->signature == MagickSignature);
1169 assert(id < (int) cache_info->number_threads);
1170 return(cache_info->nexus_info[id]->pixels);
1174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1178 % G e t A u t h e n t i c P i x e l Q u e u e %
1182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1184 % GetAuthenticPixelQueue() returns the authentic pixels associated
1185 % corresponding with the last call to QueueAuthenticPixels() or
1186 % GetAuthenticPixels().
1188 % The format of the GetAuthenticPixelQueue() method is:
1190 % Quantum *GetAuthenticPixelQueue(const Image image)
1192 % A description of each parameter follows:
1194 % o image: the image.
1197 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1200 *restrict cache_info;
1203 id = GetOpenMPThreadId();
1205 assert(image != (const Image *) NULL);
1206 assert(image->signature == MagickSignature);
1207 assert(image->cache != (Cache) NULL);
1208 cache_info=(CacheInfo *) image->cache;
1209 assert(cache_info->signature == MagickSignature);
1210 if (cache_info->methods.get_authentic_pixels_from_handler !=
1211 (GetAuthenticPixelsFromHandler) NULL)
1212 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1213 assert(id < (int) cache_info->number_threads);
1214 return(cache_info->nexus_info[id]->pixels);
1218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1222 % G e t A u t h e n t i c P i x e l s %
1225 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1227 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1228 % region is successfully accessed, a pointer to a Quantum array
1229 % representing the region is returned, otherwise NULL is returned.
1231 % The returned pointer may point to a temporary working copy of the pixels
1232 % or it may point to the original pixels in memory. Performance is maximized
1233 % if the selected region is part of one row, or one or more full rows, since
1234 % then there is opportunity to access the pixels in-place (without a copy)
1235 % if the image is in memory, or in a memory-mapped file. The returned pointer
1236 % must *never* be deallocated by the user.
1238 % Pixels accessed via the returned pointer represent a simple array of type
1239 % Quantum. If the image has corresponding metacontent,call
1240 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1241 % meta-content corresponding to the region. Once the Quantum array has
1242 % been updated, the changes must be saved back to the underlying image using
1243 % SyncAuthenticPixels() or they may be lost.
1245 % The format of the GetAuthenticPixels() method is:
1247 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1248 % const ssize_t y,const size_t columns,const size_t rows,
1249 % ExceptionInfo *exception)
1251 % A description of each parameter follows:
1253 % o image: the image.
1255 % o x,y,columns,rows: These values define the perimeter of a region of
1258 % o exception: return any errors or warnings in this structure.
1261 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1262 const ssize_t y,const size_t columns,const size_t rows,
1263 ExceptionInfo *exception)
1266 *restrict cache_info;
1269 id = GetOpenMPThreadId();
1274 assert(image != (Image *) NULL);
1275 assert(image->signature == MagickSignature);
1276 assert(image->cache != (Cache) NULL);
1277 cache_info=(CacheInfo *) image->cache;
1278 assert(cache_info->signature == MagickSignature);
1279 if (cache_info->methods.get_authentic_pixels_handler !=
1280 (GetAuthenticPixelsHandler) NULL)
1282 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1286 assert(id < (int) cache_info->number_threads);
1287 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1288 cache_info->nexus_info[id],exception);
1293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 + G e t A u t h e n t i c P i x e l s C a c h e %
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1304 % as defined by the geometry parameters. A pointer to the pixels is returned
1305 % if the pixels are transferred, otherwise a NULL is returned.
1307 % The format of the GetAuthenticPixelsCache() method is:
1309 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1310 % const ssize_t y,const size_t columns,const size_t rows,
1311 % ExceptionInfo *exception)
1313 % A description of each parameter follows:
1315 % o image: the image.
1317 % o x,y,columns,rows: These values define the perimeter of a region of
1320 % o exception: return any errors or warnings in this structure.
1323 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1324 const ssize_t y,const size_t columns,const size_t rows,
1325 ExceptionInfo *exception)
1328 *restrict cache_info;
1331 id = GetOpenMPThreadId();
1336 assert(image != (const Image *) NULL);
1337 assert(image->signature == MagickSignature);
1338 assert(image->cache != (Cache) NULL);
1339 cache_info=(CacheInfo *) image->cache;
1340 if (cache_info == (Cache) NULL)
1341 return((Quantum *) NULL);
1342 assert(cache_info->signature == MagickSignature);
1343 assert(id < (int) cache_info->number_threads);
1344 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1345 cache_info->nexus_info[id],exception);
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 + G e t I m a g e E x t e n t %
1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360 % GetImageExtent() returns the extent of the pixels associated corresponding
1361 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1363 % The format of the GetImageExtent() method is:
1365 % MagickSizeType GetImageExtent(const Image *image)
1367 % A description of each parameter follows:
1369 % o image: the image.
1372 MagickExport MagickSizeType GetImageExtent(const Image *image)
1375 *restrict cache_info;
1378 id = GetOpenMPThreadId();
1380 assert(image != (Image *) NULL);
1381 assert(image->signature == MagickSignature);
1382 if (image->debug != MagickFalse)
1383 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1384 assert(image->cache != (Cache) NULL);
1385 cache_info=(CacheInfo *) image->cache;
1386 assert(cache_info->signature == MagickSignature);
1387 assert(id < (int) cache_info->number_threads);
1388 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 + G e t I m a g e P i x e l C a c h e %
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 % GetImagePixelCache() ensures that there is only a single reference to the
1403 % pixel cache to be modified, updating the provided cache pointer to point to
1404 % a clone of the original pixel cache if necessary.
1406 % The format of the GetImagePixelCache method is:
1408 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1409 % ExceptionInfo *exception)
1411 % A description of each parameter follows:
1413 % o image: the image.
1415 % o clone: any value other than MagickFalse clones the cache pixels.
1417 % o exception: return any errors or warnings in this structure.
1421 static inline MagickBooleanType ValidatePixelCacheMorphology(
1422 const Image *restrict image)
1425 *restrict cache_info;
1427 const PixelChannelMap
1432 Does the image match the pixel cache morphology?
1434 cache_info=(CacheInfo *) image->cache;
1435 p=image->channel_map;
1436 q=cache_info->channel_map;
1437 if ((image->storage_class != cache_info->storage_class) ||
1438 (image->colorspace != cache_info->colorspace) ||
1439 (image->alpha_trait != cache_info->alpha_trait) ||
1440 (image->read_mask != cache_info->read_mask) ||
1441 (image->write_mask != cache_info->write_mask) ||
1442 (image->columns != cache_info->columns) ||
1443 (image->rows != cache_info->rows) ||
1444 (image->number_channels != cache_info->number_channels) ||
1445 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1446 (image->metacontent_extent != cache_info->metacontent_extent) ||
1447 (cache_info->nexus_info == (NexusInfo **) NULL))
1448 return(MagickFalse);
1452 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1453 ExceptionInfo *exception)
1456 *restrict cache_info;
1462 static MagickSizeType
1468 cache_timestamp = 0;
1471 LockSemaphoreInfo(image->semaphore);
1472 if (cpu_throttle == 0)
1473 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1474 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1475 MagickDelay(cpu_throttle);
1476 if (time_limit == 0)
1479 Set the expire time in seconds.
1481 time_limit=GetMagickResourceLimit(TimeResource);
1482 cache_timestamp=time((time_t *) NULL);
1484 if ((time_limit != MagickResourceInfinity) &&
1485 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1486 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1487 assert(image->cache != (Cache) NULL);
1488 cache_info=(CacheInfo *) image->cache;
1489 destroy=MagickFalse;
1490 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1492 LockSemaphoreInfo(cache_info->semaphore);
1493 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1504 clone_image=(*image);
1505 clone_image.semaphore=AllocateSemaphoreInfo();
1506 clone_image.reference_count=1;
1507 clone_image.cache=ClonePixelCache(cache_info);
1508 clone_info=(CacheInfo *) clone_image.cache;
1509 status=OpenPixelCache(&clone_image,IOMode,exception);
1510 if (status != MagickFalse)
1512 if (clone != MagickFalse)
1513 status=ClonePixelCacheRepository(clone_info,cache_info,
1515 if (status != MagickFalse)
1517 if (cache_info->reference_count == 1)
1518 cache_info->nexus_info=(NexusInfo **) NULL;
1520 image->cache=clone_image.cache;
1523 DestroySemaphoreInfo(&clone_image.semaphore);
1525 UnlockSemaphoreInfo(cache_info->semaphore);
1527 if (destroy != MagickFalse)
1528 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1529 if (status != MagickFalse)
1532 Ensure the image matches the pixel cache morphology.
1534 image->taint=MagickTrue;
1535 image->type=UndefinedType;
1536 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1538 status=OpenPixelCache(image,IOMode,exception);
1539 cache_info=(CacheInfo *) image->cache;
1540 if (cache_info->type == DiskCache)
1541 (void) ClosePixelCacheOnDisk(cache_info);
1544 UnlockSemaphoreInfo(image->semaphore);
1545 if (status == MagickFalse)
1546 return((Cache) NULL);
1547 return(image->cache);
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555 + G e t I m a g e P i x e l C a c h e T y p e %
1559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1561 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1562 % DiskCache, MemoryCache, MapCache, or PingCache.
1564 % The format of the GetImagePixelCacheType() method is:
1566 % CacheType GetImagePixelCacheType(const Image *image)
1568 % A description of each parameter follows:
1570 % o image: the image.
1573 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1576 *restrict cache_info;
1578 assert(image != (Image *) NULL);
1579 assert(image->signature == MagickSignature);
1580 assert(image->cache != (Cache) NULL);
1581 cache_info=(CacheInfo *) image->cache;
1582 assert(cache_info->signature == MagickSignature);
1583 return(cache_info->type);
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1591 % G e t O n e A u t h e n t i c P i x e l %
1595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1598 % location. The image background color is returned if an error occurs.
1600 % The format of the GetOneAuthenticPixel() method is:
1602 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1603 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1605 % A description of each parameter follows:
1607 % o image: the image.
1609 % o x,y: These values define the location of the pixel to return.
1611 % o pixel: return a pixel at the specified (x,y) location.
1613 % o exception: return any errors or warnings in this structure.
1616 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1617 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1620 *restrict cache_info;
1628 assert(image != (Image *) NULL);
1629 assert(image->signature == MagickSignature);
1630 assert(image->cache != (Cache) NULL);
1631 cache_info=(CacheInfo *) image->cache;
1632 assert(cache_info->signature == MagickSignature);
1633 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1634 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1635 (GetOneAuthenticPixelFromHandler) NULL)
1636 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1638 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1639 if (q == (Quantum *) NULL)
1641 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1642 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1643 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1644 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1645 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1646 return(MagickFalse);
1648 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1650 PixelChannel channel=GetPixelChannelChannel(image,i);
1651 pixel[channel]=q[i];
1657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1661 + 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 %
1665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1668 % location. The image background color is returned if an error occurs.
1670 % The format of the GetOneAuthenticPixelFromCache() method is:
1672 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1673 % const ssize_t x,const ssize_t y,Quantum *pixel,
1674 % ExceptionInfo *exception)
1676 % A description of each parameter follows:
1678 % o image: the image.
1680 % o x,y: These values define the location of the pixel to return.
1682 % o pixel: return a pixel at the specified (x,y) location.
1684 % o exception: return any errors or warnings in this structure.
1687 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1688 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1691 *restrict cache_info;
1694 id = GetOpenMPThreadId();
1702 assert(image != (const Image *) NULL);
1703 assert(image->signature == MagickSignature);
1704 assert(image->cache != (Cache) NULL);
1705 cache_info=(CacheInfo *) image->cache;
1706 assert(cache_info->signature == MagickSignature);
1707 assert(id < (int) cache_info->number_threads);
1708 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1709 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1711 if (q == (Quantum *) NULL)
1713 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1714 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1715 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1716 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1717 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1718 return(MagickFalse);
1720 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1722 PixelChannel channel=GetPixelChannelChannel(image,i);
1723 pixel[channel]=q[i];
1729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1733 % G e t O n e V i r t u a l P i x e l %
1737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1740 % (x,y) location. The image background color is returned if an error occurs.
1741 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1743 % The format of the GetOneVirtualPixel() method is:
1745 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1746 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1748 % A description of each parameter follows:
1750 % o image: the image.
1752 % o x,y: These values define the location of the pixel to return.
1754 % o pixel: return a pixel at the specified (x,y) location.
1756 % o exception: return any errors or warnings in this structure.
1759 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1760 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1763 *restrict cache_info;
1766 id = GetOpenMPThreadId();
1774 assert(image != (const Image *) NULL);
1775 assert(image->signature == MagickSignature);
1776 assert(image->cache != (Cache) NULL);
1777 cache_info=(CacheInfo *) image->cache;
1778 assert(cache_info->signature == MagickSignature);
1779 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1780 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1781 (GetOneVirtualPixelFromHandler) NULL)
1782 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1783 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1784 assert(id < (int) cache_info->number_threads);
1785 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1786 1UL,1UL,cache_info->nexus_info[id],exception);
1787 if (p == (const Quantum *) NULL)
1789 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1790 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1791 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1792 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1793 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1794 return(MagickFalse);
1796 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1798 PixelChannel channel=GetPixelChannelChannel(image,i);
1799 pixel[channel]=p[i];
1805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1809 + 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 %
1813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1816 % specified (x,y) location. The image background color is returned if an
1819 % The format of the GetOneVirtualPixelFromCache() method is:
1821 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1822 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1823 % Quantum *pixel,ExceptionInfo *exception)
1825 % A description of each parameter follows:
1827 % o image: the image.
1829 % o virtual_pixel_method: the virtual pixel method.
1831 % o x,y: These values define the location of the pixel to return.
1833 % o pixel: return a pixel at the specified (x,y) location.
1835 % o exception: return any errors or warnings in this structure.
1838 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1839 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1840 Quantum *pixel,ExceptionInfo *exception)
1843 *restrict cache_info;
1846 id = GetOpenMPThreadId();
1854 assert(image != (const Image *) NULL);
1855 assert(image->signature == MagickSignature);
1856 assert(image->cache != (Cache) NULL);
1857 cache_info=(CacheInfo *) image->cache;
1858 assert(cache_info->signature == MagickSignature);
1859 assert(id < (int) cache_info->number_threads);
1860 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1861 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1862 cache_info->nexus_info[id],exception);
1863 if (p == (const Quantum *) NULL)
1865 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1866 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1867 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1868 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1869 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1870 return(MagickFalse);
1872 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1874 PixelChannel channel=GetPixelChannelChannel(image,i);
1875 pixel[channel]=p[i];
1881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1885 % G e t O n e V i r t u a l P i x e l I n f o %
1889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1891 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1892 % location. The image background color is returned if an error occurs. If
1893 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1895 % The format of the GetOneVirtualPixelInfo() method is:
1897 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1898 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1899 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1901 % A description of each parameter follows:
1903 % o image: the image.
1905 % o virtual_pixel_method: the virtual pixel method.
1907 % o x,y: these values define the location of the pixel to return.
1909 % o pixel: return a pixel at the specified (x,y) location.
1911 % o exception: return any errors or warnings in this structure.
1914 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1915 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1916 PixelInfo *pixel,ExceptionInfo *exception)
1919 *restrict cache_info;
1922 id = GetOpenMPThreadId();
1924 register const Quantum
1927 assert(image != (const Image *) NULL);
1928 assert(image->signature == MagickSignature);
1929 assert(image->cache != (Cache) NULL);
1930 cache_info=(CacheInfo *) image->cache;
1931 assert(cache_info->signature == MagickSignature);
1932 assert(id < (int) cache_info->number_threads);
1933 GetPixelInfo(image,pixel);
1934 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1935 cache_info->nexus_info[id],exception);
1936 if (p == (const Quantum *) NULL)
1937 return(MagickFalse);
1938 GetPixelInfoPixel(image,p,pixel);
1943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1947 + G e t P i x e l C a c h e C o l o r s p a c e %
1951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1953 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1955 % The format of the GetPixelCacheColorspace() method is:
1957 % Colorspace GetPixelCacheColorspace(Cache cache)
1959 % A description of each parameter follows:
1961 % o cache: the pixel cache.
1964 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1967 *restrict cache_info;
1969 assert(cache != (Cache) NULL);
1970 cache_info=(CacheInfo *) cache;
1971 assert(cache_info->signature == MagickSignature);
1972 if (cache_info->debug != MagickFalse)
1973 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1974 cache_info->filename);
1975 return(cache_info->colorspace);
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983 + G e t P i x e l C a c h e M e t h o d s %
1987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989 % GetPixelCacheMethods() initializes the CacheMethods structure.
1991 % The format of the GetPixelCacheMethods() method is:
1993 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1995 % A description of each parameter follows:
1997 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2000 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2002 assert(cache_methods != (CacheMethods *) NULL);
2003 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2004 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2005 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2006 cache_methods->get_virtual_metacontent_from_handler=
2007 GetVirtualMetacontentFromCache;
2008 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2009 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2010 cache_methods->get_authentic_metacontent_from_handler=
2011 GetAuthenticMetacontentFromCache;
2012 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2013 cache_methods->get_one_authentic_pixel_from_handler=
2014 GetOneAuthenticPixelFromCache;
2015 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2016 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2017 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2025 + G e t P i x e l C a c h e N e x u s E x t e n t %
2029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2031 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2032 % corresponding with the last call to SetPixelCacheNexusPixels() or
2033 % GetPixelCacheNexusPixels().
2035 % The format of the GetPixelCacheNexusExtent() method is:
2037 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2038 % NexusInfo *nexus_info)
2040 % A description of each parameter follows:
2042 % o nexus_info: the nexus info.
2045 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2046 NexusInfo *restrict nexus_info)
2049 *restrict cache_info;
2054 assert(cache != NULL);
2055 cache_info=(CacheInfo *) cache;
2056 assert(cache_info->signature == MagickSignature);
2057 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2059 return((MagickSizeType) cache_info->columns*cache_info->rows);
2064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2068 + G e t P i x e l C a c h e P i x e l s %
2072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2074 % GetPixelCachePixels() returns the pixels associated with the specified image.
2076 % The format of the GetPixelCachePixels() method is:
2078 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2079 % ExceptionInfo *exception)
2081 % A description of each parameter follows:
2083 % o image: the image.
2085 % o length: the pixel cache length.
2087 % o exception: return any errors or warnings in this structure.
2090 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2091 ExceptionInfo *exception)
2094 *restrict cache_info;
2096 assert(image != (const Image *) NULL);
2097 assert(image->signature == MagickSignature);
2098 assert(image->cache != (Cache) NULL);
2099 assert(length != (MagickSizeType *) NULL);
2100 assert(exception != (ExceptionInfo *) NULL);
2101 assert(exception->signature == MagickSignature);
2102 cache_info=(CacheInfo *) image->cache;
2103 assert(cache_info->signature == MagickSignature);
2105 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2106 return((void *) NULL);
2107 *length=cache_info->length;
2108 return((void *) cache_info->pixels);
2112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2116 + 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 %
2120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2122 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2124 % The format of the GetPixelCacheStorageClass() method is:
2126 % ClassType GetPixelCacheStorageClass(Cache cache)
2128 % A description of each parameter follows:
2130 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2132 % o cache: the pixel cache.
2135 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2138 *restrict cache_info;
2140 assert(cache != (Cache) NULL);
2141 cache_info=(CacheInfo *) cache;
2142 assert(cache_info->signature == MagickSignature);
2143 if (cache_info->debug != MagickFalse)
2144 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2145 cache_info->filename);
2146 return(cache_info->storage_class);
2150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2154 + G e t P i x e l C a c h e T i l e S i z e %
2158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160 % GetPixelCacheTileSize() returns the pixel cache tile size.
2162 % The format of the GetPixelCacheTileSize() method is:
2164 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2167 % A description of each parameter follows:
2169 % o image: the image.
2171 % o width: the optimize cache tile width in pixels.
2173 % o height: the optimize cache tile height in pixels.
2176 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2180 *restrict cache_info;
2182 assert(image != (Image *) NULL);
2183 assert(image->signature == MagickSignature);
2184 if (image->debug != MagickFalse)
2185 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2186 cache_info=(CacheInfo *) image->cache;
2187 assert(cache_info->signature == MagickSignature);
2188 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2189 if (GetImagePixelCacheType(image) == DiskCache)
2190 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2199 + 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 %
2203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2206 % pixel cache. A virtual pixel is any pixel access that is outside the
2207 % boundaries of the image cache.
2209 % The format of the GetPixelCacheVirtualMethod() method is:
2211 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2213 % A description of each parameter follows:
2215 % o image: the image.
2218 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2221 *restrict cache_info;
2223 assert(image != (Image *) NULL);
2224 assert(image->signature == MagickSignature);
2225 assert(image->cache != (Cache) NULL);
2226 cache_info=(CacheInfo *) image->cache;
2227 assert(cache_info->signature == MagickSignature);
2228 return(cache_info->virtual_pixel_method);
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2236 + 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 %
2240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2243 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2245 % The format of the GetVirtualMetacontentFromCache() method is:
2247 % void *GetVirtualMetacontentFromCache(const Image *image)
2249 % A description of each parameter follows:
2251 % o image: the image.
2254 static const void *GetVirtualMetacontentFromCache(const Image *image)
2257 *restrict cache_info;
2260 id = GetOpenMPThreadId();
2263 *restrict metacontent;
2265 assert(image != (const Image *) NULL);
2266 assert(image->signature == MagickSignature);
2267 assert(image->cache != (Cache) NULL);
2268 cache_info=(CacheInfo *) image->cache;
2269 assert(cache_info->signature == MagickSignature);
2270 assert(id < (int) cache_info->number_threads);
2271 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2272 cache_info->nexus_info[id]);
2273 return(metacontent);
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281 + 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 %
2285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2287 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2290 % The format of the GetVirtualMetacontentFromNexus() method is:
2292 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2293 % NexusInfo *nexus_info)
2295 % A description of each parameter follows:
2297 % o cache: the pixel cache.
2299 % o nexus_info: the cache nexus to return the meta-content.
2302 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2303 NexusInfo *restrict nexus_info)
2306 *restrict cache_info;
2308 assert(cache != (Cache) NULL);
2309 cache_info=(CacheInfo *) cache;
2310 assert(cache_info->signature == MagickSignature);
2311 if (cache_info->storage_class == UndefinedClass)
2312 return((void *) NULL);
2313 return(nexus_info->metacontent);
2317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321 % G e t V i r t u a l M e t a c o n t e n t %
2325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2328 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2329 % returned if the meta-content are not available.
2331 % The format of the GetVirtualMetacontent() method is:
2333 % const void *GetVirtualMetacontent(const Image *image)
2335 % A description of each parameter follows:
2337 % o image: the image.
2340 MagickExport const void *GetVirtualMetacontent(const Image *image)
2343 *restrict cache_info;
2346 id = GetOpenMPThreadId();
2349 *restrict metacontent;
2351 assert(image != (const Image *) NULL);
2352 assert(image->signature == MagickSignature);
2353 assert(image->cache != (Cache) NULL);
2354 cache_info=(CacheInfo *) image->cache;
2355 assert(cache_info->signature == MagickSignature);
2356 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2357 if (metacontent != (void *) NULL)
2358 return(metacontent);
2359 assert(id < (int) cache_info->number_threads);
2360 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2361 cache_info->nexus_info[id]);
2362 return(metacontent);
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2370 + G e t V i r t u a l P i x e l s F r o m N e x u s %
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2377 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2378 % is returned if the pixels are transferred, otherwise a NULL is returned.
2380 % The format of the GetVirtualPixelsFromNexus() method is:
2382 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2383 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2384 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2385 % ExceptionInfo *exception)
2387 % A description of each parameter follows:
2389 % o image: the image.
2391 % o virtual_pixel_method: the virtual pixel method.
2393 % o x,y,columns,rows: These values define the perimeter of a region of
2396 % o nexus_info: the cache nexus to acquire.
2398 % o exception: return any errors or warnings in this structure.
2405 0, 48, 12, 60, 3, 51, 15, 63,
2406 32, 16, 44, 28, 35, 19, 47, 31,
2407 8, 56, 4, 52, 11, 59, 7, 55,
2408 40, 24, 36, 20, 43, 27, 39, 23,
2409 2, 50, 14, 62, 1, 49, 13, 61,
2410 34, 18, 46, 30, 33, 17, 45, 29,
2411 10, 58, 6, 54, 9, 57, 5, 53,
2412 42, 26, 38, 22, 41, 25, 37, 21
2415 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2420 index=x+DitherMatrix[x & 0x07]-32L;
2423 if (index >= (ssize_t) columns)
2424 return((ssize_t) columns-1L);
2428 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2433 index=y+DitherMatrix[y & 0x07]-32L;
2436 if (index >= (ssize_t) rows)
2437 return((ssize_t) rows-1L);
2441 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2445 if (x >= (ssize_t) columns)
2446 return((ssize_t) (columns-1));
2450 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2454 if (y >= (ssize_t) rows)
2455 return((ssize_t) (rows-1));
2459 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2461 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2464 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2466 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2469 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2470 const size_t extent)
2476 Compute the remainder of dividing offset by extent. It returns not only
2477 the quotient (tile the offset falls in) but also the positive remainer
2478 within that tile such that 0 <= remainder < extent. This method is
2479 essentially a ldiv() using a floored modulo division rather than the
2480 normal default truncated modulo division.
2482 modulo.quotient=offset/(ssize_t) extent;
2485 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2489 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2490 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2491 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2492 ExceptionInfo *exception)
2495 *restrict cache_info;
2505 **restrict virtual_nexus;
2509 virtual_pixel[MaxPixelChannels];
2514 register const Quantum
2527 register unsigned char
2534 *restrict virtual_metacontent;
2539 assert(image != (const Image *) NULL);
2540 assert(image->signature == MagickSignature);
2541 assert(image->cache != (Cache) NULL);
2542 cache_info=(CacheInfo *) image->cache;
2543 assert(cache_info->signature == MagickSignature);
2544 if (cache_info->type == UndefinedCache)
2545 return((const Quantum *) NULL);
2548 region.width=columns;
2550 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2552 if (pixels == (Quantum *) NULL)
2553 return((const Quantum *) NULL);
2555 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2556 nexus_info->region.x;
2557 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2558 nexus_info->region.width-1L;
2559 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2560 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2561 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2562 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2568 Pixel request is inside cache extents.
2570 if (nexus_info->authentic_pixel_cache != MagickFalse)
2572 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2573 if (status == MagickFalse)
2574 return((const Quantum *) NULL);
2575 if (cache_info->metacontent_extent != 0)
2577 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2578 if (status == MagickFalse)
2579 return((const Quantum *) NULL);
2584 Pixel request is outside cache extents.
2586 s=(unsigned char *) nexus_info->metacontent;
2587 virtual_nexus=AcquirePixelCacheNexus(1);
2588 if (virtual_nexus == (NexusInfo **) NULL)
2590 if (virtual_nexus != (NexusInfo **) NULL)
2591 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2592 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2593 "UnableToGetCacheNexus","`%s'",image->filename);
2594 return((const Quantum *) NULL);
2596 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2597 sizeof(*virtual_pixel));
2598 virtual_metacontent=(void *) NULL;
2599 switch (virtual_pixel_method)
2601 case BackgroundVirtualPixelMethod:
2602 case BlackVirtualPixelMethod:
2603 case GrayVirtualPixelMethod:
2604 case TransparentVirtualPixelMethod:
2605 case MaskVirtualPixelMethod:
2606 case WhiteVirtualPixelMethod:
2607 case EdgeVirtualPixelMethod:
2608 case CheckerTileVirtualPixelMethod:
2609 case HorizontalTileVirtualPixelMethod:
2610 case VerticalTileVirtualPixelMethod:
2612 if (cache_info->metacontent_extent != 0)
2615 Acquire a metacontent buffer.
2617 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2618 cache_info->metacontent_extent);
2619 if (virtual_metacontent == (void *) NULL)
2621 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2622 (void) ThrowMagickException(exception,GetMagickModule(),
2623 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2624 return((const Quantum *) NULL);
2626 (void) ResetMagickMemory(virtual_metacontent,0,
2627 cache_info->metacontent_extent);
2629 switch (virtual_pixel_method)
2631 case BlackVirtualPixelMethod:
2633 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2634 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2635 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2638 case GrayVirtualPixelMethod:
2640 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2641 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2643 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2646 case TransparentVirtualPixelMethod:
2648 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2649 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2650 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2653 case MaskVirtualPixelMethod:
2654 case WhiteVirtualPixelMethod:
2656 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2657 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2658 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2663 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2665 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2667 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2669 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2671 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2681 for (v=0; v < (ssize_t) rows; v++)
2687 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2688 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2689 y_offset=EdgeY(y_offset,cache_info->rows);
2690 for (u=0; u < (ssize_t) columns; u+=length)
2696 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2697 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2698 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2706 Transfer a single pixel.
2708 length=(MagickSizeType) 1;
2709 switch (virtual_pixel_method)
2711 case EdgeVirtualPixelMethod:
2714 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2715 EdgeX(x_offset,cache_info->columns),
2716 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2718 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2721 case RandomVirtualPixelMethod:
2723 if (cache_info->random_info == (RandomInfo *) NULL)
2724 cache_info->random_info=AcquireRandomInfo();
2725 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2726 RandomX(cache_info->random_info,cache_info->columns),
2727 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2728 *virtual_nexus,exception);
2729 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2732 case DitherVirtualPixelMethod:
2734 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2735 DitherX(x_offset,cache_info->columns),
2736 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2738 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2741 case TileVirtualPixelMethod:
2743 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2744 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2745 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2746 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2748 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2751 case MirrorVirtualPixelMethod:
2753 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2754 if ((x_modulo.quotient & 0x01) == 1L)
2755 x_modulo.remainder=(ssize_t) cache_info->columns-
2756 x_modulo.remainder-1L;
2757 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2758 if ((y_modulo.quotient & 0x01) == 1L)
2759 y_modulo.remainder=(ssize_t) cache_info->rows-
2760 y_modulo.remainder-1L;
2761 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2762 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2764 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2767 case HorizontalTileEdgeVirtualPixelMethod:
2769 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2770 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2771 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2772 *virtual_nexus,exception);
2773 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2776 case VerticalTileEdgeVirtualPixelMethod:
2778 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2779 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2780 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2781 *virtual_nexus,exception);
2782 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2785 case BackgroundVirtualPixelMethod:
2786 case BlackVirtualPixelMethod:
2787 case GrayVirtualPixelMethod:
2788 case TransparentVirtualPixelMethod:
2789 case MaskVirtualPixelMethod:
2790 case WhiteVirtualPixelMethod:
2793 r=virtual_metacontent;
2796 case CheckerTileVirtualPixelMethod:
2798 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2799 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2800 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2803 r=virtual_metacontent;
2806 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2807 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2809 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2812 case HorizontalTileVirtualPixelMethod:
2814 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2817 r=virtual_metacontent;
2820 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2821 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2822 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2823 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2825 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2828 case VerticalTileVirtualPixelMethod:
2830 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2833 r=virtual_metacontent;
2836 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2837 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2838 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2839 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2841 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2845 if (p == (const Quantum *) NULL)
2847 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2849 q+=cache_info->number_channels;
2850 if ((s != (void *) NULL) && (r != (const void *) NULL))
2852 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2853 s+=cache_info->metacontent_extent;
2858 Transfer a run of pixels.
2860 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2861 (size_t) length,1UL,*virtual_nexus,exception);
2862 if (p == (const Quantum *) NULL)
2864 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2865 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2866 q+=length*cache_info->number_channels;
2867 if ((r != (void *) NULL) && (s != (const void *) NULL))
2869 (void) memcpy(s,r,(size_t) length);
2870 s+=length*cache_info->metacontent_extent;
2877 if (virtual_metacontent != (void *) NULL)
2878 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2879 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2888 + G e t V i r t u a l P i x e l C a c h e %
2892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2894 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2895 % cache as defined by the geometry parameters. A pointer to the pixels
2896 % is returned if the pixels are transferred, otherwise a NULL is returned.
2898 % The format of the GetVirtualPixelCache() method is:
2900 % const Quantum *GetVirtualPixelCache(const Image *image,
2901 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2902 % const ssize_t y,const size_t columns,const size_t rows,
2903 % ExceptionInfo *exception)
2905 % A description of each parameter follows:
2907 % o image: the image.
2909 % o virtual_pixel_method: the virtual pixel method.
2911 % o x,y,columns,rows: These values define the perimeter of a region of
2914 % o exception: return any errors or warnings in this structure.
2917 static const Quantum *GetVirtualPixelCache(const Image *image,
2918 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2919 const size_t columns,const size_t rows,ExceptionInfo *exception)
2922 *restrict cache_info;
2925 id = GetOpenMPThreadId();
2930 assert(image != (const Image *) NULL);
2931 assert(image->signature == MagickSignature);
2932 assert(image->cache != (Cache) NULL);
2933 cache_info=(CacheInfo *) image->cache;
2934 assert(cache_info->signature == MagickSignature);
2935 assert(id < (int) cache_info->number_threads);
2936 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2937 cache_info->nexus_info[id],exception);
2942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2946 % G e t V i r t u a l P i x e l Q u e u e %
2950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2952 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2953 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2955 % The format of the GetVirtualPixelQueue() method is:
2957 % const Quantum *GetVirtualPixelQueue(const Image image)
2959 % A description of each parameter follows:
2961 % o image: the image.
2964 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2967 *restrict cache_info;
2970 id = GetOpenMPThreadId();
2972 assert(image != (const Image *) NULL);
2973 assert(image->signature == MagickSignature);
2974 assert(image->cache != (Cache) NULL);
2975 cache_info=(CacheInfo *) image->cache;
2976 assert(cache_info->signature == MagickSignature);
2977 if (cache_info->methods.get_virtual_pixels_handler !=
2978 (GetVirtualPixelsHandler) NULL)
2979 return(cache_info->methods.get_virtual_pixels_handler(image));
2980 assert(id < (int) cache_info->number_threads);
2981 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2989 % G e t V i r t u a l P i x e l s %
2993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2995 % GetVirtualPixels() returns an immutable pixel region. If the
2996 % region is successfully accessed, a pointer to it is returned, otherwise
2997 % NULL is returned. The returned pointer may point to a temporary working
2998 % copy of the pixels or it may point to the original pixels in memory.
2999 % Performance is maximized if the selected region is part of one row, or one
3000 % or more full rows, since there is opportunity to access the pixels in-place
3001 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3002 % returned pointer must *never* be deallocated by the user.
3004 % Pixels accessed via the returned pointer represent a simple array of type
3005 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3006 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3007 % access the meta-content (of type void) corresponding to the the
3010 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3012 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3013 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3014 % GetCacheViewAuthenticPixels() instead.
3016 % The format of the GetVirtualPixels() method is:
3018 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3019 % const ssize_t y,const size_t columns,const size_t rows,
3020 % ExceptionInfo *exception)
3022 % A description of each parameter follows:
3024 % o image: the image.
3026 % o x,y,columns,rows: These values define the perimeter of a region of
3029 % o exception: return any errors or warnings in this structure.
3032 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3033 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3034 ExceptionInfo *exception)
3037 *restrict cache_info;
3040 id = GetOpenMPThreadId();
3045 assert(image != (const Image *) NULL);
3046 assert(image->signature == MagickSignature);
3047 assert(image->cache != (Cache) NULL);
3048 cache_info=(CacheInfo *) image->cache;
3049 assert(cache_info->signature == MagickSignature);
3050 if (cache_info->methods.get_virtual_pixel_handler !=
3051 (GetVirtualPixelHandler) NULL)
3052 return(cache_info->methods.get_virtual_pixel_handler(image,
3053 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3054 assert(id < (int) cache_info->number_threads);
3055 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3056 columns,rows,cache_info->nexus_info[id],exception);
3061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3065 + 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 %
3069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3071 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3072 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3074 % The format of the GetVirtualPixelsCache() method is:
3076 % Quantum *GetVirtualPixelsCache(const Image *image)
3078 % A description of each parameter follows:
3080 % o image: the image.
3083 static const Quantum *GetVirtualPixelsCache(const Image *image)
3086 *restrict cache_info;
3089 id = GetOpenMPThreadId();
3091 assert(image != (const Image *) NULL);
3092 assert(image->signature == MagickSignature);
3093 assert(image->cache != (Cache) NULL);
3094 cache_info=(CacheInfo *) image->cache;
3095 assert(cache_info->signature == MagickSignature);
3096 assert(id < (int) cache_info->number_threads);
3097 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3105 + G e t V i r t u a l P i x e l s N e x u s %
3109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3111 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3114 % The format of the GetVirtualPixelsNexus() method is:
3116 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3117 % NexusInfo *nexus_info)
3119 % A description of each parameter follows:
3121 % o cache: the pixel cache.
3123 % o nexus_info: the cache nexus to return the colormap pixels.
3126 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3127 NexusInfo *restrict nexus_info)
3130 *restrict cache_info;
3132 assert(cache != (Cache) NULL);
3133 cache_info=(CacheInfo *) cache;
3134 assert(cache_info->signature == MagickSignature);
3135 if (cache_info->storage_class == UndefinedClass)
3136 return((Quantum *) NULL);
3137 return((const Quantum *) nexus_info->pixels);
3141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3145 + O p e n P i x e l C a c h e %
3149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3151 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3152 % dimensions, allocating space for the image pixels and optionally the
3153 % metacontent, and memory mapping the cache if it is disk based. The cache
3154 % nexus array is initialized as well.
3156 % The format of the OpenPixelCache() method is:
3158 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3159 % ExceptionInfo *exception)
3161 % A description of each parameter follows:
3163 % o image: the image.
3165 % o mode: ReadMode, WriteMode, or IOMode.
3167 % o exception: return any errors or warnings in this structure.
3171 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3173 cache_info->mapped=MagickFalse;
3174 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3175 (size_t) cache_info->length));
3176 if (cache_info->pixels == (Quantum *) NULL)
3178 cache_info->mapped=MagickTrue;
3179 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3180 cache_info->length);
3184 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3191 Open pixel cache on disk.
3193 if (cache_info->file != -1)
3194 return(MagickTrue); /* cache already open */
3195 if (*cache_info->cache_filename == '\0')
3196 file=AcquireUniqueFileResource(cache_info->cache_filename);
3202 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3207 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3208 O_BINARY | O_EXCL,S_MODE);
3210 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3216 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3219 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3224 return(MagickFalse);
3225 (void) AcquireMagickResource(FileResource,1);
3226 cache_info->file=file;
3227 cache_info->mode=mode;
3231 static inline MagickOffsetType WritePixelCacheRegion(
3232 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3233 const MagickSizeType length,const unsigned char *restrict buffer)
3235 register MagickOffsetType
3241 #if !defined(MAGICKCORE_HAVE_PWRITE)
3242 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3243 return((MagickOffsetType) -1);
3246 for (i=0; i < (MagickOffsetType) length; i+=count)
3248 #if !defined(MAGICKCORE_HAVE_PWRITE)
3249 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3250 (MagickSizeType) SSIZE_MAX));
3252 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3253 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3265 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3268 *restrict cache_info;
3275 cache_info=(CacheInfo *) image->cache;
3276 if (image->debug != MagickFalse)
3279 format[MaxTextExtent],
3280 message[MaxTextExtent];
3282 (void) FormatMagickSize(length,MagickFalse,format);
3283 (void) FormatLocaleString(message,MaxTextExtent,
3284 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3285 cache_info->cache_filename,cache_info->file,format);
3286 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3288 if (length != (MagickSizeType) ((MagickOffsetType) length))
3289 return(MagickFalse);
3290 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3292 return(MagickFalse);
3293 if ((MagickSizeType) offset >= length)
3295 extent=(MagickOffsetType) length-1;
3296 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3297 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3298 if (cache_info->synchronize != MagickFalse)
3303 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3305 return(MagickFalse);
3308 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3311 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3312 ExceptionInfo *exception)
3315 *restrict cache_info,
3319 format[MaxTextExtent],
3320 message[MaxTextExtent];
3336 assert(image != (const Image *) NULL);
3337 assert(image->signature == MagickSignature);
3338 assert(image->cache != (Cache) NULL);
3339 if (image->debug != MagickFalse)
3340 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3341 if ((image->columns == 0) || (image->rows == 0))
3342 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3343 cache_info=(CacheInfo *) image->cache;
3344 assert(cache_info->signature == MagickSignature);
3345 source_info=(*cache_info);
3346 source_info.file=(-1);
3347 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3348 image->filename,(double) GetImageIndexInList(image));
3349 cache_info->storage_class=image->storage_class;
3350 cache_info->colorspace=image->colorspace;
3351 cache_info->alpha_trait=image->alpha_trait;
3352 cache_info->read_mask=image->read_mask;
3353 cache_info->write_mask=image->write_mask;
3354 cache_info->rows=image->rows;
3355 cache_info->columns=image->columns;
3356 InitializePixelChannelMap(image);
3357 cache_info->number_channels=GetPixelChannels(image);
3358 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3359 sizeof(*image->channel_map));
3360 cache_info->metacontent_extent=image->metacontent_extent;
3361 cache_info->mode=mode;
3362 if (image->ping != MagickFalse)
3364 cache_info->type=PingCache;
3365 cache_info->pixels=(Quantum *) NULL;
3366 cache_info->metacontent=(void *) NULL;
3367 cache_info->length=0;
3370 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3371 packet_size=cache_info->number_channels*sizeof(Quantum);
3372 if (image->metacontent_extent != 0)
3373 packet_size+=cache_info->metacontent_extent;
3374 length=number_pixels*packet_size;
3375 columns=(size_t) (length/cache_info->rows/packet_size);
3376 if (cache_info->columns != columns)
3377 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3379 cache_info->length=length;
3380 status=AcquireMagickResource(AreaResource,cache_info->length);
3381 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3382 cache_info->metacontent_extent);
3383 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3385 status=AcquireMagickResource(MemoryResource,cache_info->length);
3386 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3387 (cache_info->type == MemoryCache))
3389 AllocatePixelCachePixels(cache_info);
3390 if (cache_info->pixels == (Quantum *) NULL)
3391 cache_info->pixels=source_info.pixels;
3395 Create memory pixel cache.
3398 cache_info->type=MemoryCache;
3399 cache_info->metacontent=(void *) NULL;
3400 if (cache_info->metacontent_extent != 0)
3401 cache_info->metacontent=(void *) (cache_info->pixels+
3402 number_pixels*cache_info->number_channels);
3403 if ((source_info.storage_class != UndefinedClass) &&
3406 status=ClonePixelCacheRepository(cache_info,&source_info,
3408 RelinquishPixelCachePixels(&source_info);
3410 if (image->debug != MagickFalse)
3412 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3413 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3415 (void) FormatLocaleString(message,MaxTextExtent,
3416 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3417 cache_info->filename,cache_info->mapped != MagickFalse ?
3418 "Anonymous" : "Heap",type,(double) cache_info->columns,
3419 (double) cache_info->rows,(double)
3420 cache_info->number_channels,format);
3421 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3427 RelinquishMagickResource(MemoryResource,cache_info->length);
3430 Create pixel cache on disk.
3432 status=AcquireMagickResource(DiskResource,cache_info->length);
3433 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3438 if (cache_info->type == DistributedCache)
3439 RelinquishMagickResource(DiskResource,cache_info->length);
3440 server_info=AcquireDistributeCacheInfo(exception);
3441 if (server_info != (DistributeCacheInfo *) NULL)
3443 status=OpenDistributePixelCache(server_info,image);
3444 if (status == MagickFalse)
3446 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3447 GetDistributeCacheHostname(server_info));
3448 server_info=DestroyDistributeCacheInfo(server_info);
3453 Create a distributed pixel cache.
3455 cache_info->type=DistributedCache;
3456 cache_info->server_info=server_info;
3457 (void) FormatLocaleString(cache_info->cache_filename,
3458 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3459 (DistributeCacheInfo *) cache_info->server_info),
3460 GetDistributeCachePort((DistributeCacheInfo *)
3461 cache_info->server_info));
3462 if ((source_info.storage_class != UndefinedClass) &&
3465 status=ClonePixelCacheRepository(cache_info,&source_info,
3467 RelinquishPixelCachePixels(&source_info);
3469 if (image->debug != MagickFalse)
3471 (void) FormatMagickSize(cache_info->length,MagickFalse,
3473 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3475 (void) FormatLocaleString(message,MaxTextExtent,
3476 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3477 cache_info->filename,cache_info->cache_filename,
3478 GetDistributeCacheFile((DistributeCacheInfo *)
3479 cache_info->server_info),type,(double) cache_info->columns,
3480 (double) cache_info->rows,(double)
3481 cache_info->number_channels,format);
3482 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3488 RelinquishMagickResource(DiskResource,cache_info->length);
3489 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3490 "CacheResourcesExhausted","`%s'",image->filename);
3491 return(MagickFalse);
3493 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3495 (void) ClosePixelCacheOnDisk(cache_info);
3496 *cache_info->cache_filename='\0';
3498 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3500 RelinquishMagickResource(DiskResource,cache_info->length);
3501 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3503 return(MagickFalse);
3505 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3506 cache_info->length);
3507 if (status == MagickFalse)
3509 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3511 return(MagickFalse);
3513 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3514 cache_info->metacontent_extent);
3515 if (length != (MagickSizeType) ((size_t) length))
3516 cache_info->type=DiskCache;
3519 status=AcquireMagickResource(MapResource,cache_info->length);
3520 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3521 (cache_info->type != MemoryCache))
3522 cache_info->type=DiskCache;
3525 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3526 cache_info->offset,(size_t) cache_info->length);
3527 if (cache_info->pixels == (Quantum *) NULL)
3529 cache_info->type=DiskCache;
3530 cache_info->pixels=source_info.pixels;
3535 Create file-backed memory-mapped pixel cache.
3538 (void) ClosePixelCacheOnDisk(cache_info);
3539 cache_info->type=MapCache;
3540 cache_info->mapped=MagickTrue;
3541 cache_info->metacontent=(void *) NULL;
3542 if (cache_info->metacontent_extent != 0)
3543 cache_info->metacontent=(void *) (cache_info->pixels+
3544 number_pixels*cache_info->number_channels);
3545 if ((source_info.storage_class != UndefinedClass) &&
3548 status=ClonePixelCacheRepository(cache_info,&source_info,
3550 RelinquishPixelCachePixels(&source_info);
3552 if (image->debug != MagickFalse)
3554 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3555 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3557 (void) FormatLocaleString(message,MaxTextExtent,
3558 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3559 cache_info->filename,cache_info->cache_filename,
3560 cache_info->file,type,(double) cache_info->columns,(double)
3561 cache_info->rows,(double) cache_info->number_channels,
3563 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3569 RelinquishMagickResource(MapResource,cache_info->length);
3572 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3574 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3575 RelinquishPixelCachePixels(&source_info);
3577 if (image->debug != MagickFalse)
3579 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3580 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3582 (void) FormatLocaleString(message,MaxTextExtent,
3583 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3584 cache_info->cache_filename,cache_info->file,type,(double)
3585 cache_info->columns,(double) cache_info->rows,(double)
3586 cache_info->number_channels,format);
3587 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597 + P e r s i s t P i x e l C a c h e %
3601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3603 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3604 % persistent pixel cache is one that resides on disk and is not destroyed
3605 % when the program exits.
3607 % The format of the PersistPixelCache() method is:
3609 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3610 % const MagickBooleanType attach,MagickOffsetType *offset,
3611 % ExceptionInfo *exception)
3613 % A description of each parameter follows:
3615 % o image: the image.
3617 % o filename: the persistent pixel cache filename.
3619 % o attach: A value other than zero initializes the persistent pixel cache.
3621 % o initialize: A value other than zero initializes the persistent pixel
3624 % o offset: the offset in the persistent cache to store pixels.
3626 % o exception: return any errors or warnings in this structure.
3629 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3630 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3631 ExceptionInfo *exception)
3634 *restrict cache_info,
3635 *restrict clone_info;
3646 assert(image != (Image *) NULL);
3647 assert(image->signature == MagickSignature);
3648 if (image->debug != MagickFalse)
3649 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3650 assert(image->cache != (void *) NULL);
3651 assert(filename != (const char *) NULL);
3652 assert(offset != (MagickOffsetType *) NULL);
3653 page_size=GetMagickPageSize();
3654 cache_info=(CacheInfo *) image->cache;
3655 assert(cache_info->signature == MagickSignature);
3656 if (attach != MagickFalse)
3659 Attach existing persistent pixel cache.
3661 if (image->debug != MagickFalse)
3662 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3663 "attach persistent cache");
3664 (void) CopyMagickString(cache_info->cache_filename,filename,
3666 cache_info->type=DiskCache;
3667 cache_info->offset=(*offset);
3668 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3669 return(MagickFalse);
3670 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3673 if ((cache_info->mode != ReadMode) &&
3674 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3675 (cache_info->reference_count == 1))
3677 LockSemaphoreInfo(cache_info->semaphore);
3678 if ((cache_info->mode != ReadMode) &&
3679 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3680 (cache_info->reference_count == 1))
3686 Usurp existing persistent pixel cache.
3688 status=rename_utf8(cache_info->cache_filename,filename);
3691 (void) CopyMagickString(cache_info->cache_filename,filename,
3693 *offset+=cache_info->length+page_size-(cache_info->length %
3695 UnlockSemaphoreInfo(cache_info->semaphore);
3696 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3697 if (image->debug != MagickFalse)
3698 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3699 "Usurp resident persistent cache");
3703 UnlockSemaphoreInfo(cache_info->semaphore);
3706 Clone persistent pixel cache.
3708 clone_image=(*image);
3709 clone_info=(CacheInfo *) clone_image.cache;
3710 image->cache=ClonePixelCache(cache_info);
3711 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3712 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3713 cache_info->type=DiskCache;
3714 cache_info->offset=(*offset);
3715 cache_info=(CacheInfo *) image->cache;
3716 status=OpenPixelCache(image,IOMode,exception);
3717 if (status != MagickFalse)
3718 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3719 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3720 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3729 + 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 %
3733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3735 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3736 % defined by the region rectangle and returns a pointer to the region. This
3737 % region is subsequently transferred from the pixel cache with
3738 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3739 % pixels are transferred, otherwise a NULL is returned.
3741 % The format of the QueueAuthenticPixelCacheNexus() method is:
3743 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3744 % const ssize_t y,const size_t columns,const size_t rows,
3745 % const MagickBooleanType clone,NexusInfo *nexus_info,
3746 % ExceptionInfo *exception)
3748 % A description of each parameter follows:
3750 % o image: the image.
3752 % o x,y,columns,rows: These values define the perimeter of a region of
3755 % o nexus_info: the cache nexus to set.
3757 % o clone: clone the pixel cache.
3759 % o exception: return any errors or warnings in this structure.
3762 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3763 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3764 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3767 *restrict cache_info;
3782 Validate pixel cache geometry.
3784 assert(image != (const Image *) NULL);
3785 assert(image->signature == MagickSignature);
3786 assert(image->cache != (Cache) NULL);
3787 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3788 if (cache_info == (Cache) NULL)
3789 return((Quantum *) NULL);
3790 assert(cache_info->signature == MagickSignature);
3791 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3792 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3793 (y >= (ssize_t) cache_info->rows))
3795 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3796 "PixelsAreNotAuthentic","`%s'",image->filename);
3797 return((Quantum *) NULL);
3799 offset=(MagickOffsetType) y*cache_info->columns+x;
3801 return((Quantum *) NULL);
3802 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3803 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3804 if ((MagickSizeType) offset >= number_pixels)
3805 return((Quantum *) NULL);
3811 region.width=columns;
3813 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3823 + 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 %
3827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3829 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3830 % defined by the region rectangle and returns a pointer to the region. This
3831 % region is subsequently transferred from the pixel cache with
3832 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3833 % pixels are transferred, otherwise a NULL is returned.
3835 % The format of the QueueAuthenticPixelsCache() method is:
3837 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3838 % const ssize_t y,const size_t columns,const size_t rows,
3839 % ExceptionInfo *exception)
3841 % A description of each parameter follows:
3843 % o image: the image.
3845 % o x,y,columns,rows: These values define the perimeter of a region of
3848 % o exception: return any errors or warnings in this structure.
3851 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3852 const ssize_t y,const size_t columns,const size_t rows,
3853 ExceptionInfo *exception)
3856 *restrict cache_info;
3859 id = GetOpenMPThreadId();
3864 assert(image != (const Image *) NULL);
3865 assert(image->signature == MagickSignature);
3866 assert(image->cache != (Cache) NULL);
3867 cache_info=(CacheInfo *) image->cache;
3868 assert(cache_info->signature == MagickSignature);
3869 assert(id < (int) cache_info->number_threads);
3870 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3871 cache_info->nexus_info[id],exception);
3876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3880 % Q u e u e A u t h e n t i c P i x e l s %
3884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3886 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3887 % successfully initialized a pointer to a Quantum array representing the
3888 % region is returned, otherwise NULL is returned. The returned pointer may
3889 % point to a temporary working buffer for the pixels or it may point to the
3890 % final location of the pixels in memory.
3892 % Write-only access means that any existing pixel values corresponding to
3893 % the region are ignored. This is useful if the initial image is being
3894 % created from scratch, or if the existing pixel values are to be
3895 % completely replaced without need to refer to their pre-existing values.
3896 % The application is free to read and write the pixel buffer returned by
3897 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3898 % initialize the pixel array values. Initializing pixel array values is the
3899 % application's responsibility.
3901 % Performance is maximized if the selected region is part of one row, or
3902 % one or more full rows, since then there is opportunity to access the
3903 % pixels in-place (without a copy) if the image is in memory, or in a
3904 % memory-mapped file. The returned pointer must *never* be deallocated
3907 % Pixels accessed via the returned pointer represent a simple array of type
3908 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3909 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3910 % obtain the meta-content (of type void) corresponding to the region.
3911 % Once the Quantum (and/or Quantum) array has been updated, the
3912 % changes must be saved back to the underlying image using
3913 % SyncAuthenticPixels() or they may be lost.
3915 % The format of the QueueAuthenticPixels() method is:
3917 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3918 % const ssize_t y,const size_t columns,const size_t rows,
3919 % ExceptionInfo *exception)
3921 % A description of each parameter follows:
3923 % o image: the image.
3925 % o x,y,columns,rows: These values define the perimeter of a region of
3928 % o exception: return any errors or warnings in this structure.
3931 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3932 const ssize_t y,const size_t columns,const size_t rows,
3933 ExceptionInfo *exception)
3936 *restrict cache_info;
3939 id = GetOpenMPThreadId();
3944 assert(image != (Image *) NULL);
3945 assert(image->signature == MagickSignature);
3946 assert(image->cache != (Cache) NULL);
3947 cache_info=(CacheInfo *) image->cache;
3948 assert(cache_info->signature == MagickSignature);
3949 if (cache_info->methods.queue_authentic_pixels_handler !=
3950 (QueueAuthenticPixelsHandler) NULL)
3952 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3953 columns,rows,exception);
3956 assert(id < (int) cache_info->number_threads);
3957 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3958 cache_info->nexus_info[id],exception);
3963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967 + 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 %
3971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3973 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3976 % The format of the ReadPixelCacheMetacontent() method is:
3978 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
3979 % NexusInfo *nexus_info,ExceptionInfo *exception)
3981 % A description of each parameter follows:
3983 % o cache_info: the pixel cache.
3985 % o nexus_info: the cache nexus to read the metacontent.
3987 % o exception: return any errors or warnings in this structure.
3991 static inline MagickOffsetType ReadPixelCacheRegion(
3992 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3993 const MagickSizeType length,unsigned char *restrict buffer)
3995 register MagickOffsetType
4001 #if !defined(MAGICKCORE_HAVE_PREAD)
4002 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4003 return((MagickOffsetType) -1);
4006 for (i=0; i < (MagickOffsetType) length; i+=count)
4008 #if !defined(MAGICKCORE_HAVE_PREAD)
4009 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4010 (MagickSizeType) SSIZE_MAX));
4012 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4013 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4025 static MagickBooleanType ReadPixelCacheMetacontent(
4026 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4027 ExceptionInfo *exception)
4040 register unsigned char
4046 if (cache_info->metacontent_extent == 0)
4047 return(MagickFalse);
4048 if (nexus_info->authentic_pixel_cache != MagickFalse)
4050 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4051 nexus_info->region.x;
4052 length=(MagickSizeType) nexus_info->region.width*
4053 cache_info->metacontent_extent;
4054 extent=length*nexus_info->region.height;
4055 rows=nexus_info->region.height;
4057 q=(unsigned char *) nexus_info->metacontent;
4058 switch (cache_info->type)
4063 register unsigned char
4067 Read meta-content from memory.
4069 if ((cache_info->columns == nexus_info->region.width) &&
4070 (extent == (MagickSizeType) ((size_t) extent)))
4075 p=(unsigned char *) cache_info->metacontent+offset*
4076 cache_info->metacontent_extent;
4077 for (y=0; y < (ssize_t) rows; y++)
4079 (void) memcpy(q,p,(size_t) length);
4080 p+=cache_info->metacontent_extent*cache_info->columns;
4081 q+=cache_info->metacontent_extent*nexus_info->region.width;
4088 Read meta content from disk.
4090 LockSemaphoreInfo(cache_info->file_semaphore);
4091 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4093 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4094 cache_info->cache_filename);
4095 UnlockSemaphoreInfo(cache_info->file_semaphore);
4096 return(MagickFalse);
4098 if ((cache_info->columns == nexus_info->region.width) &&
4099 (extent <= MagickMaxBufferExtent))
4104 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4105 for (y=0; y < (ssize_t) rows; y++)
4107 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4108 cache_info->number_channels*sizeof(Quantum)+offset*
4109 cache_info->metacontent_extent,length,(unsigned char *) q);
4110 if (count != (MagickOffsetType) length)
4112 offset+=cache_info->columns;
4113 q+=cache_info->metacontent_extent*nexus_info->region.width;
4115 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4116 (void) ClosePixelCacheOnDisk(cache_info);
4117 UnlockSemaphoreInfo(cache_info->file_semaphore);
4120 case DistributedCache:
4126 Read metacontent from distributed cache.
4128 LockSemaphoreInfo(cache_info->file_semaphore);
4129 region=nexus_info->region;
4130 if ((cache_info->columns != nexus_info->region.width) ||
4131 (extent > MagickMaxBufferExtent))
4138 for (y=0; y < (ssize_t) rows; y++)
4140 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4141 cache_info->server_info,®ion,length,(unsigned char *) q);
4142 if (count != (MagickOffsetType) length)
4144 q+=cache_info->metacontent_extent*nexus_info->region.width;
4147 UnlockSemaphoreInfo(cache_info->file_semaphore);
4153 if (y < (ssize_t) rows)
4155 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4156 cache_info->cache_filename);
4157 return(MagickFalse);
4159 if ((cache_info->debug != MagickFalse) &&
4160 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4161 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4162 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4163 nexus_info->region.width,(double) nexus_info->region.height,(double)
4164 nexus_info->region.x,(double) nexus_info->region.y);
4169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4173 + R e a d P i x e l C a c h e P i x e l s %
4177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4179 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4182 % The format of the ReadPixelCachePixels() method is:
4184 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4185 % NexusInfo *nexus_info,ExceptionInfo *exception)
4187 % A description of each parameter follows:
4189 % o cache_info: the pixel cache.
4191 % o nexus_info: the cache nexus to read the pixels.
4193 % o exception: return any errors or warnings in this structure.
4196 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4197 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4216 if (nexus_info->authentic_pixel_cache != MagickFalse)
4218 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4219 nexus_info->region.x;
4220 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4222 extent=length*nexus_info->region.height;
4223 rows=nexus_info->region.height;
4225 q=nexus_info->pixels;
4226 switch (cache_info->type)
4235 Read pixels from memory.
4237 if ((cache_info->columns == nexus_info->region.width) &&
4238 (extent == (MagickSizeType) ((size_t) extent)))
4243 p=cache_info->pixels+offset*cache_info->number_channels;
4244 for (y=0; y < (ssize_t) rows; y++)
4246 (void) memcpy(q,p,(size_t) length);
4247 p+=cache_info->number_channels*cache_info->columns;
4248 q+=cache_info->number_channels*nexus_info->region.width;
4255 Read pixels from disk.
4257 LockSemaphoreInfo(cache_info->file_semaphore);
4258 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4260 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4261 cache_info->cache_filename);
4262 UnlockSemaphoreInfo(cache_info->file_semaphore);
4263 return(MagickFalse);
4265 if ((cache_info->columns == nexus_info->region.width) &&
4266 (extent <= MagickMaxBufferExtent))
4271 for (y=0; y < (ssize_t) rows; y++)
4273 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4274 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4275 if (count != (MagickOffsetType) length)
4277 offset+=cache_info->columns;
4278 q+=cache_info->number_channels*nexus_info->region.width;
4280 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4281 (void) ClosePixelCacheOnDisk(cache_info);
4282 UnlockSemaphoreInfo(cache_info->file_semaphore);
4285 case DistributedCache:
4291 Read pixels from distributed cache.
4293 LockSemaphoreInfo(cache_info->file_semaphore);
4294 region=nexus_info->region;
4295 if ((cache_info->columns != nexus_info->region.width) ||
4296 (extent > MagickMaxBufferExtent))
4303 for (y=0; y < (ssize_t) rows; y++)
4305 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4306 cache_info->server_info,®ion,length,(unsigned char *) q);
4307 if (count != (MagickOffsetType) length)
4309 q+=cache_info->number_channels*nexus_info->region.width;
4312 UnlockSemaphoreInfo(cache_info->file_semaphore);
4318 if (y < (ssize_t) rows)
4320 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4321 cache_info->cache_filename);
4322 return(MagickFalse);
4324 if ((cache_info->debug != MagickFalse) &&
4325 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4326 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4327 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4328 nexus_info->region.width,(double) nexus_info->region.height,(double)
4329 nexus_info->region.x,(double) nexus_info->region.y);
4334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4338 + R e f e r e n c e P i x e l C a c h e %
4342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4344 % ReferencePixelCache() increments the reference count associated with the
4345 % pixel cache returning a pointer to the cache.
4347 % The format of the ReferencePixelCache method is:
4349 % Cache ReferencePixelCache(Cache cache_info)
4351 % A description of each parameter follows:
4353 % o cache_info: the pixel cache.
4356 MagickPrivate Cache ReferencePixelCache(Cache cache)
4359 *restrict cache_info;
4361 assert(cache != (Cache *) NULL);
4362 cache_info=(CacheInfo *) cache;
4363 assert(cache_info->signature == MagickSignature);
4364 LockSemaphoreInfo(cache_info->semaphore);
4365 cache_info->reference_count++;
4366 UnlockSemaphoreInfo(cache_info->semaphore);
4371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375 + S e t P i x e l C a c h e M e t h o d s %
4379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4381 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4383 % The format of the SetPixelCacheMethods() method is:
4385 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4387 % A description of each parameter follows:
4389 % o cache: the pixel cache.
4391 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4394 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4397 *restrict cache_info;
4399 GetOneAuthenticPixelFromHandler
4400 get_one_authentic_pixel_from_handler;
4402 GetOneVirtualPixelFromHandler
4403 get_one_virtual_pixel_from_handler;
4406 Set cache pixel methods.
4408 assert(cache != (Cache) NULL);
4409 assert(cache_methods != (CacheMethods *) NULL);
4410 cache_info=(CacheInfo *) cache;
4411 assert(cache_info->signature == MagickSignature);
4412 if (cache_info->debug != MagickFalse)
4413 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4414 cache_info->filename);
4415 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4416 cache_info->methods.get_virtual_pixel_handler=
4417 cache_methods->get_virtual_pixel_handler;
4418 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4419 cache_info->methods.destroy_pixel_handler=
4420 cache_methods->destroy_pixel_handler;
4421 if (cache_methods->get_virtual_metacontent_from_handler !=
4422 (GetVirtualMetacontentFromHandler) NULL)
4423 cache_info->methods.get_virtual_metacontent_from_handler=
4424 cache_methods->get_virtual_metacontent_from_handler;
4425 if (cache_methods->get_authentic_pixels_handler !=
4426 (GetAuthenticPixelsHandler) NULL)
4427 cache_info->methods.get_authentic_pixels_handler=
4428 cache_methods->get_authentic_pixels_handler;
4429 if (cache_methods->queue_authentic_pixels_handler !=
4430 (QueueAuthenticPixelsHandler) NULL)
4431 cache_info->methods.queue_authentic_pixels_handler=
4432 cache_methods->queue_authentic_pixels_handler;
4433 if (cache_methods->sync_authentic_pixels_handler !=
4434 (SyncAuthenticPixelsHandler) NULL)
4435 cache_info->methods.sync_authentic_pixels_handler=
4436 cache_methods->sync_authentic_pixels_handler;
4437 if (cache_methods->get_authentic_pixels_from_handler !=
4438 (GetAuthenticPixelsFromHandler) NULL)
4439 cache_info->methods.get_authentic_pixels_from_handler=
4440 cache_methods->get_authentic_pixels_from_handler;
4441 if (cache_methods->get_authentic_metacontent_from_handler !=
4442 (GetAuthenticMetacontentFromHandler) NULL)
4443 cache_info->methods.get_authentic_metacontent_from_handler=
4444 cache_methods->get_authentic_metacontent_from_handler;
4445 get_one_virtual_pixel_from_handler=
4446 cache_info->methods.get_one_virtual_pixel_from_handler;
4447 if (get_one_virtual_pixel_from_handler !=
4448 (GetOneVirtualPixelFromHandler) NULL)
4449 cache_info->methods.get_one_virtual_pixel_from_handler=
4450 cache_methods->get_one_virtual_pixel_from_handler;
4451 get_one_authentic_pixel_from_handler=
4452 cache_methods->get_one_authentic_pixel_from_handler;
4453 if (get_one_authentic_pixel_from_handler !=
4454 (GetOneAuthenticPixelFromHandler) NULL)
4455 cache_info->methods.get_one_authentic_pixel_from_handler=
4456 cache_methods->get_one_authentic_pixel_from_handler;
4460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4464 + S e t P i x e l C a c h e N e x u s P i x e l s %
4468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4470 % SetPixelCacheNexusPixels() defines the region of the cache for the
4471 % specified cache nexus.
4473 % The format of the SetPixelCacheNexusPixels() method is:
4475 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4476 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4477 % ExceptionInfo *exception)
4479 % A description of each parameter follows:
4481 % o cache_info: the pixel cache.
4483 % o mode: ReadMode, WriteMode, or IOMode.
4485 % o region: A pointer to the RectangleInfo structure that defines the
4486 % region of this particular cache nexus.
4488 % o nexus_info: the cache nexus to set.
4490 % o exception: return any errors or warnings in this structure.
4494 static inline MagickBooleanType AcquireCacheNexusPixels(
4495 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4496 ExceptionInfo *exception)
4498 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4499 return(MagickFalse);
4500 nexus_info->mapped=MagickFalse;
4501 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4502 (size_t) nexus_info->length));
4503 if (nexus_info->cache == (Quantum *) NULL)
4505 nexus_info->mapped=MagickTrue;
4506 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4507 nexus_info->length);
4509 if (nexus_info->cache == (Quantum *) NULL)
4511 (void) ThrowMagickException(exception,GetMagickModule(),
4512 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4513 cache_info->filename);
4514 return(MagickFalse);
4519 static inline MagickBooleanType IsPixelCacheAuthentic(
4520 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4529 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4531 if (cache_info->type == PingCache)
4533 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4534 nexus_info->region.x;
4535 status=nexus_info->pixels == (cache_info->pixels+offset*
4536 cache_info->number_channels) ? MagickTrue : MagickFalse;
4540 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4543 if (mode == ReadMode)
4545 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4548 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4551 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4552 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4553 ExceptionInfo *exception)
4562 assert(cache_info != (const CacheInfo *) NULL);
4563 assert(cache_info->signature == MagickSignature);
4564 if (cache_info->type == UndefinedCache)
4565 return((Quantum *) NULL);
4566 nexus_info->region=(*region);
4567 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4573 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4574 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4575 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4576 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4577 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4578 ((nexus_info->region.width == cache_info->columns) ||
4579 ((nexus_info->region.width % cache_info->columns) == 0)))))
4585 Pixels are accessed directly from memory.
4587 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4588 nexus_info->region.x;
4589 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4591 nexus_info->metacontent=(void *) NULL;
4592 if (cache_info->metacontent_extent != 0)
4593 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4594 offset*cache_info->metacontent_extent;
4595 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4596 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4598 return(nexus_info->pixels);
4602 Pixels are stored in a staging region until they are synced to the cache.
4604 number_pixels=(MagickSizeType) nexus_info->region.width*
4605 nexus_info->region.height;
4606 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4607 if (cache_info->metacontent_extent != 0)
4608 length+=number_pixels*cache_info->metacontent_extent;
4609 if (nexus_info->cache == (Quantum *) NULL)
4611 nexus_info->length=length;
4612 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4613 if (status == MagickFalse)
4615 nexus_info->length=0;
4616 return((Quantum *) NULL);
4620 if (nexus_info->length < length)
4622 RelinquishCacheNexusPixels(nexus_info);
4623 nexus_info->length=length;
4624 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4625 if (status == MagickFalse)
4627 nexus_info->length=0;
4628 return((Quantum *) NULL);
4631 nexus_info->pixels=nexus_info->cache;
4632 nexus_info->metacontent=(void *) NULL;
4633 if (cache_info->metacontent_extent != 0)
4634 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4635 cache_info->number_channels);
4636 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4637 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4639 return(nexus_info->pixels);
4643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4647 % 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 %
4651 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4653 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4654 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4655 % access that is outside the boundaries of the image cache.
4657 % The format of the SetPixelCacheVirtualMethod() method is:
4659 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4660 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4662 % A description of each parameter follows:
4664 % o image: the image.
4666 % o virtual_pixel_method: choose the type of virtual pixel.
4668 % o exception: return any errors or warnings in this structure.
4672 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4673 ExceptionInfo *exception)
4676 *restrict cache_info;
4679 *restrict image_view;
4687 assert(image != (Image *) NULL);
4688 assert(image->signature == MagickSignature);
4689 if (image->debug != MagickFalse)
4690 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4691 assert(image->cache != (Cache) NULL);
4692 cache_info=(CacheInfo *) image->cache;
4693 assert(cache_info->signature == MagickSignature);
4694 image->alpha_trait=BlendPixelTrait;
4696 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4697 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4698 #pragma omp parallel for schedule(static,4) shared(status) \
4699 magick_threads(image,image,1,1)
4701 for (y=0; y < (ssize_t) image->rows; y++)
4709 if (status == MagickFalse)
4711 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4712 if (q == (Quantum *) NULL)
4717 for (x=0; x < (ssize_t) image->columns; x++)
4719 SetPixelAlpha(image,alpha,q);
4720 q+=GetPixelChannels(image);
4722 status=SyncCacheViewAuthenticPixels(image_view,exception);
4724 image_view=DestroyCacheView(image_view);
4728 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4729 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4732 *restrict cache_info;
4737 assert(image != (Image *) NULL);
4738 assert(image->signature == MagickSignature);
4739 if (image->debug != MagickFalse)
4740 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4741 assert(image->cache != (Cache) NULL);
4742 cache_info=(CacheInfo *) image->cache;
4743 assert(cache_info->signature == MagickSignature);
4744 method=cache_info->virtual_pixel_method;
4745 cache_info->virtual_pixel_method=virtual_pixel_method;
4746 if ((image->columns != 0) && (image->rows != 0))
4747 switch (virtual_pixel_method)
4749 case BackgroundVirtualPixelMethod:
4751 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4752 (image->alpha_trait != BlendPixelTrait))
4753 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4754 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4755 (IsGrayColorspace(image->colorspace) != MagickFalse))
4756 (void) SetImageColorspace(image,sRGBColorspace,exception);
4759 case TransparentVirtualPixelMethod:
4761 if (image->alpha_trait != BlendPixelTrait)
4762 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4776 + 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 %
4780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4782 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4783 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4784 % is synced, otherwise MagickFalse.
4786 % The format of the SyncAuthenticPixelCacheNexus() method is:
4788 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4789 % NexusInfo *nexus_info,ExceptionInfo *exception)
4791 % A description of each parameter follows:
4793 % o image: the image.
4795 % o nexus_info: the cache nexus to sync.
4797 % o exception: return any errors or warnings in this structure.
4800 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4801 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4804 *restrict cache_info;
4810 Transfer pixels to the cache.
4812 assert(image != (Image *) NULL);
4813 assert(image->signature == MagickSignature);
4814 if (image->cache == (Cache) NULL)
4815 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4816 cache_info=(CacheInfo *) image->cache;
4817 assert(cache_info->signature == MagickSignature);
4818 if (cache_info->type == UndefinedCache)
4819 return(MagickFalse);
4820 if (nexus_info->authentic_pixel_cache != MagickFalse)
4822 assert(cache_info->signature == MagickSignature);
4823 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4824 if ((cache_info->metacontent_extent != 0) &&
4825 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4826 return(MagickFalse);
4831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4835 + S y n c A u t h e n t i c P i x e l C a c h e %
4839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4841 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4842 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4843 % otherwise MagickFalse.
4845 % The format of the SyncAuthenticPixelsCache() method is:
4847 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4848 % ExceptionInfo *exception)
4850 % A description of each parameter follows:
4852 % o image: the image.
4854 % o exception: return any errors or warnings in this structure.
4857 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4858 ExceptionInfo *exception)
4861 *restrict cache_info;
4864 id = GetOpenMPThreadId();
4869 assert(image != (Image *) NULL);
4870 assert(image->signature == MagickSignature);
4871 assert(image->cache != (Cache) NULL);
4872 cache_info=(CacheInfo *) image->cache;
4873 assert(cache_info->signature == MagickSignature);
4874 assert(id < (int) cache_info->number_threads);
4875 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4885 % S y n c A u t h e n t i c P i x e l s %
4889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4891 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4892 % The method returns MagickTrue if the pixel region is flushed, otherwise
4895 % The format of the SyncAuthenticPixels() method is:
4897 % MagickBooleanType SyncAuthenticPixels(Image *image,
4898 % ExceptionInfo *exception)
4900 % A description of each parameter follows:
4902 % o image: the image.
4904 % o exception: return any errors or warnings in this structure.
4907 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4908 ExceptionInfo *exception)
4911 *restrict cache_info;
4914 id = GetOpenMPThreadId();
4919 assert(image != (Image *) NULL);
4920 assert(image->signature == MagickSignature);
4921 assert(image->cache != (Cache) NULL);
4922 cache_info=(CacheInfo *) image->cache;
4923 assert(cache_info->signature == MagickSignature);
4924 if (cache_info->methods.sync_authentic_pixels_handler !=
4925 (SyncAuthenticPixelsHandler) NULL)
4927 status=cache_info->methods.sync_authentic_pixels_handler(image,
4931 assert(id < (int) cache_info->number_threads);
4932 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4942 + S y n c I m a g e P i x e l C a c h e %
4946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4948 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4949 % The method returns MagickTrue if the pixel region is flushed, otherwise
4952 % The format of the SyncImagePixelCache() method is:
4954 % MagickBooleanType SyncImagePixelCache(Image *image,
4955 % ExceptionInfo *exception)
4957 % A description of each parameter follows:
4959 % o image: the image.
4961 % o exception: return any errors or warnings in this structure.
4964 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4965 ExceptionInfo *exception)
4968 *restrict cache_info;
4970 assert(image != (Image *) NULL);
4971 assert(exception != (ExceptionInfo *) NULL);
4972 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4973 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4981 + 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 %
4985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4987 % WritePixelCacheMetacontent() writes the meta-content to the specified region
4988 % of the pixel cache.
4990 % The format of the WritePixelCacheMetacontent() method is:
4992 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4993 % NexusInfo *nexus_info,ExceptionInfo *exception)
4995 % A description of each parameter follows:
4997 % o cache_info: the pixel cache.
4999 % o nexus_info: the cache nexus to write the meta-content.
5001 % o exception: return any errors or warnings in this structure.
5004 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5005 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5015 register const unsigned char
5024 if (cache_info->metacontent_extent == 0)
5025 return(MagickFalse);
5026 if (nexus_info->authentic_pixel_cache != MagickFalse)
5028 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5029 nexus_info->region.x;
5030 length=(MagickSizeType) nexus_info->region.width*
5031 cache_info->metacontent_extent;
5032 extent=(MagickSizeType) length*nexus_info->region.height;
5033 rows=nexus_info->region.height;
5035 p=(unsigned char *) nexus_info->metacontent;
5036 switch (cache_info->type)
5041 register unsigned char
5045 Write associated pixels to memory.
5047 if ((cache_info->columns == nexus_info->region.width) &&
5048 (extent == (MagickSizeType) ((size_t) extent)))
5053 q=(unsigned char *) cache_info->metacontent+offset*
5054 cache_info->metacontent_extent;
5055 for (y=0; y < (ssize_t) rows; y++)
5057 (void) memcpy(q,p,(size_t) length);
5058 p+=nexus_info->region.width*cache_info->metacontent_extent;
5059 q+=cache_info->columns*cache_info->metacontent_extent;
5066 Write associated pixels to disk.
5068 LockSemaphoreInfo(cache_info->file_semaphore);
5069 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5071 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5072 cache_info->cache_filename);
5073 UnlockSemaphoreInfo(cache_info->file_semaphore);
5074 return(MagickFalse);
5076 if ((cache_info->columns == nexus_info->region.width) &&
5077 (extent <= MagickMaxBufferExtent))
5082 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5083 for (y=0; y < (ssize_t) rows; y++)
5085 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5086 cache_info->number_channels*sizeof(Quantum)+offset*
5087 cache_info->metacontent_extent,length,(const unsigned char *) p);
5088 if (count != (MagickOffsetType) length)
5090 p+=cache_info->metacontent_extent*nexus_info->region.width;
5091 offset+=cache_info->columns;
5093 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5094 (void) ClosePixelCacheOnDisk(cache_info);
5095 UnlockSemaphoreInfo(cache_info->file_semaphore);
5098 case DistributedCache:
5104 Write metacontent to distributed cache.
5106 LockSemaphoreInfo(cache_info->file_semaphore);
5107 region=nexus_info->region;
5108 if ((cache_info->columns != nexus_info->region.width) ||
5109 (extent > MagickMaxBufferExtent))
5116 for (y=0; y < (ssize_t) rows; y++)
5118 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5119 cache_info->server_info,®ion,length,(const unsigned char *) p);
5120 if (count != (MagickOffsetType) length)
5122 p+=cache_info->metacontent_extent*nexus_info->region.width;
5125 UnlockSemaphoreInfo(cache_info->file_semaphore);
5131 if (y < (ssize_t) rows)
5133 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5134 cache_info->cache_filename);
5135 return(MagickFalse);
5137 if ((cache_info->debug != MagickFalse) &&
5138 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5139 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5140 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5141 nexus_info->region.width,(double) nexus_info->region.height,(double)
5142 nexus_info->region.x,(double) nexus_info->region.y);
5147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151 + W r i t e C a c h e P i x e l s %
5155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5157 % WritePixelCachePixels() writes image pixels to the specified region of the
5160 % The format of the WritePixelCachePixels() method is:
5162 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5163 % NexusInfo *nexus_info,ExceptionInfo *exception)
5165 % A description of each parameter follows:
5167 % o cache_info: the pixel cache.
5169 % o nexus_info: the cache nexus to write the pixels.
5171 % o exception: return any errors or warnings in this structure.
5174 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5175 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5185 register const Quantum
5194 if (nexus_info->authentic_pixel_cache != MagickFalse)
5196 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5197 nexus_info->region.x;
5198 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5200 extent=length*nexus_info->region.height;
5201 rows=nexus_info->region.height;
5203 p=nexus_info->pixels;
5204 switch (cache_info->type)
5213 Write pixels to memory.
5215 if ((cache_info->columns == nexus_info->region.width) &&
5216 (extent == (MagickSizeType) ((size_t) extent)))
5221 q=cache_info->pixels+offset*cache_info->number_channels;
5222 for (y=0; y < (ssize_t) rows; y++)
5224 (void) memcpy(q,p,(size_t) length);
5225 p+=cache_info->number_channels*nexus_info->region.width;
5226 q+=cache_info->columns*cache_info->number_channels;
5233 Write pixels to disk.
5235 LockSemaphoreInfo(cache_info->file_semaphore);
5236 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5238 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5239 cache_info->cache_filename);
5240 UnlockSemaphoreInfo(cache_info->file_semaphore);
5241 return(MagickFalse);
5243 if ((cache_info->columns == nexus_info->region.width) &&
5244 (extent <= MagickMaxBufferExtent))
5249 for (y=0; y < (ssize_t) rows; y++)
5251 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5252 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5254 if (count != (MagickOffsetType) length)
5256 p+=cache_info->number_channels*nexus_info->region.width;
5257 offset+=cache_info->columns;
5259 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5260 (void) ClosePixelCacheOnDisk(cache_info);
5261 UnlockSemaphoreInfo(cache_info->file_semaphore);
5264 case DistributedCache:
5270 Write pixels to distributed cache.
5272 LockSemaphoreInfo(cache_info->file_semaphore);
5273 region=nexus_info->region;
5274 if ((cache_info->columns != nexus_info->region.width) ||
5275 (extent > MagickMaxBufferExtent))
5282 for (y=0; y < (ssize_t) rows; y++)
5284 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5285 cache_info->server_info,®ion,length,(const unsigned char *) p);
5286 if (count != (MagickOffsetType) length)
5288 p+=cache_info->number_channels*nexus_info->region.width;
5291 UnlockSemaphoreInfo(cache_info->file_semaphore);
5297 if (y < (ssize_t) rows)
5299 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5300 cache_info->cache_filename);
5301 return(MagickFalse);
5303 if ((cache_info->debug != MagickFalse) &&
5304 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5305 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5306 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5307 nexus_info->region.width,(double) nexus_info->region.height,(double)
5308 nexus_info->region.x,(double) nexus_info->region.y);