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-2014 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=AcquireSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->file_semaphore=AcquireSemaphoreInfo();
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 if (cache_semaphore == (SemaphoreInfo *) NULL)
328 cache_semaphore=AcquireSemaphoreInfo();
333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337 + C a c h e C o m p o n e n t T e r m i n u s %
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 % CacheComponentTerminus() destroys the cache component.
345 % The format of the CacheComponentTerminus() method is:
347 % CacheComponentTerminus(void)
350 MagickPrivate void CacheComponentTerminus(void)
352 if (cache_semaphore == (SemaphoreInfo *) NULL)
353 ActivateSemaphoreInfo(&cache_semaphore);
354 LockSemaphoreInfo(cache_semaphore);
355 instantiate_cache=MagickFalse;
356 UnlockSemaphoreInfo(cache_semaphore);
357 RelinquishSemaphoreInfo(&cache_semaphore);
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 + C l o n e P i x e l C a c h e %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371 % ClonePixelCache() clones a pixel cache.
373 % The format of the ClonePixelCache() method is:
375 % Cache ClonePixelCache(const Cache cache)
377 % A description of each parameter follows:
379 % o cache: the pixel cache.
382 MagickPrivate Cache ClonePixelCache(const Cache cache)
385 *restrict clone_info;
388 *restrict cache_info;
390 assert(cache != NULL);
391 cache_info=(const CacheInfo *) cache;
392 assert(cache_info->signature == MagickSignature);
393 if (cache_info->debug != MagickFalse)
394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
395 cache_info->filename);
396 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
397 if (clone_info == (Cache) NULL)
398 return((Cache) NULL);
399 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
400 return((Cache ) clone_info);
404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408 + C l o n e P i x e l C a c h e M e t h o d s %
412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
417 % The format of the ClonePixelCacheMethods() method is:
419 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
421 % A description of each parameter follows:
423 % o clone: Specifies a pointer to a Cache structure.
425 % o cache: the pixel cache.
428 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
431 *restrict cache_info,
432 *restrict source_info;
434 assert(clone != (Cache) NULL);
435 source_info=(CacheInfo *) clone;
436 assert(source_info->signature == MagickSignature);
437 if (source_info->debug != MagickFalse)
438 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
439 source_info->filename);
440 assert(cache != (Cache) NULL);
441 cache_info=(CacheInfo *) cache;
442 assert(cache_info->signature == MagickSignature);
443 source_info->methods=cache_info->methods;
447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451 + 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 %
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
456 % ClonePixelCacheRepository() clones the source pixel cache to the destination
459 % The format of the ClonePixelCacheRepository() method is:
461 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
462 % CacheInfo *source_info,ExceptionInfo *exception)
464 % A description of each parameter follows:
466 % o cache_info: the pixel cache.
468 % o source_info: the source pixel cache.
470 % o exception: return any errors or warnings in this structure.
474 static inline void CopyPixels(Quantum *destination,const Quantum *source,
475 const MagickSizeType number_pixels)
477 #if !defined(MAGICKCORE_OPENMP_SUPPORT) || (MAGICKCORE_QUANTUM_DEPTH <= 8)
478 (void) memcpy(destination,source,(size_t) number_pixels*sizeof(*source));
481 register MagickOffsetType
484 if ((number_pixels*sizeof(*source)) < MagickMaxBufferExtent)
486 (void) memcpy(destination,source,(size_t) number_pixels*
490 #pragma omp parallel for
491 for (i=0; i < (MagickOffsetType) number_pixels; i++)
492 destination[i]=source[i];
497 static inline MagickSizeType MagickMin(const MagickSizeType x,
498 const MagickSizeType y)
505 static MagickBooleanType ClonePixelCacheRepository(
506 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
507 ExceptionInfo *exception)
509 #define MaxCacheThreads 2
510 #define cache_threads(source,destination,chunk) \
511 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
512 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
513 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
520 **restrict cache_nexus,
521 **restrict clone_nexus;
529 assert(cache_info != (CacheInfo *) NULL);
530 assert(clone_info != (CacheInfo *) NULL);
531 assert(exception != (ExceptionInfo *) NULL);
532 if (cache_info->type == PingCache)
534 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
535 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
536 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
537 (cache_info->columns == clone_info->columns) &&
538 (cache_info->rows == clone_info->rows) &&
539 (cache_info->number_channels == clone_info->number_channels) &&
540 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
541 (cache_info->metacontent_extent == clone_info->metacontent_extent))
543 CopyPixels(clone_info->pixels,cache_info->pixels,cache_info->columns*
544 cache_info->number_channels*cache_info->rows);
545 if ((cache_info->metacontent_extent != 0) &&
546 (clone_info->metacontent_extent != 0))
547 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
548 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
549 sizeof(cache_info->metacontent));
553 Mismatched pixel cache morphology.
555 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
556 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
557 if ((cache_nexus == (NexusInfo **) NULL) ||
558 (clone_nexus == (NexusInfo **) NULL))
559 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
560 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
561 optimize=(cache_info->number_channels == clone_info->number_channels) &&
562 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
563 MagickTrue : MagickFalse;
564 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
565 clone_info->columns*clone_info->number_channels);
567 #if defined(MAGICKCORE_OPENMP_SUPPORT)
568 #pragma omp parallel for schedule(static,4) shared(status) \
569 cache_threads(cache_info,clone_info,cache_info->rows)
571 for (y=0; y < (ssize_t) cache_info->rows; y++)
574 id = GetOpenMPThreadId();
585 if (status == MagickFalse)
587 if (y >= (ssize_t) clone_info->rows)
589 region.width=cache_info->columns;
593 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
595 if (pixels == (Quantum *) NULL)
597 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
598 if (status == MagickFalse)
600 region.width=clone_info->columns;
601 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
602 clone_nexus[id],exception);
603 if (pixels == (Quantum *) NULL)
605 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
606 clone_nexus[id]->length);
607 if (optimize != MagickFalse)
608 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
612 register const Quantum
619 Mismatched pixel channel map.
621 p=cache_nexus[id]->pixels;
622 q=clone_nexus[id]->pixels;
623 for (x=0; x < (ssize_t) cache_info->columns; x++)
628 if (x == (ssize_t) clone_info->columns)
630 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
638 channel=clone_info->channel_map[i].channel;
639 traits=cache_info->channel_map[channel].traits;
640 if (traits != UndefinedPixelTrait)
641 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
645 p+=cache_info->number_channels;
648 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
650 if ((cache_info->metacontent_extent != 0) &&
651 (clone_info->metacontent_extent != 0))
656 length=(size_t) MagickMin(cache_info->metacontent_extent,
657 clone_info->metacontent_extent);
658 #if defined(MAGICKCORE_OPENMP_SUPPORT)
659 #pragma omp parallel for schedule(static,4) shared(status) \
660 cache_threads(cache_info,clone_info,cache_info->rows)
662 for (y=0; y < (ssize_t) cache_info->rows; y++)
665 id = GetOpenMPThreadId();
673 if (status == MagickFalse)
675 if (y >= (ssize_t) clone_info->rows)
677 region.width=cache_info->columns;
681 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
682 cache_nexus[id],exception);
683 if (pixels == (Quantum *) NULL)
685 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
686 if (status == MagickFalse)
688 region.width=clone_info->columns;
689 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
690 clone_nexus[id],exception);
691 if (pixels == (Quantum *) NULL)
693 if (clone_nexus[id]->metacontent != (void *) NULL)
694 (void) memcpy(clone_nexus[id]->metacontent,
695 cache_nexus[id]->metacontent,length*
696 sizeof(cache_nexus[id]->metacontent));
697 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
700 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
701 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
702 if (cache_info->debug != MagickFalse)
705 message[MaxTextExtent];
707 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
708 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
709 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
710 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720 + D e s t r o y I m a g e P i x e l C a c h e %
724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
726 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
728 % The format of the DestroyImagePixelCache() method is:
730 % void DestroyImagePixelCache(Image *image)
732 % A description of each parameter follows:
734 % o image: the image.
737 static void DestroyImagePixelCache(Image *image)
739 assert(image != (Image *) NULL);
740 assert(image->signature == MagickSignature);
741 if (image->debug != MagickFalse)
742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
743 if (image->cache == (void *) NULL)
745 image->cache=DestroyPixelCache(image->cache);
749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753 + D e s t r o y I m a g e P i x e l s %
757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
759 % DestroyImagePixels() deallocates memory associated with the pixel cache.
761 % The format of the DestroyImagePixels() method is:
763 % void DestroyImagePixels(Image *image)
765 % A description of each parameter follows:
767 % o image: the image.
770 MagickExport void DestroyImagePixels(Image *image)
773 *restrict cache_info;
775 assert(image != (const Image *) NULL);
776 assert(image->signature == MagickSignature);
777 if (image->debug != MagickFalse)
778 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
779 assert(image->cache != (Cache) NULL);
780 cache_info=(CacheInfo *) image->cache;
781 assert(cache_info->signature == MagickSignature);
782 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
784 cache_info->methods.destroy_pixel_handler(image);
787 image->cache=DestroyPixelCache(image->cache);
791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795 + D e s t r o y P i x e l C a c h e %
799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
801 % DestroyPixelCache() deallocates memory associated with the pixel cache.
803 % The format of the DestroyPixelCache() method is:
805 % Cache DestroyPixelCache(Cache cache)
807 % A description of each parameter follows:
809 % o cache: the pixel cache.
813 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
819 if (cache_info->file != -1)
821 status=close(cache_info->file);
822 cache_info->file=(-1);
823 RelinquishMagickResource(FileResource,1);
825 return(status == -1 ? MagickFalse : MagickTrue);
828 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
830 switch (cache_info->type)
834 if (cache_info->mapped == MagickFalse)
835 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
839 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
840 cache_info->pixels=(Quantum *) NULL;
842 RelinquishMagickResource(MemoryResource,cache_info->length);
847 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
848 cache_info->pixels=(Quantum *) NULL;
849 if (cache_info->mode != ReadMode)
850 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
851 *cache_info->cache_filename='\0';
852 RelinquishMagickResource(MapResource,cache_info->length);
856 if (cache_info->file != -1)
857 (void) ClosePixelCacheOnDisk(cache_info);
858 if (cache_info->mode != ReadMode)
859 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
860 *cache_info->cache_filename='\0';
861 RelinquishMagickResource(DiskResource,cache_info->length);
864 case DistributedCache:
866 *cache_info->cache_filename='\0';
867 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
868 cache_info->server_info);
874 cache_info->type=UndefinedCache;
875 cache_info->mapped=MagickFalse;
876 cache_info->metacontent=(void *) NULL;
879 MagickPrivate Cache DestroyPixelCache(Cache cache)
882 *restrict cache_info;
884 assert(cache != (Cache) NULL);
885 cache_info=(CacheInfo *) cache;
886 assert(cache_info->signature == MagickSignature);
887 if (cache_info->debug != MagickFalse)
888 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
889 cache_info->filename);
890 LockSemaphoreInfo(cache_info->semaphore);
891 cache_info->reference_count--;
892 if (cache_info->reference_count != 0)
894 UnlockSemaphoreInfo(cache_info->semaphore);
895 return((Cache) NULL);
897 UnlockSemaphoreInfo(cache_info->semaphore);
898 if (cache_info->debug != MagickFalse)
901 message[MaxTextExtent];
903 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
904 cache_info->filename);
905 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
907 RelinquishPixelCachePixels(cache_info);
908 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
909 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
910 cache_info->server_info);
911 if (cache_info->nexus_info != (NexusInfo **) NULL)
912 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
913 cache_info->number_threads);
914 if (cache_info->random_info != (RandomInfo *) NULL)
915 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
916 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
917 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
918 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
919 RelinquishSemaphoreInfo(&cache_info->semaphore);
920 cache_info->signature=(~MagickSignature);
921 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931 + D e s t r o y P i x e l C a c h e N e x u s %
935 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
937 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
939 % The format of the DestroyPixelCacheNexus() method is:
941 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
942 % const size_t number_threads)
944 % A description of each parameter follows:
946 % o nexus_info: the nexus to destroy.
948 % o number_threads: the number of nexus threads.
952 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
954 if (nexus_info->mapped == MagickFalse)
955 (void) RelinquishAlignedMemory(nexus_info->cache);
957 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
958 nexus_info->cache=(Quantum *) NULL;
959 nexus_info->pixels=(Quantum *) NULL;
960 nexus_info->metacontent=(void *) NULL;
961 nexus_info->length=0;
962 nexus_info->mapped=MagickFalse;
965 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
966 const size_t number_threads)
971 assert(nexus_info != (NexusInfo **) NULL);
972 for (i=0; i < (ssize_t) number_threads; i++)
974 if (nexus_info[i]->cache != (Quantum *) NULL)
975 RelinquishCacheNexusPixels(nexus_info[i]);
976 nexus_info[i]->signature=(~MagickSignature);
978 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
979 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 % G e t A u t h e n t i c M e t a c o n t e n t %
992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
994 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
995 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
996 % returned if the associated pixels are not available.
998 % The format of the GetAuthenticMetacontent() method is:
1000 % void *GetAuthenticMetacontent(const Image *image)
1002 % A description of each parameter follows:
1004 % o image: the image.
1007 MagickExport void *GetAuthenticMetacontent(const Image *image)
1010 *restrict cache_info;
1013 id = GetOpenMPThreadId();
1015 assert(image != (const Image *) NULL);
1016 assert(image->signature == MagickSignature);
1017 assert(image->cache != (Cache) NULL);
1018 cache_info=(CacheInfo *) image->cache;
1019 assert(cache_info->signature == MagickSignature);
1020 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1021 (GetAuthenticMetacontentFromHandler) NULL)
1026 metacontent=cache_info->methods.
1027 get_authentic_metacontent_from_handler(image);
1028 return(metacontent);
1030 assert(id < (int) cache_info->number_threads);
1031 return(cache_info->nexus_info[id]->metacontent);
1035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1039 + 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 %
1043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1046 % with the last call to QueueAuthenticPixelsCache() or
1047 % GetAuthenticPixelsCache().
1049 % The format of the GetAuthenticMetacontentFromCache() method is:
1051 % void *GetAuthenticMetacontentFromCache(const Image *image)
1053 % A description of each parameter follows:
1055 % o image: the image.
1058 static void *GetAuthenticMetacontentFromCache(const Image *image)
1061 *restrict cache_info;
1064 id = GetOpenMPThreadId();
1066 assert(image != (const Image *) NULL);
1067 assert(image->signature == MagickSignature);
1068 assert(image->cache != (Cache) NULL);
1069 cache_info=(CacheInfo *) image->cache;
1070 assert(cache_info->signature == MagickSignature);
1071 assert(id < (int) cache_info->number_threads);
1072 return(cache_info->nexus_info[id]->metacontent);
1076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080 + 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 %
1084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1087 % disk pixel cache as defined by the geometry parameters. A pointer to the
1088 % pixels is returned if the pixels are transferred, otherwise a NULL is
1091 % The format of the GetAuthenticPixelCacheNexus() method is:
1093 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1094 % const ssize_t y,const size_t columns,const size_t rows,
1095 % NexusInfo *nexus_info,ExceptionInfo *exception)
1097 % A description of each parameter follows:
1099 % o image: the image.
1101 % o x,y,columns,rows: These values define the perimeter of a region of
1104 % o nexus_info: the cache nexus to return.
1106 % o exception: return any errors or warnings in this structure.
1110 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1111 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1112 ExceptionInfo *exception)
1115 *restrict cache_info;
1121 Transfer pixels from the cache.
1123 assert(image != (Image *) NULL);
1124 assert(image->signature == MagickSignature);
1125 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1126 nexus_info,exception);
1127 if (pixels == (Quantum *) NULL)
1128 return((Quantum *) NULL);
1129 cache_info=(CacheInfo *) image->cache;
1130 assert(cache_info->signature == MagickSignature);
1131 if (nexus_info->authentic_pixel_cache != MagickFalse)
1133 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1134 return((Quantum *) NULL);
1135 if (cache_info->metacontent_extent != 0)
1136 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1137 return((Quantum *) NULL);
1142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1146 + 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 %
1150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1153 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1155 % The format of the GetAuthenticPixelsFromCache() method is:
1157 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1159 % A description of each parameter follows:
1161 % o image: the image.
1164 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1167 *restrict cache_info;
1170 id = GetOpenMPThreadId();
1172 assert(image != (const Image *) NULL);
1173 assert(image->signature == MagickSignature);
1174 assert(image->cache != (Cache) NULL);
1175 cache_info=(CacheInfo *) image->cache;
1176 assert(cache_info->signature == MagickSignature);
1177 assert(id < (int) cache_info->number_threads);
1178 return(cache_info->nexus_info[id]->pixels);
1182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1186 % G e t A u t h e n t i c P i x e l Q u e u e %
1190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 % GetAuthenticPixelQueue() returns the authentic pixels associated
1193 % corresponding with the last call to QueueAuthenticPixels() or
1194 % GetAuthenticPixels().
1196 % The format of the GetAuthenticPixelQueue() method is:
1198 % Quantum *GetAuthenticPixelQueue(const Image image)
1200 % A description of each parameter follows:
1202 % o image: the image.
1205 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1208 *restrict cache_info;
1211 id = GetOpenMPThreadId();
1213 assert(image != (const Image *) NULL);
1214 assert(image->signature == MagickSignature);
1215 assert(image->cache != (Cache) NULL);
1216 cache_info=(CacheInfo *) image->cache;
1217 assert(cache_info->signature == MagickSignature);
1218 if (cache_info->methods.get_authentic_pixels_from_handler !=
1219 (GetAuthenticPixelsFromHandler) NULL)
1220 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1221 assert(id < (int) cache_info->number_threads);
1222 return(cache_info->nexus_info[id]->pixels);
1226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1230 % G e t A u t h e n t i c P i x e l s %
1233 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1235 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1236 % region is successfully accessed, a pointer to a Quantum array
1237 % representing the region is returned, otherwise NULL is returned.
1239 % The returned pointer may point to a temporary working copy of the pixels
1240 % or it may point to the original pixels in memory. Performance is maximized
1241 % if the selected region is part of one row, or one or more full rows, since
1242 % then there is opportunity to access the pixels in-place (without a copy)
1243 % if the image is in memory, or in a memory-mapped file. The returned pointer
1244 % must *never* be deallocated by the user.
1246 % Pixels accessed via the returned pointer represent a simple array of type
1247 % Quantum. If the image has corresponding metacontent,call
1248 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1249 % meta-content corresponding to the region. Once the Quantum array has
1250 % been updated, the changes must be saved back to the underlying image using
1251 % SyncAuthenticPixels() or they may be lost.
1253 % The format of the GetAuthenticPixels() method is:
1255 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1256 % const ssize_t y,const size_t columns,const size_t rows,
1257 % ExceptionInfo *exception)
1259 % A description of each parameter follows:
1261 % o image: the image.
1263 % o x,y,columns,rows: These values define the perimeter of a region of
1266 % o exception: return any errors or warnings in this structure.
1269 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1270 const ssize_t y,const size_t columns,const size_t rows,
1271 ExceptionInfo *exception)
1274 *restrict cache_info;
1277 id = GetOpenMPThreadId();
1282 assert(image != (Image *) NULL);
1283 assert(image->signature == MagickSignature);
1284 assert(image->cache != (Cache) NULL);
1285 cache_info=(CacheInfo *) image->cache;
1286 assert(cache_info->signature == MagickSignature);
1287 if (cache_info->methods.get_authentic_pixels_handler !=
1288 (GetAuthenticPixelsHandler) NULL)
1290 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1294 assert(id < (int) cache_info->number_threads);
1295 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1296 cache_info->nexus_info[id],exception);
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305 + G e t A u t h e n t i c P i x e l s C a c h e %
1309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1312 % as defined by the geometry parameters. A pointer to the pixels is returned
1313 % if the pixels are transferred, otherwise a NULL is returned.
1315 % The format of the GetAuthenticPixelsCache() method is:
1317 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1318 % const ssize_t y,const size_t columns,const size_t rows,
1319 % ExceptionInfo *exception)
1321 % A description of each parameter follows:
1323 % o image: the image.
1325 % o x,y,columns,rows: These values define the perimeter of a region of
1328 % o exception: return any errors or warnings in this structure.
1331 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1332 const ssize_t y,const size_t columns,const size_t rows,
1333 ExceptionInfo *exception)
1336 *restrict cache_info;
1339 id = GetOpenMPThreadId();
1344 assert(image != (const Image *) NULL);
1345 assert(image->signature == MagickSignature);
1346 assert(image->cache != (Cache) NULL);
1347 cache_info=(CacheInfo *) image->cache;
1348 if (cache_info == (Cache) NULL)
1349 return((Quantum *) NULL);
1350 assert(cache_info->signature == MagickSignature);
1351 assert(id < (int) cache_info->number_threads);
1352 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1353 cache_info->nexus_info[id],exception);
1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 + G e t I m a g e E x t e n t %
1366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368 % GetImageExtent() returns the extent of the pixels associated corresponding
1369 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1371 % The format of the GetImageExtent() method is:
1373 % MagickSizeType GetImageExtent(const Image *image)
1375 % A description of each parameter follows:
1377 % o image: the image.
1380 MagickExport MagickSizeType GetImageExtent(const Image *image)
1383 *restrict cache_info;
1386 id = GetOpenMPThreadId();
1388 assert(image != (Image *) NULL);
1389 assert(image->signature == MagickSignature);
1390 if (image->debug != MagickFalse)
1391 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1392 assert(image->cache != (Cache) NULL);
1393 cache_info=(CacheInfo *) image->cache;
1394 assert(cache_info->signature == MagickSignature);
1395 assert(id < (int) cache_info->number_threads);
1396 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404 + G e t I m a g e P i x e l C a c h e %
1408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410 % GetImagePixelCache() ensures that there is only a single reference to the
1411 % pixel cache to be modified, updating the provided cache pointer to point to
1412 % a clone of the original pixel cache if necessary.
1414 % The format of the GetImagePixelCache method is:
1416 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1417 % ExceptionInfo *exception)
1419 % A description of each parameter follows:
1421 % o image: the image.
1423 % o clone: any value other than MagickFalse clones the cache pixels.
1425 % o exception: return any errors or warnings in this structure.
1429 static inline MagickBooleanType ValidatePixelCacheMorphology(
1430 const Image *restrict image)
1433 *restrict cache_info;
1435 const PixelChannelMap
1440 Does the image match the pixel cache morphology?
1442 cache_info=(CacheInfo *) image->cache;
1443 p=image->channel_map;
1444 q=cache_info->channel_map;
1445 if ((image->storage_class != cache_info->storage_class) ||
1446 (image->colorspace != cache_info->colorspace) ||
1447 (image->alpha_trait != cache_info->alpha_trait) ||
1448 (image->read_mask != cache_info->read_mask) ||
1449 (image->write_mask != cache_info->write_mask) ||
1450 (image->columns != cache_info->columns) ||
1451 (image->rows != cache_info->rows) ||
1452 (image->number_channels != cache_info->number_channels) ||
1453 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1454 (image->metacontent_extent != cache_info->metacontent_extent) ||
1455 (cache_info->nexus_info == (NexusInfo **) NULL))
1456 return(MagickFalse);
1460 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1461 ExceptionInfo *exception)
1464 *restrict cache_info;
1470 static MagickSizeType
1476 cache_timestamp = 0;
1479 LockSemaphoreInfo(image->semaphore);
1480 if (cpu_throttle == 0)
1481 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1482 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1483 MagickDelay(cpu_throttle);
1484 if (time_limit == 0)
1487 Set the expire time in seconds.
1489 time_limit=GetMagickResourceLimit(TimeResource);
1490 cache_timestamp=time((time_t *) NULL);
1492 if ((time_limit != MagickResourceInfinity) &&
1493 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1495 #if defined(ECANCELED)
1498 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1500 assert(image->cache != (Cache) NULL);
1501 cache_info=(CacheInfo *) image->cache;
1502 destroy=MagickFalse;
1503 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1505 LockSemaphoreInfo(cache_info->semaphore);
1506 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1517 clone_image=(*image);
1518 clone_image.semaphore=AcquireSemaphoreInfo();
1519 clone_image.reference_count=1;
1520 clone_image.cache=ClonePixelCache(cache_info);
1521 clone_info=(CacheInfo *) clone_image.cache;
1522 status=OpenPixelCache(&clone_image,IOMode,exception);
1523 if (status != MagickFalse)
1525 if (clone != MagickFalse)
1526 status=ClonePixelCacheRepository(clone_info,cache_info,
1528 if (status != MagickFalse)
1530 if (cache_info->reference_count == 1)
1531 cache_info->nexus_info=(NexusInfo **) NULL;
1533 image->cache=clone_image.cache;
1536 RelinquishSemaphoreInfo(&clone_image.semaphore);
1538 UnlockSemaphoreInfo(cache_info->semaphore);
1540 if (destroy != MagickFalse)
1541 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1542 if (status != MagickFalse)
1545 Ensure the image matches the pixel cache morphology.
1547 image->taint=MagickTrue;
1548 image->type=UndefinedType;
1549 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1551 status=OpenPixelCache(image,IOMode,exception);
1552 cache_info=(CacheInfo *) image->cache;
1553 if (cache_info->type == DiskCache)
1554 (void) ClosePixelCacheOnDisk(cache_info);
1557 UnlockSemaphoreInfo(image->semaphore);
1558 if (status == MagickFalse)
1559 return((Cache) NULL);
1560 return(image->cache);
1564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568 + G e t I m a g e P i x e l C a c h e T y p e %
1572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1574 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1575 % DiskCache, MemoryCache, MapCache, or PingCache.
1577 % The format of the GetImagePixelCacheType() method is:
1579 % CacheType GetImagePixelCacheType(const Image *image)
1581 % A description of each parameter follows:
1583 % o image: the image.
1586 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1589 *restrict cache_info;
1591 assert(image != (Image *) NULL);
1592 assert(image->signature == MagickSignature);
1593 assert(image->cache != (Cache) NULL);
1594 cache_info=(CacheInfo *) image->cache;
1595 assert(cache_info->signature == MagickSignature);
1596 return(cache_info->type);
1600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1604 % G e t O n e A u t h e n t i c P i x e l %
1608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1610 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1611 % location. The image background color is returned if an error occurs.
1613 % The format of the GetOneAuthenticPixel() method is:
1615 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1616 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1618 % A description of each parameter follows:
1620 % o image: the image.
1622 % o x,y: These values define the location of the pixel to return.
1624 % o pixel: return a pixel at the specified (x,y) location.
1626 % o exception: return any errors or warnings in this structure.
1629 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1630 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1633 *restrict cache_info;
1641 assert(image != (Image *) NULL);
1642 assert(image->signature == MagickSignature);
1643 assert(image->cache != (Cache) NULL);
1644 cache_info=(CacheInfo *) image->cache;
1645 assert(cache_info->signature == MagickSignature);
1646 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1647 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1648 (GetOneAuthenticPixelFromHandler) NULL)
1649 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1651 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1652 if (q == (Quantum *) NULL)
1654 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1655 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1656 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1657 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1658 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1659 return(MagickFalse);
1661 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1663 PixelChannel channel=GetPixelChannelChannel(image,i);
1664 pixel[channel]=q[i];
1670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1674 + 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 %
1678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1680 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1681 % location. The image background color is returned if an error occurs.
1683 % The format of the GetOneAuthenticPixelFromCache() method is:
1685 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1686 % const ssize_t x,const ssize_t y,Quantum *pixel,
1687 % ExceptionInfo *exception)
1689 % A description of each parameter follows:
1691 % o image: the image.
1693 % o x,y: These values define the location of the pixel to return.
1695 % o pixel: return a pixel at the specified (x,y) location.
1697 % o exception: return any errors or warnings in this structure.
1700 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1701 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1704 *restrict cache_info;
1707 id = GetOpenMPThreadId();
1715 assert(image != (const Image *) NULL);
1716 assert(image->signature == MagickSignature);
1717 assert(image->cache != (Cache) NULL);
1718 cache_info=(CacheInfo *) image->cache;
1719 assert(cache_info->signature == MagickSignature);
1720 assert(id < (int) cache_info->number_threads);
1721 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1722 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1724 if (q == (Quantum *) NULL)
1726 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1727 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1728 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1729 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1730 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1731 return(MagickFalse);
1733 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1735 PixelChannel channel=GetPixelChannelChannel(image,i);
1736 pixel[channel]=q[i];
1742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1746 % G e t O n e V i r t u a l P i x e l %
1750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1752 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1753 % (x,y) location. The image background color is returned if an error occurs.
1754 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1756 % The format of the GetOneVirtualPixel() method is:
1758 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1759 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1761 % A description of each parameter follows:
1763 % o image: the image.
1765 % o x,y: These values define the location of the pixel to return.
1767 % o pixel: return a pixel at the specified (x,y) location.
1769 % o exception: return any errors or warnings in this structure.
1772 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1773 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1776 *restrict cache_info;
1779 id = GetOpenMPThreadId();
1787 assert(image != (const Image *) NULL);
1788 assert(image->signature == MagickSignature);
1789 assert(image->cache != (Cache) NULL);
1790 cache_info=(CacheInfo *) image->cache;
1791 assert(cache_info->signature == MagickSignature);
1792 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1793 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1794 (GetOneVirtualPixelFromHandler) NULL)
1795 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1796 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1797 assert(id < (int) cache_info->number_threads);
1798 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1799 1UL,1UL,cache_info->nexus_info[id],exception);
1800 if (p == (const Quantum *) NULL)
1802 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1803 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1804 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1805 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1806 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1807 return(MagickFalse);
1809 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1811 PixelChannel channel=GetPixelChannelChannel(image,i);
1812 pixel[channel]=p[i];
1818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1822 + 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 %
1826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1828 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1829 % specified (x,y) location. The image background color is returned if an
1832 % The format of the GetOneVirtualPixelFromCache() method is:
1834 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1835 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1836 % Quantum *pixel,ExceptionInfo *exception)
1838 % A description of each parameter follows:
1840 % o image: the image.
1842 % o virtual_pixel_method: the virtual pixel method.
1844 % o x,y: These values define the location of the pixel to return.
1846 % o pixel: return a pixel at the specified (x,y) location.
1848 % o exception: return any errors or warnings in this structure.
1851 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1852 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1853 Quantum *pixel,ExceptionInfo *exception)
1856 *restrict cache_info;
1859 id = GetOpenMPThreadId();
1867 assert(image != (const Image *) NULL);
1868 assert(image->signature == MagickSignature);
1869 assert(image->cache != (Cache) NULL);
1870 cache_info=(CacheInfo *) image->cache;
1871 assert(cache_info->signature == MagickSignature);
1872 assert(id < (int) cache_info->number_threads);
1873 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1874 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1875 cache_info->nexus_info[id],exception);
1876 if (p == (const Quantum *) NULL)
1878 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1879 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1880 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1881 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1882 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1883 return(MagickFalse);
1885 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1887 PixelChannel channel=GetPixelChannelChannel(image,i);
1888 pixel[channel]=p[i];
1894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1898 % G e t O n e V i r t u a l P i x e l I n f o %
1902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1905 % location. The image background color is returned if an error occurs. If
1906 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1908 % The format of the GetOneVirtualPixelInfo() method is:
1910 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1911 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1912 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1914 % A description of each parameter follows:
1916 % o image: the image.
1918 % o virtual_pixel_method: the virtual pixel method.
1920 % o x,y: these values define the location of the pixel to return.
1922 % o pixel: return a pixel at the specified (x,y) location.
1924 % o exception: return any errors or warnings in this structure.
1927 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1928 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1929 PixelInfo *pixel,ExceptionInfo *exception)
1932 *restrict cache_info;
1935 id = GetOpenMPThreadId();
1937 register const Quantum
1940 assert(image != (const Image *) NULL);
1941 assert(image->signature == MagickSignature);
1942 assert(image->cache != (Cache) NULL);
1943 cache_info=(CacheInfo *) image->cache;
1944 assert(cache_info->signature == MagickSignature);
1945 assert(id < (int) cache_info->number_threads);
1946 GetPixelInfo(image,pixel);
1947 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1948 cache_info->nexus_info[id],exception);
1949 if (p == (const Quantum *) NULL)
1950 return(MagickFalse);
1951 GetPixelInfoPixel(image,p,pixel);
1956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1960 + G e t P i x e l C a c h e C o l o r s p a c e %
1964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1966 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1968 % The format of the GetPixelCacheColorspace() method is:
1970 % Colorspace GetPixelCacheColorspace(Cache cache)
1972 % A description of each parameter follows:
1974 % o cache: the pixel cache.
1977 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1980 *restrict cache_info;
1982 assert(cache != (Cache) NULL);
1983 cache_info=(CacheInfo *) cache;
1984 assert(cache_info->signature == MagickSignature);
1985 if (cache_info->debug != MagickFalse)
1986 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1987 cache_info->filename);
1988 return(cache_info->colorspace);
1992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1996 + G e t P i x e l C a c h e M e t h o d s %
2000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2002 % GetPixelCacheMethods() initializes the CacheMethods structure.
2004 % The format of the GetPixelCacheMethods() method is:
2006 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2008 % A description of each parameter follows:
2010 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2013 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2015 assert(cache_methods != (CacheMethods *) NULL);
2016 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2017 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2018 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2019 cache_methods->get_virtual_metacontent_from_handler=
2020 GetVirtualMetacontentFromCache;
2021 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2022 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2023 cache_methods->get_authentic_metacontent_from_handler=
2024 GetAuthenticMetacontentFromCache;
2025 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2026 cache_methods->get_one_authentic_pixel_from_handler=
2027 GetOneAuthenticPixelFromCache;
2028 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2029 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2030 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2038 + G e t P i x e l C a c h e N e x u s E x t e n t %
2042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2044 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2045 % corresponding with the last call to SetPixelCacheNexusPixels() or
2046 % GetPixelCacheNexusPixels().
2048 % The format of the GetPixelCacheNexusExtent() method is:
2050 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2051 % NexusInfo *nexus_info)
2053 % A description of each parameter follows:
2055 % o nexus_info: the nexus info.
2058 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2059 NexusInfo *restrict nexus_info)
2062 *restrict cache_info;
2067 assert(cache != NULL);
2068 cache_info=(CacheInfo *) cache;
2069 assert(cache_info->signature == MagickSignature);
2070 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2072 return((MagickSizeType) cache_info->columns*cache_info->rows);
2077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2081 + G e t P i x e l C a c h e P i x e l s %
2085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2087 % GetPixelCachePixels() returns the pixels associated with the specified image.
2089 % The format of the GetPixelCachePixels() method is:
2091 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2092 % ExceptionInfo *exception)
2094 % A description of each parameter follows:
2096 % o image: the image.
2098 % o length: the pixel cache length.
2100 % o exception: return any errors or warnings in this structure.
2103 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2104 ExceptionInfo *exception)
2107 *restrict cache_info;
2109 assert(image != (const Image *) NULL);
2110 assert(image->signature == MagickSignature);
2111 assert(image->cache != (Cache) NULL);
2112 assert(length != (MagickSizeType *) NULL);
2113 assert(exception != (ExceptionInfo *) NULL);
2114 assert(exception->signature == MagickSignature);
2115 cache_info=(CacheInfo *) image->cache;
2116 assert(cache_info->signature == MagickSignature);
2118 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2119 return((void *) NULL);
2120 *length=cache_info->length;
2121 return((void *) cache_info->pixels);
2125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2129 + 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 %
2133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2135 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2137 % The format of the GetPixelCacheStorageClass() method is:
2139 % ClassType GetPixelCacheStorageClass(Cache cache)
2141 % A description of each parameter follows:
2143 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2145 % o cache: the pixel cache.
2148 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2151 *restrict cache_info;
2153 assert(cache != (Cache) NULL);
2154 cache_info=(CacheInfo *) cache;
2155 assert(cache_info->signature == MagickSignature);
2156 if (cache_info->debug != MagickFalse)
2157 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2158 cache_info->filename);
2159 return(cache_info->storage_class);
2163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167 + G e t P i x e l C a c h e T i l e S i z e %
2171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2173 % GetPixelCacheTileSize() returns the pixel cache tile size.
2175 % The format of the GetPixelCacheTileSize() method is:
2177 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2180 % A description of each parameter follows:
2182 % o image: the image.
2184 % o width: the optimize cache tile width in pixels.
2186 % o height: the optimize cache tile height in pixels.
2189 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2193 *restrict cache_info;
2195 assert(image != (Image *) NULL);
2196 assert(image->signature == MagickSignature);
2197 if (image->debug != MagickFalse)
2198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2199 cache_info=(CacheInfo *) image->cache;
2200 assert(cache_info->signature == MagickSignature);
2201 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2202 if (GetImagePixelCacheType(image) == DiskCache)
2203 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212 + 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 %
2216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2218 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2219 % pixel cache. A virtual pixel is any pixel access that is outside the
2220 % boundaries of the image cache.
2222 % The format of the GetPixelCacheVirtualMethod() method is:
2224 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2226 % A description of each parameter follows:
2228 % o image: the image.
2231 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2234 *restrict cache_info;
2236 assert(image != (Image *) NULL);
2237 assert(image->signature == MagickSignature);
2238 assert(image->cache != (Cache) NULL);
2239 cache_info=(CacheInfo *) image->cache;
2240 assert(cache_info->signature == MagickSignature);
2241 return(cache_info->virtual_pixel_method);
2245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249 + 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 %
2253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2255 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2256 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2258 % The format of the GetVirtualMetacontentFromCache() method is:
2260 % void *GetVirtualMetacontentFromCache(const Image *image)
2262 % A description of each parameter follows:
2264 % o image: the image.
2267 static const void *GetVirtualMetacontentFromCache(const Image *image)
2270 *restrict cache_info;
2273 id = GetOpenMPThreadId();
2276 *restrict metacontent;
2278 assert(image != (const Image *) NULL);
2279 assert(image->signature == MagickSignature);
2280 assert(image->cache != (Cache) NULL);
2281 cache_info=(CacheInfo *) image->cache;
2282 assert(cache_info->signature == MagickSignature);
2283 assert(id < (int) cache_info->number_threads);
2284 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2285 cache_info->nexus_info[id]);
2286 return(metacontent);
2290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2294 + 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 %
2298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2300 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2303 % The format of the GetVirtualMetacontentFromNexus() method is:
2305 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2306 % NexusInfo *nexus_info)
2308 % A description of each parameter follows:
2310 % o cache: the pixel cache.
2312 % o nexus_info: the cache nexus to return the meta-content.
2315 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2316 NexusInfo *restrict nexus_info)
2319 *restrict cache_info;
2321 assert(cache != (Cache) NULL);
2322 cache_info=(CacheInfo *) cache;
2323 assert(cache_info->signature == MagickSignature);
2324 if (cache_info->storage_class == UndefinedClass)
2325 return((void *) NULL);
2326 return(nexus_info->metacontent);
2330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2334 % G e t V i r t u a l M e t a c o n t e n t %
2338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2340 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2341 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2342 % returned if the meta-content are not available.
2344 % The format of the GetVirtualMetacontent() method is:
2346 % const void *GetVirtualMetacontent(const Image *image)
2348 % A description of each parameter follows:
2350 % o image: the image.
2353 MagickExport const void *GetVirtualMetacontent(const Image *image)
2356 *restrict cache_info;
2359 id = GetOpenMPThreadId();
2362 *restrict metacontent;
2364 assert(image != (const Image *) NULL);
2365 assert(image->signature == MagickSignature);
2366 assert(image->cache != (Cache) NULL);
2367 cache_info=(CacheInfo *) image->cache;
2368 assert(cache_info->signature == MagickSignature);
2369 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2370 if (metacontent != (void *) NULL)
2371 return(metacontent);
2372 assert(id < (int) cache_info->number_threads);
2373 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2374 cache_info->nexus_info[id]);
2375 return(metacontent);
2379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2383 + 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 %
2387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2389 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2390 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2391 % is returned if the pixels are transferred, otherwise a NULL is returned.
2393 % The format of the GetVirtualPixelsFromNexus() method is:
2395 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2396 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2397 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2398 % ExceptionInfo *exception)
2400 % A description of each parameter follows:
2402 % o image: the image.
2404 % o virtual_pixel_method: the virtual pixel method.
2406 % o x,y,columns,rows: These values define the perimeter of a region of
2409 % o nexus_info: the cache nexus to acquire.
2411 % o exception: return any errors or warnings in this structure.
2418 0, 48, 12, 60, 3, 51, 15, 63,
2419 32, 16, 44, 28, 35, 19, 47, 31,
2420 8, 56, 4, 52, 11, 59, 7, 55,
2421 40, 24, 36, 20, 43, 27, 39, 23,
2422 2, 50, 14, 62, 1, 49, 13, 61,
2423 34, 18, 46, 30, 33, 17, 45, 29,
2424 10, 58, 6, 54, 9, 57, 5, 53,
2425 42, 26, 38, 22, 41, 25, 37, 21
2428 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2433 index=x+DitherMatrix[x & 0x07]-32L;
2436 if (index >= (ssize_t) columns)
2437 return((ssize_t) columns-1L);
2441 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2446 index=y+DitherMatrix[y & 0x07]-32L;
2449 if (index >= (ssize_t) rows)
2450 return((ssize_t) rows-1L);
2454 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2458 if (x >= (ssize_t) columns)
2459 return((ssize_t) (columns-1));
2463 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2467 if (y >= (ssize_t) rows)
2468 return((ssize_t) (rows-1));
2472 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2474 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2477 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2479 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2482 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2483 const size_t extent)
2489 Compute the remainder of dividing offset by extent. It returns not only
2490 the quotient (tile the offset falls in) but also the positive remainer
2491 within that tile such that 0 <= remainder < extent. This method is
2492 essentially a ldiv() using a floored modulo division rather than the
2493 normal default truncated modulo division.
2495 modulo.quotient=offset/(ssize_t) extent;
2498 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2502 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2503 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2504 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2505 ExceptionInfo *exception)
2508 *restrict cache_info;
2518 **restrict virtual_nexus;
2522 virtual_pixel[MaxPixelChannels];
2527 register const Quantum
2540 register unsigned char
2547 *restrict virtual_metacontent;
2552 assert(image != (const Image *) NULL);
2553 assert(image->signature == MagickSignature);
2554 assert(image->cache != (Cache) NULL);
2555 cache_info=(CacheInfo *) image->cache;
2556 assert(cache_info->signature == MagickSignature);
2557 if (cache_info->type == UndefinedCache)
2558 return((const Quantum *) NULL);
2561 region.width=columns;
2563 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2565 if (pixels == (Quantum *) NULL)
2566 return((const Quantum *) NULL);
2568 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2569 nexus_info->region.x;
2570 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2571 nexus_info->region.width-1L;
2572 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2573 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2574 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2575 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2581 Pixel request is inside cache extents.
2583 if (nexus_info->authentic_pixel_cache != MagickFalse)
2585 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2586 if (status == MagickFalse)
2587 return((const Quantum *) NULL);
2588 if (cache_info->metacontent_extent != 0)
2590 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2591 if (status == MagickFalse)
2592 return((const Quantum *) NULL);
2597 Pixel request is outside cache extents.
2599 s=(unsigned char *) nexus_info->metacontent;
2600 virtual_nexus=AcquirePixelCacheNexus(1);
2601 if (virtual_nexus == (NexusInfo **) NULL)
2603 if (virtual_nexus != (NexusInfo **) NULL)
2604 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2605 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2606 "UnableToGetCacheNexus","`%s'",image->filename);
2607 return((const Quantum *) NULL);
2609 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2610 sizeof(*virtual_pixel));
2611 virtual_metacontent=(void *) NULL;
2612 switch (virtual_pixel_method)
2614 case BackgroundVirtualPixelMethod:
2615 case BlackVirtualPixelMethod:
2616 case GrayVirtualPixelMethod:
2617 case TransparentVirtualPixelMethod:
2618 case MaskVirtualPixelMethod:
2619 case WhiteVirtualPixelMethod:
2620 case EdgeVirtualPixelMethod:
2621 case CheckerTileVirtualPixelMethod:
2622 case HorizontalTileVirtualPixelMethod:
2623 case VerticalTileVirtualPixelMethod:
2625 if (cache_info->metacontent_extent != 0)
2628 Acquire a metacontent buffer.
2630 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2631 cache_info->metacontent_extent);
2632 if (virtual_metacontent == (void *) NULL)
2634 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2635 (void) ThrowMagickException(exception,GetMagickModule(),
2636 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2637 return((const Quantum *) NULL);
2639 (void) ResetMagickMemory(virtual_metacontent,0,
2640 cache_info->metacontent_extent);
2642 switch (virtual_pixel_method)
2644 case BlackVirtualPixelMethod:
2646 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2647 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2648 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2651 case GrayVirtualPixelMethod:
2653 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2654 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2656 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2659 case TransparentVirtualPixelMethod:
2661 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2662 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2663 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2666 case MaskVirtualPixelMethod:
2667 case WhiteVirtualPixelMethod:
2669 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2670 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2671 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2676 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2678 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2680 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2682 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2684 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2694 for (v=0; v < (ssize_t) rows; v++)
2700 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2701 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2702 y_offset=EdgeY(y_offset,cache_info->rows);
2703 for (u=0; u < (ssize_t) columns; u+=length)
2709 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2710 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2711 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2719 Transfer a single pixel.
2721 length=(MagickSizeType) 1;
2722 switch (virtual_pixel_method)
2724 case EdgeVirtualPixelMethod:
2727 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2728 EdgeX(x_offset,cache_info->columns),
2729 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2731 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2734 case RandomVirtualPixelMethod:
2736 if (cache_info->random_info == (RandomInfo *) NULL)
2737 cache_info->random_info=AcquireRandomInfo();
2738 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2739 RandomX(cache_info->random_info,cache_info->columns),
2740 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2741 *virtual_nexus,exception);
2742 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2745 case DitherVirtualPixelMethod:
2747 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2748 DitherX(x_offset,cache_info->columns),
2749 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2751 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2754 case TileVirtualPixelMethod:
2756 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2757 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2758 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2759 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2761 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2764 case MirrorVirtualPixelMethod:
2766 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2767 if ((x_modulo.quotient & 0x01) == 1L)
2768 x_modulo.remainder=(ssize_t) cache_info->columns-
2769 x_modulo.remainder-1L;
2770 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2771 if ((y_modulo.quotient & 0x01) == 1L)
2772 y_modulo.remainder=(ssize_t) cache_info->rows-
2773 y_modulo.remainder-1L;
2774 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2775 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2777 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2780 case HorizontalTileEdgeVirtualPixelMethod:
2782 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2783 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2784 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2785 *virtual_nexus,exception);
2786 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2789 case VerticalTileEdgeVirtualPixelMethod:
2791 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2792 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2793 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2794 *virtual_nexus,exception);
2795 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2798 case BackgroundVirtualPixelMethod:
2799 case BlackVirtualPixelMethod:
2800 case GrayVirtualPixelMethod:
2801 case TransparentVirtualPixelMethod:
2802 case MaskVirtualPixelMethod:
2803 case WhiteVirtualPixelMethod:
2806 r=virtual_metacontent;
2809 case CheckerTileVirtualPixelMethod:
2811 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2812 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2813 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2816 r=virtual_metacontent;
2819 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2820 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2822 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2825 case HorizontalTileVirtualPixelMethod:
2827 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2830 r=virtual_metacontent;
2833 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2834 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2835 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2836 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2838 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2841 case VerticalTileVirtualPixelMethod:
2843 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2846 r=virtual_metacontent;
2849 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2850 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2851 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2852 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2854 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2858 if (p == (const Quantum *) NULL)
2860 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2862 q+=cache_info->number_channels;
2863 if ((s != (void *) NULL) && (r != (const void *) NULL))
2865 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2866 s+=cache_info->metacontent_extent;
2871 Transfer a run of pixels.
2873 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2874 (size_t) length,1UL,*virtual_nexus,exception);
2875 if (p == (const Quantum *) NULL)
2877 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2878 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2879 q+=length*cache_info->number_channels;
2880 if ((r != (void *) NULL) && (s != (const void *) NULL))
2882 (void) memcpy(s,r,(size_t) length);
2883 s+=length*cache_info->metacontent_extent;
2890 if (virtual_metacontent != (void *) NULL)
2891 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2892 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2901 + G e t V i r t u a l P i x e l C a c h e %
2905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2907 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2908 % cache as defined by the geometry parameters. A pointer to the pixels
2909 % is returned if the pixels are transferred, otherwise a NULL is returned.
2911 % The format of the GetVirtualPixelCache() method is:
2913 % const Quantum *GetVirtualPixelCache(const Image *image,
2914 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2915 % const ssize_t y,const size_t columns,const size_t rows,
2916 % ExceptionInfo *exception)
2918 % A description of each parameter follows:
2920 % o image: the image.
2922 % o virtual_pixel_method: the virtual pixel method.
2924 % o x,y,columns,rows: These values define the perimeter of a region of
2927 % o exception: return any errors or warnings in this structure.
2930 static const Quantum *GetVirtualPixelCache(const Image *image,
2931 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2932 const size_t columns,const size_t rows,ExceptionInfo *exception)
2935 *restrict cache_info;
2938 id = GetOpenMPThreadId();
2943 assert(image != (const Image *) NULL);
2944 assert(image->signature == MagickSignature);
2945 assert(image->cache != (Cache) NULL);
2946 cache_info=(CacheInfo *) image->cache;
2947 assert(cache_info->signature == MagickSignature);
2948 assert(id < (int) cache_info->number_threads);
2949 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2950 cache_info->nexus_info[id],exception);
2955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2959 % G e t V i r t u a l P i x e l Q u e u e %
2963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2966 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2968 % The format of the GetVirtualPixelQueue() method is:
2970 % const Quantum *GetVirtualPixelQueue(const Image image)
2972 % A description of each parameter follows:
2974 % o image: the image.
2977 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2980 *restrict cache_info;
2983 id = GetOpenMPThreadId();
2985 assert(image != (const Image *) NULL);
2986 assert(image->signature == MagickSignature);
2987 assert(image->cache != (Cache) NULL);
2988 cache_info=(CacheInfo *) image->cache;
2989 assert(cache_info->signature == MagickSignature);
2990 if (cache_info->methods.get_virtual_pixels_handler !=
2991 (GetVirtualPixelsHandler) NULL)
2992 return(cache_info->methods.get_virtual_pixels_handler(image));
2993 assert(id < (int) cache_info->number_threads);
2994 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3002 % G e t V i r t u a l P i x e l s %
3006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3008 % GetVirtualPixels() returns an immutable pixel region. If the
3009 % region is successfully accessed, a pointer to it is returned, otherwise
3010 % NULL is returned. The returned pointer may point to a temporary working
3011 % copy of the pixels or it may point to the original pixels in memory.
3012 % Performance is maximized if the selected region is part of one row, or one
3013 % or more full rows, since there is opportunity to access the pixels in-place
3014 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3015 % returned pointer must *never* be deallocated by the user.
3017 % Pixels accessed via the returned pointer represent a simple array of type
3018 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3019 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3020 % access the meta-content (of type void) corresponding to the the
3023 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3025 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3026 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3027 % GetCacheViewAuthenticPixels() instead.
3029 % The format of the GetVirtualPixels() method is:
3031 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3032 % const ssize_t y,const size_t columns,const size_t rows,
3033 % ExceptionInfo *exception)
3035 % A description of each parameter follows:
3037 % o image: the image.
3039 % o x,y,columns,rows: These values define the perimeter of a region of
3042 % o exception: return any errors or warnings in this structure.
3045 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3046 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3047 ExceptionInfo *exception)
3050 *restrict cache_info;
3053 id = GetOpenMPThreadId();
3058 assert(image != (const Image *) NULL);
3059 assert(image->signature == MagickSignature);
3060 assert(image->cache != (Cache) NULL);
3061 cache_info=(CacheInfo *) image->cache;
3062 assert(cache_info->signature == MagickSignature);
3063 if (cache_info->methods.get_virtual_pixel_handler !=
3064 (GetVirtualPixelHandler) NULL)
3065 return(cache_info->methods.get_virtual_pixel_handler(image,
3066 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3067 assert(id < (int) cache_info->number_threads);
3068 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3069 columns,rows,cache_info->nexus_info[id],exception);
3074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3078 + 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 %
3082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3084 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3085 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3087 % The format of the GetVirtualPixelsCache() method is:
3089 % Quantum *GetVirtualPixelsCache(const Image *image)
3091 % A description of each parameter follows:
3093 % o image: the image.
3096 static const Quantum *GetVirtualPixelsCache(const Image *image)
3099 *restrict cache_info;
3102 id = GetOpenMPThreadId();
3104 assert(image != (const Image *) NULL);
3105 assert(image->signature == MagickSignature);
3106 assert(image->cache != (Cache) NULL);
3107 cache_info=(CacheInfo *) image->cache;
3108 assert(cache_info->signature == MagickSignature);
3109 assert(id < (int) cache_info->number_threads);
3110 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3118 + G e t V i r t u a l P i x e l s N e x u s %
3122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3124 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3127 % The format of the GetVirtualPixelsNexus() method is:
3129 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3130 % NexusInfo *nexus_info)
3132 % A description of each parameter follows:
3134 % o cache: the pixel cache.
3136 % o nexus_info: the cache nexus to return the colormap pixels.
3139 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3140 NexusInfo *restrict nexus_info)
3143 *restrict cache_info;
3145 assert(cache != (Cache) NULL);
3146 cache_info=(CacheInfo *) cache;
3147 assert(cache_info->signature == MagickSignature);
3148 if (cache_info->storage_class == UndefinedClass)
3149 return((Quantum *) NULL);
3150 return((const Quantum *) nexus_info->pixels);
3154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3158 + O p e n P i x e l C a c h e %
3162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3164 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3165 % dimensions, allocating space for the image pixels and optionally the
3166 % metacontent, and memory mapping the cache if it is disk based. The cache
3167 % nexus array is initialized as well.
3169 % The format of the OpenPixelCache() method is:
3171 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3172 % ExceptionInfo *exception)
3174 % A description of each parameter follows:
3176 % o image: the image.
3178 % o mode: ReadMode, WriteMode, or IOMode.
3180 % o exception: return any errors or warnings in this structure.
3184 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3186 cache_info->mapped=MagickFalse;
3187 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3188 (size_t) cache_info->length));
3189 if (cache_info->pixels == (Quantum *) NULL)
3191 cache_info->mapped=MagickTrue;
3192 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3193 cache_info->length);
3197 #if defined(__cplusplus) || defined(c_plusplus)
3202 static void CacheSignalHandler(int status)
3204 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3208 #if defined(__cplusplus) || defined(c_plusplus)
3212 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3219 Open pixel cache on disk.
3221 if (cache_info->file != -1)
3222 return(MagickTrue); /* cache already open */
3223 if (*cache_info->cache_filename == '\0')
3224 file=AcquireUniqueFileResource(cache_info->cache_filename);
3230 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3235 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3236 O_BINARY | O_EXCL,S_MODE);
3238 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3244 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3247 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3252 return(MagickFalse);
3253 (void) AcquireMagickResource(FileResource,1);
3254 cache_info->file=file;
3255 cache_info->mode=mode;
3259 static inline MagickOffsetType WritePixelCacheRegion(
3260 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3261 const MagickSizeType length,const unsigned char *restrict buffer)
3263 register MagickOffsetType
3269 #if !defined(MAGICKCORE_HAVE_PWRITE)
3270 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3271 return((MagickOffsetType) -1);
3274 for (i=0; i < (MagickOffsetType) length; i+=count)
3276 #if !defined(MAGICKCORE_HAVE_PWRITE)
3277 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3278 (MagickSizeType) SSIZE_MAX));
3280 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3281 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3293 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3296 *restrict cache_info;
3303 cache_info=(CacheInfo *) image->cache;
3304 if (image->debug != MagickFalse)
3307 format[MaxTextExtent],
3308 message[MaxTextExtent];
3310 (void) FormatMagickSize(length,MagickFalse,format);
3311 (void) FormatLocaleString(message,MaxTextExtent,
3312 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3313 cache_info->cache_filename,cache_info->file,format);
3314 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3316 if (length != (MagickSizeType) ((MagickOffsetType) length))
3317 return(MagickFalse);
3318 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3320 return(MagickFalse);
3321 if ((MagickSizeType) offset >= length)
3323 extent=(MagickOffsetType) length-1;
3324 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3325 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3326 if (cache_info->synchronize != MagickFalse)
3331 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3333 return(MagickFalse);
3337 (void) signal(SIGBUS,CacheSignalHandler);
3339 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3342 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3343 ExceptionInfo *exception)
3346 *restrict cache_info,
3350 format[MaxTextExtent],
3351 message[MaxTextExtent];
3367 assert(image != (const Image *) NULL);
3368 assert(image->signature == MagickSignature);
3369 assert(image->cache != (Cache) NULL);
3370 if (image->debug != MagickFalse)
3371 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3372 if ((image->columns == 0) || (image->rows == 0))
3373 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3374 cache_info=(CacheInfo *) image->cache;
3375 assert(cache_info->signature == MagickSignature);
3376 source_info=(*cache_info);
3377 source_info.file=(-1);
3378 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3379 image->filename,(double) GetImageIndexInList(image));
3380 cache_info->storage_class=image->storage_class;
3381 cache_info->colorspace=image->colorspace;
3382 cache_info->alpha_trait=image->alpha_trait;
3383 cache_info->read_mask=image->read_mask;
3384 cache_info->write_mask=image->write_mask;
3385 cache_info->rows=image->rows;
3386 cache_info->columns=image->columns;
3387 InitializePixelChannelMap(image);
3388 cache_info->number_channels=GetPixelChannels(image);
3389 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3390 sizeof(*image->channel_map));
3391 cache_info->metacontent_extent=image->metacontent_extent;
3392 cache_info->mode=mode;
3393 if (image->ping != MagickFalse)
3395 cache_info->type=PingCache;
3396 cache_info->pixels=(Quantum *) NULL;
3397 cache_info->metacontent=(void *) NULL;
3398 cache_info->length=0;
3401 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3402 packet_size=cache_info->number_channels*sizeof(Quantum);
3403 if (image->metacontent_extent != 0)
3404 packet_size+=cache_info->metacontent_extent;
3405 length=number_pixels*packet_size;
3406 columns=(size_t) (length/cache_info->rows/packet_size);
3407 if (cache_info->columns != columns)
3408 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3410 cache_info->length=length;
3411 status=AcquireMagickResource(AreaResource,cache_info->length);
3412 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3413 cache_info->metacontent_extent);
3414 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3416 status=AcquireMagickResource(MemoryResource,cache_info->length);
3417 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3418 (cache_info->type == MemoryCache))
3420 AllocatePixelCachePixels(cache_info);
3421 if (cache_info->pixels == (Quantum *) NULL)
3422 cache_info->pixels=source_info.pixels;
3426 Create memory pixel cache.
3429 cache_info->type=MemoryCache;
3430 cache_info->metacontent=(void *) NULL;
3431 if (cache_info->metacontent_extent != 0)
3432 cache_info->metacontent=(void *) (cache_info->pixels+
3433 number_pixels*cache_info->number_channels);
3434 if ((source_info.storage_class != UndefinedClass) &&
3437 status=ClonePixelCacheRepository(cache_info,&source_info,
3439 RelinquishPixelCachePixels(&source_info);
3441 if (image->debug != MagickFalse)
3443 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3444 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3446 (void) FormatLocaleString(message,MaxTextExtent,
3447 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3448 cache_info->filename,cache_info->mapped != MagickFalse ?
3449 "Anonymous" : "Heap",type,(double) cache_info->columns,
3450 (double) cache_info->rows,(double)
3451 cache_info->number_channels,format);
3452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3458 RelinquishMagickResource(MemoryResource,cache_info->length);
3461 Create pixel cache on disk.
3463 status=AcquireMagickResource(DiskResource,cache_info->length);
3464 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3469 if (cache_info->type == DistributedCache)
3470 RelinquishMagickResource(DiskResource,cache_info->length);
3471 server_info=AcquireDistributeCacheInfo(exception);
3472 if (server_info != (DistributeCacheInfo *) NULL)
3474 status=OpenDistributePixelCache(server_info,image);
3475 if (status == MagickFalse)
3477 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3478 GetDistributeCacheHostname(server_info));
3479 server_info=DestroyDistributeCacheInfo(server_info);
3484 Create a distributed pixel cache.
3486 cache_info->type=DistributedCache;
3487 cache_info->server_info=server_info;
3488 (void) FormatLocaleString(cache_info->cache_filename,
3489 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3490 (DistributeCacheInfo *) cache_info->server_info),
3491 GetDistributeCachePort((DistributeCacheInfo *)
3492 cache_info->server_info));
3493 if ((source_info.storage_class != UndefinedClass) &&
3496 status=ClonePixelCacheRepository(cache_info,&source_info,
3498 RelinquishPixelCachePixels(&source_info);
3500 if (image->debug != MagickFalse)
3502 (void) FormatMagickSize(cache_info->length,MagickFalse,
3504 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3506 (void) FormatLocaleString(message,MaxTextExtent,
3507 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3508 cache_info->filename,cache_info->cache_filename,
3509 GetDistributeCacheFile((DistributeCacheInfo *)
3510 cache_info->server_info),type,(double) cache_info->columns,
3511 (double) cache_info->rows,(double)
3512 cache_info->number_channels,format);
3513 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3519 RelinquishMagickResource(DiskResource,cache_info->length);
3520 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3521 "CacheResourcesExhausted","`%s'",image->filename);
3522 return(MagickFalse);
3524 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3526 (void) ClosePixelCacheOnDisk(cache_info);
3527 *cache_info->cache_filename='\0';
3529 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3531 RelinquishMagickResource(DiskResource,cache_info->length);
3532 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3534 return(MagickFalse);
3536 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3537 cache_info->length);
3538 if (status == MagickFalse)
3540 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3542 return(MagickFalse);
3544 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3545 cache_info->metacontent_extent);
3546 if (length != (MagickSizeType) ((size_t) length))
3547 cache_info->type=DiskCache;
3550 status=AcquireMagickResource(MapResource,cache_info->length);
3551 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3552 (cache_info->type != MemoryCache))
3553 cache_info->type=DiskCache;
3556 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3557 cache_info->offset,(size_t) cache_info->length);
3558 if (cache_info->pixels == (Quantum *) NULL)
3560 cache_info->type=DiskCache;
3561 cache_info->pixels=source_info.pixels;
3566 Create file-backed memory-mapped pixel cache.
3569 (void) ClosePixelCacheOnDisk(cache_info);
3570 cache_info->type=MapCache;
3571 cache_info->mapped=MagickTrue;
3572 cache_info->metacontent=(void *) NULL;
3573 if (cache_info->metacontent_extent != 0)
3574 cache_info->metacontent=(void *) (cache_info->pixels+
3575 number_pixels*cache_info->number_channels);
3576 if ((source_info.storage_class != UndefinedClass) &&
3579 status=ClonePixelCacheRepository(cache_info,&source_info,
3581 RelinquishPixelCachePixels(&source_info);
3583 if (image->debug != MagickFalse)
3585 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3586 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3588 (void) FormatLocaleString(message,MaxTextExtent,
3589 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3590 cache_info->filename,cache_info->cache_filename,
3591 cache_info->file,type,(double) cache_info->columns,(double)
3592 cache_info->rows,(double) cache_info->number_channels,
3594 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3600 RelinquishMagickResource(MapResource,cache_info->length);
3603 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3605 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3606 RelinquishPixelCachePixels(&source_info);
3608 if (image->debug != MagickFalse)
3610 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3611 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3613 (void) FormatLocaleString(message,MaxTextExtent,
3614 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3615 cache_info->cache_filename,cache_info->file,type,(double)
3616 cache_info->columns,(double) cache_info->rows,(double)
3617 cache_info->number_channels,format);
3618 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3628 + P e r s i s t P i x e l C a c h e %
3632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3634 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3635 % persistent pixel cache is one that resides on disk and is not destroyed
3636 % when the program exits.
3638 % The format of the PersistPixelCache() method is:
3640 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3641 % const MagickBooleanType attach,MagickOffsetType *offset,
3642 % ExceptionInfo *exception)
3644 % A description of each parameter follows:
3646 % o image: the image.
3648 % o filename: the persistent pixel cache filename.
3650 % o attach: A value other than zero initializes the persistent pixel cache.
3652 % o initialize: A value other than zero initializes the persistent pixel
3655 % o offset: the offset in the persistent cache to store pixels.
3657 % o exception: return any errors or warnings in this structure.
3660 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3661 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3662 ExceptionInfo *exception)
3665 *restrict cache_info,
3666 *restrict clone_info;
3677 assert(image != (Image *) NULL);
3678 assert(image->signature == MagickSignature);
3679 if (image->debug != MagickFalse)
3680 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3681 assert(image->cache != (void *) NULL);
3682 assert(filename != (const char *) NULL);
3683 assert(offset != (MagickOffsetType *) NULL);
3684 page_size=GetMagickPageSize();
3685 cache_info=(CacheInfo *) image->cache;
3686 assert(cache_info->signature == MagickSignature);
3687 if (attach != MagickFalse)
3690 Attach existing persistent pixel cache.
3692 if (image->debug != MagickFalse)
3693 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3694 "attach persistent cache");
3695 (void) CopyMagickString(cache_info->cache_filename,filename,
3697 cache_info->type=DiskCache;
3698 cache_info->offset=(*offset);
3699 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3700 return(MagickFalse);
3701 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3704 if ((cache_info->mode != ReadMode) &&
3705 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3706 (cache_info->reference_count == 1))
3708 LockSemaphoreInfo(cache_info->semaphore);
3709 if ((cache_info->mode != ReadMode) &&
3710 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3711 (cache_info->reference_count == 1))
3717 Usurp existing persistent pixel cache.
3719 status=rename_utf8(cache_info->cache_filename,filename);
3722 (void) CopyMagickString(cache_info->cache_filename,filename,
3724 *offset+=cache_info->length+page_size-(cache_info->length %
3726 UnlockSemaphoreInfo(cache_info->semaphore);
3727 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3728 if (image->debug != MagickFalse)
3729 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3730 "Usurp resident persistent cache");
3734 UnlockSemaphoreInfo(cache_info->semaphore);
3737 Clone persistent pixel cache.
3739 clone_image=(*image);
3740 clone_info=(CacheInfo *) clone_image.cache;
3741 image->cache=ClonePixelCache(cache_info);
3742 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3743 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3744 cache_info->type=DiskCache;
3745 cache_info->offset=(*offset);
3746 cache_info=(CacheInfo *) image->cache;
3747 status=OpenPixelCache(image,IOMode,exception);
3748 if (status != MagickFalse)
3749 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3750 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3751 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3760 + 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 %
3764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3766 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3767 % defined by the region rectangle and returns a pointer to the region. This
3768 % region is subsequently transferred from the pixel cache with
3769 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3770 % pixels are transferred, otherwise a NULL is returned.
3772 % The format of the QueueAuthenticPixelCacheNexus() method is:
3774 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3775 % const ssize_t y,const size_t columns,const size_t rows,
3776 % const MagickBooleanType clone,NexusInfo *nexus_info,
3777 % ExceptionInfo *exception)
3779 % A description of each parameter follows:
3781 % o image: the image.
3783 % o x,y,columns,rows: These values define the perimeter of a region of
3786 % o nexus_info: the cache nexus to set.
3788 % o clone: clone the pixel cache.
3790 % o exception: return any errors or warnings in this structure.
3793 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3794 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3795 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3798 *restrict cache_info;
3813 Validate pixel cache geometry.
3815 assert(image != (const Image *) NULL);
3816 assert(image->signature == MagickSignature);
3817 assert(image->cache != (Cache) NULL);
3818 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3819 if (cache_info == (Cache) NULL)
3820 return((Quantum *) NULL);
3821 assert(cache_info->signature == MagickSignature);
3822 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3823 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3824 (y >= (ssize_t) cache_info->rows))
3826 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3827 "PixelsAreNotAuthentic","`%s'",image->filename);
3828 return((Quantum *) NULL);
3830 offset=(MagickOffsetType) y*cache_info->columns+x;
3832 return((Quantum *) NULL);
3833 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3834 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3835 if ((MagickSizeType) offset >= number_pixels)
3836 return((Quantum *) NULL);
3842 region.width=columns;
3844 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3854 + 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 %
3858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3860 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3861 % defined by the region rectangle and returns a pointer to the region. This
3862 % region is subsequently transferred from the pixel cache with
3863 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3864 % pixels are transferred, otherwise a NULL is returned.
3866 % The format of the QueueAuthenticPixelsCache() method is:
3868 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3869 % const ssize_t y,const size_t columns,const size_t rows,
3870 % ExceptionInfo *exception)
3872 % A description of each parameter follows:
3874 % o image: the image.
3876 % o x,y,columns,rows: These values define the perimeter of a region of
3879 % o exception: return any errors or warnings in this structure.
3882 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3883 const ssize_t y,const size_t columns,const size_t rows,
3884 ExceptionInfo *exception)
3887 *restrict cache_info;
3890 id = GetOpenMPThreadId();
3895 assert(image != (const Image *) NULL);
3896 assert(image->signature == MagickSignature);
3897 assert(image->cache != (Cache) NULL);
3898 cache_info=(CacheInfo *) image->cache;
3899 assert(cache_info->signature == MagickSignature);
3900 assert(id < (int) cache_info->number_threads);
3901 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3902 cache_info->nexus_info[id],exception);
3907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3911 % Q u e u e A u t h e n t i c P i x e l s %
3915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3917 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3918 % successfully initialized a pointer to a Quantum array representing the
3919 % region is returned, otherwise NULL is returned. The returned pointer may
3920 % point to a temporary working buffer for the pixels or it may point to the
3921 % final location of the pixels in memory.
3923 % Write-only access means that any existing pixel values corresponding to
3924 % the region are ignored. This is useful if the initial image is being
3925 % created from scratch, or if the existing pixel values are to be
3926 % completely replaced without need to refer to their pre-existing values.
3927 % The application is free to read and write the pixel buffer returned by
3928 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3929 % initialize the pixel array values. Initializing pixel array values is the
3930 % application's responsibility.
3932 % Performance is maximized if the selected region is part of one row, or
3933 % one or more full rows, since then there is opportunity to access the
3934 % pixels in-place (without a copy) if the image is in memory, or in a
3935 % memory-mapped file. The returned pointer must *never* be deallocated
3938 % Pixels accessed via the returned pointer represent a simple array of type
3939 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3940 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3941 % obtain the meta-content (of type void) corresponding to the region.
3942 % Once the Quantum (and/or Quantum) array has been updated, the
3943 % changes must be saved back to the underlying image using
3944 % SyncAuthenticPixels() or they may be lost.
3946 % The format of the QueueAuthenticPixels() method is:
3948 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3949 % const ssize_t y,const size_t columns,const size_t rows,
3950 % ExceptionInfo *exception)
3952 % A description of each parameter follows:
3954 % o image: the image.
3956 % o x,y,columns,rows: These values define the perimeter of a region of
3959 % o exception: return any errors or warnings in this structure.
3962 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3963 const ssize_t y,const size_t columns,const size_t rows,
3964 ExceptionInfo *exception)
3967 *restrict cache_info;
3970 id = GetOpenMPThreadId();
3975 assert(image != (Image *) NULL);
3976 assert(image->signature == MagickSignature);
3977 assert(image->cache != (Cache) NULL);
3978 cache_info=(CacheInfo *) image->cache;
3979 assert(cache_info->signature == MagickSignature);
3980 if (cache_info->methods.queue_authentic_pixels_handler !=
3981 (QueueAuthenticPixelsHandler) NULL)
3983 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3984 columns,rows,exception);
3987 assert(id < (int) cache_info->number_threads);
3988 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3989 cache_info->nexus_info[id],exception);
3994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3998 + 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 %
4002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4004 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4007 % The format of the ReadPixelCacheMetacontent() method is:
4009 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4010 % NexusInfo *nexus_info,ExceptionInfo *exception)
4012 % A description of each parameter follows:
4014 % o cache_info: the pixel cache.
4016 % o nexus_info: the cache nexus to read the metacontent.
4018 % o exception: return any errors or warnings in this structure.
4022 static inline MagickOffsetType ReadPixelCacheRegion(
4023 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4024 const MagickSizeType length,unsigned char *restrict buffer)
4026 register MagickOffsetType
4032 #if !defined(MAGICKCORE_HAVE_PREAD)
4033 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4034 return((MagickOffsetType) -1);
4037 for (i=0; i < (MagickOffsetType) length; i+=count)
4039 #if !defined(MAGICKCORE_HAVE_PREAD)
4040 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4041 (MagickSizeType) SSIZE_MAX));
4043 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4044 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4056 static MagickBooleanType ReadPixelCacheMetacontent(
4057 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4058 ExceptionInfo *exception)
4071 register unsigned char
4077 if (cache_info->metacontent_extent == 0)
4078 return(MagickFalse);
4079 if (nexus_info->authentic_pixel_cache != MagickFalse)
4081 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4082 nexus_info->region.x;
4083 length=(MagickSizeType) nexus_info->region.width*
4084 cache_info->metacontent_extent;
4085 extent=length*nexus_info->region.height;
4086 rows=nexus_info->region.height;
4088 q=(unsigned char *) nexus_info->metacontent;
4089 switch (cache_info->type)
4094 register unsigned char
4098 Read meta-content from memory.
4100 if ((cache_info->columns == nexus_info->region.width) &&
4101 (extent == (MagickSizeType) ((size_t) extent)))
4106 p=(unsigned char *) cache_info->metacontent+offset*
4107 cache_info->metacontent_extent;
4108 for (y=0; y < (ssize_t) rows; y++)
4110 (void) memcpy(q,p,(size_t) length);
4111 p+=cache_info->metacontent_extent*cache_info->columns;
4112 q+=cache_info->metacontent_extent*nexus_info->region.width;
4119 Read meta content from disk.
4121 LockSemaphoreInfo(cache_info->file_semaphore);
4122 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4124 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4125 cache_info->cache_filename);
4126 UnlockSemaphoreInfo(cache_info->file_semaphore);
4127 return(MagickFalse);
4129 if ((cache_info->columns == nexus_info->region.width) &&
4130 (extent <= MagickMaxBufferExtent))
4135 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4136 for (y=0; y < (ssize_t) rows; y++)
4138 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4139 cache_info->number_channels*sizeof(Quantum)+offset*
4140 cache_info->metacontent_extent,length,(unsigned char *) q);
4141 if (count != (MagickOffsetType) length)
4143 offset+=cache_info->columns;
4144 q+=cache_info->metacontent_extent*nexus_info->region.width;
4146 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4147 (void) ClosePixelCacheOnDisk(cache_info);
4148 UnlockSemaphoreInfo(cache_info->file_semaphore);
4151 case DistributedCache:
4157 Read metacontent from distributed cache.
4159 LockSemaphoreInfo(cache_info->file_semaphore);
4160 region=nexus_info->region;
4161 if ((cache_info->columns != nexus_info->region.width) ||
4162 (extent > MagickMaxBufferExtent))
4169 for (y=0; y < (ssize_t) rows; y++)
4171 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4172 cache_info->server_info,®ion,length,(unsigned char *) q);
4173 if (count != (MagickOffsetType) length)
4175 q+=cache_info->metacontent_extent*nexus_info->region.width;
4178 UnlockSemaphoreInfo(cache_info->file_semaphore);
4184 if (y < (ssize_t) rows)
4186 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4187 cache_info->cache_filename);
4188 return(MagickFalse);
4190 if ((cache_info->debug != MagickFalse) &&
4191 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4192 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4193 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4194 nexus_info->region.width,(double) nexus_info->region.height,(double)
4195 nexus_info->region.x,(double) nexus_info->region.y);
4200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4204 + R e a d P i x e l C a c h e P i x e l s %
4208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4210 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4213 % The format of the ReadPixelCachePixels() method is:
4215 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4216 % NexusInfo *nexus_info,ExceptionInfo *exception)
4218 % A description of each parameter follows:
4220 % o cache_info: the pixel cache.
4222 % o nexus_info: the cache nexus to read the pixels.
4224 % o exception: return any errors or warnings in this structure.
4227 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4228 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4247 if (nexus_info->authentic_pixel_cache != MagickFalse)
4249 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4250 nexus_info->region.x;
4251 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4253 extent=length*nexus_info->region.height;
4254 rows=nexus_info->region.height;
4256 q=nexus_info->pixels;
4257 switch (cache_info->type)
4266 Read pixels from memory.
4268 if ((cache_info->columns == nexus_info->region.width) &&
4269 (extent == (MagickSizeType) ((size_t) extent)))
4274 p=cache_info->pixels+offset*cache_info->number_channels;
4275 for (y=0; y < (ssize_t) rows; y++)
4277 (void) memcpy(q,p,(size_t) length);
4278 p+=cache_info->number_channels*cache_info->columns;
4279 q+=cache_info->number_channels*nexus_info->region.width;
4286 Read pixels from disk.
4288 LockSemaphoreInfo(cache_info->file_semaphore);
4289 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4291 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4292 cache_info->cache_filename);
4293 UnlockSemaphoreInfo(cache_info->file_semaphore);
4294 return(MagickFalse);
4296 if ((cache_info->columns == nexus_info->region.width) &&
4297 (extent <= MagickMaxBufferExtent))
4302 for (y=0; y < (ssize_t) rows; y++)
4304 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4305 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4306 if (count != (MagickOffsetType) length)
4308 offset+=cache_info->columns;
4309 q+=cache_info->number_channels*nexus_info->region.width;
4311 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4312 (void) ClosePixelCacheOnDisk(cache_info);
4313 UnlockSemaphoreInfo(cache_info->file_semaphore);
4316 case DistributedCache:
4322 Read pixels from distributed cache.
4324 LockSemaphoreInfo(cache_info->file_semaphore);
4325 region=nexus_info->region;
4326 if ((cache_info->columns != nexus_info->region.width) ||
4327 (extent > MagickMaxBufferExtent))
4334 for (y=0; y < (ssize_t) rows; y++)
4336 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4337 cache_info->server_info,®ion,length,(unsigned char *) q);
4338 if (count != (MagickOffsetType) length)
4340 q+=cache_info->number_channels*nexus_info->region.width;
4343 UnlockSemaphoreInfo(cache_info->file_semaphore);
4349 if (y < (ssize_t) rows)
4351 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4352 cache_info->cache_filename);
4353 return(MagickFalse);
4355 if ((cache_info->debug != MagickFalse) &&
4356 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4357 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4358 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4359 nexus_info->region.width,(double) nexus_info->region.height,(double)
4360 nexus_info->region.x,(double) nexus_info->region.y);
4365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4369 + R e f e r e n c e P i x e l C a c h e %
4373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375 % ReferencePixelCache() increments the reference count associated with the
4376 % pixel cache returning a pointer to the cache.
4378 % The format of the ReferencePixelCache method is:
4380 % Cache ReferencePixelCache(Cache cache_info)
4382 % A description of each parameter follows:
4384 % o cache_info: the pixel cache.
4387 MagickPrivate Cache ReferencePixelCache(Cache cache)
4390 *restrict cache_info;
4392 assert(cache != (Cache *) NULL);
4393 cache_info=(CacheInfo *) cache;
4394 assert(cache_info->signature == MagickSignature);
4395 LockSemaphoreInfo(cache_info->semaphore);
4396 cache_info->reference_count++;
4397 UnlockSemaphoreInfo(cache_info->semaphore);
4402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4406 + S e t P i x e l C a c h e M e t h o d s %
4410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4412 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4414 % The format of the SetPixelCacheMethods() method is:
4416 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4418 % A description of each parameter follows:
4420 % o cache: the pixel cache.
4422 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4425 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4428 *restrict cache_info;
4430 GetOneAuthenticPixelFromHandler
4431 get_one_authentic_pixel_from_handler;
4433 GetOneVirtualPixelFromHandler
4434 get_one_virtual_pixel_from_handler;
4437 Set cache pixel methods.
4439 assert(cache != (Cache) NULL);
4440 assert(cache_methods != (CacheMethods *) NULL);
4441 cache_info=(CacheInfo *) cache;
4442 assert(cache_info->signature == MagickSignature);
4443 if (cache_info->debug != MagickFalse)
4444 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4445 cache_info->filename);
4446 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4447 cache_info->methods.get_virtual_pixel_handler=
4448 cache_methods->get_virtual_pixel_handler;
4449 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4450 cache_info->methods.destroy_pixel_handler=
4451 cache_methods->destroy_pixel_handler;
4452 if (cache_methods->get_virtual_metacontent_from_handler !=
4453 (GetVirtualMetacontentFromHandler) NULL)
4454 cache_info->methods.get_virtual_metacontent_from_handler=
4455 cache_methods->get_virtual_metacontent_from_handler;
4456 if (cache_methods->get_authentic_pixels_handler !=
4457 (GetAuthenticPixelsHandler) NULL)
4458 cache_info->methods.get_authentic_pixels_handler=
4459 cache_methods->get_authentic_pixels_handler;
4460 if (cache_methods->queue_authentic_pixels_handler !=
4461 (QueueAuthenticPixelsHandler) NULL)
4462 cache_info->methods.queue_authentic_pixels_handler=
4463 cache_methods->queue_authentic_pixels_handler;
4464 if (cache_methods->sync_authentic_pixels_handler !=
4465 (SyncAuthenticPixelsHandler) NULL)
4466 cache_info->methods.sync_authentic_pixels_handler=
4467 cache_methods->sync_authentic_pixels_handler;
4468 if (cache_methods->get_authentic_pixels_from_handler !=
4469 (GetAuthenticPixelsFromHandler) NULL)
4470 cache_info->methods.get_authentic_pixels_from_handler=
4471 cache_methods->get_authentic_pixels_from_handler;
4472 if (cache_methods->get_authentic_metacontent_from_handler !=
4473 (GetAuthenticMetacontentFromHandler) NULL)
4474 cache_info->methods.get_authentic_metacontent_from_handler=
4475 cache_methods->get_authentic_metacontent_from_handler;
4476 get_one_virtual_pixel_from_handler=
4477 cache_info->methods.get_one_virtual_pixel_from_handler;
4478 if (get_one_virtual_pixel_from_handler !=
4479 (GetOneVirtualPixelFromHandler) NULL)
4480 cache_info->methods.get_one_virtual_pixel_from_handler=
4481 cache_methods->get_one_virtual_pixel_from_handler;
4482 get_one_authentic_pixel_from_handler=
4483 cache_methods->get_one_authentic_pixel_from_handler;
4484 if (get_one_authentic_pixel_from_handler !=
4485 (GetOneAuthenticPixelFromHandler) NULL)
4486 cache_info->methods.get_one_authentic_pixel_from_handler=
4487 cache_methods->get_one_authentic_pixel_from_handler;
4491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4495 + S e t P i x e l C a c h e N e x u s P i x e l s %
4499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4501 % SetPixelCacheNexusPixels() defines the region of the cache for the
4502 % specified cache nexus.
4504 % The format of the SetPixelCacheNexusPixels() method is:
4506 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4507 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4508 % ExceptionInfo *exception)
4510 % A description of each parameter follows:
4512 % o cache_info: the pixel cache.
4514 % o mode: ReadMode, WriteMode, or IOMode.
4516 % o region: A pointer to the RectangleInfo structure that defines the
4517 % region of this particular cache nexus.
4519 % o nexus_info: the cache nexus to set.
4521 % o exception: return any errors or warnings in this structure.
4525 static inline MagickBooleanType AcquireCacheNexusPixels(
4526 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4527 ExceptionInfo *exception)
4529 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4530 return(MagickFalse);
4531 nexus_info->mapped=MagickFalse;
4532 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4533 (size_t) nexus_info->length));
4534 if (nexus_info->cache == (Quantum *) NULL)
4536 nexus_info->mapped=MagickTrue;
4537 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4538 nexus_info->length);
4540 if (nexus_info->cache == (Quantum *) NULL)
4542 (void) ThrowMagickException(exception,GetMagickModule(),
4543 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4544 cache_info->filename);
4545 return(MagickFalse);
4550 static inline MagickBooleanType IsPixelCacheAuthentic(
4551 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4560 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4562 if (cache_info->type == PingCache)
4564 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4565 nexus_info->region.x;
4566 status=nexus_info->pixels == (cache_info->pixels+offset*
4567 cache_info->number_channels) ? MagickTrue : MagickFalse;
4571 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4574 if (mode == ReadMode)
4576 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4579 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4582 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4583 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4584 ExceptionInfo *exception)
4593 assert(cache_info != (const CacheInfo *) NULL);
4594 assert(cache_info->signature == MagickSignature);
4595 if (cache_info->type == UndefinedCache)
4596 return((Quantum *) NULL);
4597 nexus_info->region=(*region);
4598 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4604 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4605 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4606 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4607 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4608 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4609 ((nexus_info->region.width == cache_info->columns) ||
4610 ((nexus_info->region.width % cache_info->columns) == 0)))))
4616 Pixels are accessed directly from memory.
4618 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4619 nexus_info->region.x;
4620 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4622 nexus_info->metacontent=(void *) NULL;
4623 if (cache_info->metacontent_extent != 0)
4624 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4625 offset*cache_info->metacontent_extent;
4626 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4627 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4629 return(nexus_info->pixels);
4633 Pixels are stored in a staging region until they are synced to the cache.
4635 number_pixels=(MagickSizeType) nexus_info->region.width*
4636 nexus_info->region.height;
4637 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4638 if (cache_info->metacontent_extent != 0)
4639 length+=number_pixels*cache_info->metacontent_extent;
4640 if (nexus_info->cache == (Quantum *) NULL)
4642 nexus_info->length=length;
4643 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4644 if (status == MagickFalse)
4646 nexus_info->length=0;
4647 return((Quantum *) NULL);
4651 if (nexus_info->length < length)
4653 RelinquishCacheNexusPixels(nexus_info);
4654 nexus_info->length=length;
4655 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4656 if (status == MagickFalse)
4658 nexus_info->length=0;
4659 return((Quantum *) NULL);
4662 nexus_info->pixels=nexus_info->cache;
4663 nexus_info->metacontent=(void *) NULL;
4664 if (cache_info->metacontent_extent != 0)
4665 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4666 cache_info->number_channels);
4667 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4668 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4670 return(nexus_info->pixels);
4674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4678 % 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 %
4682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4684 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4685 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4686 % access that is outside the boundaries of the image cache.
4688 % The format of the SetPixelCacheVirtualMethod() method is:
4690 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4691 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4693 % A description of each parameter follows:
4695 % o image: the image.
4697 % o virtual_pixel_method: choose the type of virtual pixel.
4699 % o exception: return any errors or warnings in this structure.
4703 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4704 ExceptionInfo *exception)
4707 *restrict cache_info;
4710 *restrict image_view;
4718 assert(image != (Image *) NULL);
4719 assert(image->signature == MagickSignature);
4720 if (image->debug != MagickFalse)
4721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4722 assert(image->cache != (Cache) NULL);
4723 cache_info=(CacheInfo *) image->cache;
4724 assert(cache_info->signature == MagickSignature);
4725 image->alpha_trait=BlendPixelTrait;
4727 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4728 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4729 #pragma omp parallel for schedule(static,4) shared(status) \
4730 magick_threads(image,image,1,1)
4732 for (y=0; y < (ssize_t) image->rows; y++)
4740 if (status == MagickFalse)
4742 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4743 if (q == (Quantum *) NULL)
4748 for (x=0; x < (ssize_t) image->columns; x++)
4750 SetPixelAlpha(image,alpha,q);
4751 q+=GetPixelChannels(image);
4753 status=SyncCacheViewAuthenticPixels(image_view,exception);
4755 image_view=DestroyCacheView(image_view);
4759 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4760 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4763 *restrict cache_info;
4768 assert(image != (Image *) NULL);
4769 assert(image->signature == MagickSignature);
4770 if (image->debug != MagickFalse)
4771 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4772 assert(image->cache != (Cache) NULL);
4773 cache_info=(CacheInfo *) image->cache;
4774 assert(cache_info->signature == MagickSignature);
4775 method=cache_info->virtual_pixel_method;
4776 cache_info->virtual_pixel_method=virtual_pixel_method;
4777 if ((image->columns != 0) && (image->rows != 0))
4778 switch (virtual_pixel_method)
4780 case BackgroundVirtualPixelMethod:
4782 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4783 (image->alpha_trait != BlendPixelTrait))
4784 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4785 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4786 (IsGrayColorspace(image->colorspace) != MagickFalse))
4787 (void) SetImageColorspace(image,sRGBColorspace,exception);
4790 case TransparentVirtualPixelMethod:
4792 if (image->alpha_trait != BlendPixelTrait)
4793 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4807 + 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 %
4811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4813 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4814 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4815 % is synced, otherwise MagickFalse.
4817 % The format of the SyncAuthenticPixelCacheNexus() method is:
4819 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4820 % NexusInfo *nexus_info,ExceptionInfo *exception)
4822 % A description of each parameter follows:
4824 % o image: the image.
4826 % o nexus_info: the cache nexus to sync.
4828 % o exception: return any errors or warnings in this structure.
4831 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4832 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4835 *restrict cache_info;
4841 Transfer pixels to the cache.
4843 assert(image != (Image *) NULL);
4844 assert(image->signature == MagickSignature);
4845 if (image->cache == (Cache) NULL)
4846 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4847 cache_info=(CacheInfo *) image->cache;
4848 assert(cache_info->signature == MagickSignature);
4849 if (cache_info->type == UndefinedCache)
4850 return(MagickFalse);
4851 if (nexus_info->authentic_pixel_cache != MagickFalse)
4853 assert(cache_info->signature == MagickSignature);
4854 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4855 if ((cache_info->metacontent_extent != 0) &&
4856 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4857 return(MagickFalse);
4862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866 + S y n c A u t h e n t i c P i x e l C a c h e %
4870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4872 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4873 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4874 % otherwise MagickFalse.
4876 % The format of the SyncAuthenticPixelsCache() method is:
4878 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4879 % ExceptionInfo *exception)
4881 % A description of each parameter follows:
4883 % o image: the image.
4885 % o exception: return any errors or warnings in this structure.
4888 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4889 ExceptionInfo *exception)
4892 *restrict cache_info;
4895 id = GetOpenMPThreadId();
4900 assert(image != (Image *) NULL);
4901 assert(image->signature == MagickSignature);
4902 assert(image->cache != (Cache) NULL);
4903 cache_info=(CacheInfo *) image->cache;
4904 assert(cache_info->signature == MagickSignature);
4905 assert(id < (int) cache_info->number_threads);
4906 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4916 % S y n c A u t h e n t i c P i x e l s %
4920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4922 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4923 % The method returns MagickTrue if the pixel region is flushed, otherwise
4926 % The format of the SyncAuthenticPixels() method is:
4928 % MagickBooleanType SyncAuthenticPixels(Image *image,
4929 % ExceptionInfo *exception)
4931 % A description of each parameter follows:
4933 % o image: the image.
4935 % o exception: return any errors or warnings in this structure.
4938 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4939 ExceptionInfo *exception)
4942 *restrict cache_info;
4945 id = GetOpenMPThreadId();
4950 assert(image != (Image *) NULL);
4951 assert(image->signature == MagickSignature);
4952 assert(image->cache != (Cache) NULL);
4953 cache_info=(CacheInfo *) image->cache;
4954 assert(cache_info->signature == MagickSignature);
4955 if (cache_info->methods.sync_authentic_pixels_handler !=
4956 (SyncAuthenticPixelsHandler) NULL)
4958 status=cache_info->methods.sync_authentic_pixels_handler(image,
4962 assert(id < (int) cache_info->number_threads);
4963 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4973 + S y n c I m a g e P i x e l C a c h e %
4977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4979 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4980 % The method returns MagickTrue if the pixel region is flushed, otherwise
4983 % The format of the SyncImagePixelCache() method is:
4985 % MagickBooleanType SyncImagePixelCache(Image *image,
4986 % ExceptionInfo *exception)
4988 % A description of each parameter follows:
4990 % o image: the image.
4992 % o exception: return any errors or warnings in this structure.
4995 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4996 ExceptionInfo *exception)
4999 *restrict cache_info;
5001 assert(image != (Image *) NULL);
5002 assert(exception != (ExceptionInfo *) NULL);
5003 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5004 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5012 + 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 %
5016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5018 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5019 % of the pixel cache.
5021 % The format of the WritePixelCacheMetacontent() method is:
5023 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5024 % NexusInfo *nexus_info,ExceptionInfo *exception)
5026 % A description of each parameter follows:
5028 % o cache_info: the pixel cache.
5030 % o nexus_info: the cache nexus to write the meta-content.
5032 % o exception: return any errors or warnings in this structure.
5035 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5036 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5046 register const unsigned char
5055 if (cache_info->metacontent_extent == 0)
5056 return(MagickFalse);
5057 if (nexus_info->authentic_pixel_cache != MagickFalse)
5059 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5060 nexus_info->region.x;
5061 length=(MagickSizeType) nexus_info->region.width*
5062 cache_info->metacontent_extent;
5063 extent=(MagickSizeType) length*nexus_info->region.height;
5064 rows=nexus_info->region.height;
5066 p=(unsigned char *) nexus_info->metacontent;
5067 switch (cache_info->type)
5072 register unsigned char
5076 Write associated pixels to memory.
5078 if ((cache_info->columns == nexus_info->region.width) &&
5079 (extent == (MagickSizeType) ((size_t) extent)))
5084 q=(unsigned char *) cache_info->metacontent+offset*
5085 cache_info->metacontent_extent;
5086 for (y=0; y < (ssize_t) rows; y++)
5088 (void) memcpy(q,p,(size_t) length);
5089 p+=nexus_info->region.width*cache_info->metacontent_extent;
5090 q+=cache_info->columns*cache_info->metacontent_extent;
5097 Write associated pixels to disk.
5099 LockSemaphoreInfo(cache_info->file_semaphore);
5100 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5102 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5103 cache_info->cache_filename);
5104 UnlockSemaphoreInfo(cache_info->file_semaphore);
5105 return(MagickFalse);
5107 if ((cache_info->columns == nexus_info->region.width) &&
5108 (extent <= MagickMaxBufferExtent))
5113 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5114 for (y=0; y < (ssize_t) rows; y++)
5116 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5117 cache_info->number_channels*sizeof(Quantum)+offset*
5118 cache_info->metacontent_extent,length,(const unsigned char *) p);
5119 if (count != (MagickOffsetType) length)
5121 p+=cache_info->metacontent_extent*nexus_info->region.width;
5122 offset+=cache_info->columns;
5124 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5125 (void) ClosePixelCacheOnDisk(cache_info);
5126 UnlockSemaphoreInfo(cache_info->file_semaphore);
5129 case DistributedCache:
5135 Write metacontent to distributed cache.
5137 LockSemaphoreInfo(cache_info->file_semaphore);
5138 region=nexus_info->region;
5139 if ((cache_info->columns != nexus_info->region.width) ||
5140 (extent > MagickMaxBufferExtent))
5147 for (y=0; y < (ssize_t) rows; y++)
5149 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5150 cache_info->server_info,®ion,length,(const unsigned char *) p);
5151 if (count != (MagickOffsetType) length)
5153 p+=cache_info->metacontent_extent*nexus_info->region.width;
5156 UnlockSemaphoreInfo(cache_info->file_semaphore);
5162 if (y < (ssize_t) rows)
5164 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5165 cache_info->cache_filename);
5166 return(MagickFalse);
5168 if ((cache_info->debug != MagickFalse) &&
5169 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5171 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5172 nexus_info->region.width,(double) nexus_info->region.height,(double)
5173 nexus_info->region.x,(double) nexus_info->region.y);
5178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5182 + W r i t e C a c h e P i x e l s %
5186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5188 % WritePixelCachePixels() writes image pixels to the specified region of the
5191 % The format of the WritePixelCachePixels() method is:
5193 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5194 % NexusInfo *nexus_info,ExceptionInfo *exception)
5196 % A description of each parameter follows:
5198 % o cache_info: the pixel cache.
5200 % o nexus_info: the cache nexus to write the pixels.
5202 % o exception: return any errors or warnings in this structure.
5205 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5206 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5216 register const Quantum
5225 if (nexus_info->authentic_pixel_cache != MagickFalse)
5227 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5228 nexus_info->region.x;
5229 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5231 extent=length*nexus_info->region.height;
5232 rows=nexus_info->region.height;
5234 p=nexus_info->pixels;
5235 switch (cache_info->type)
5244 Write pixels to memory.
5246 if ((cache_info->columns == nexus_info->region.width) &&
5247 (extent == (MagickSizeType) ((size_t) extent)))
5252 q=cache_info->pixels+offset*cache_info->number_channels;
5253 for (y=0; y < (ssize_t) rows; y++)
5255 (void) memcpy(q,p,(size_t) length);
5256 p+=cache_info->number_channels*nexus_info->region.width;
5257 q+=cache_info->columns*cache_info->number_channels;
5264 Write pixels to disk.
5266 LockSemaphoreInfo(cache_info->file_semaphore);
5267 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5269 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5270 cache_info->cache_filename);
5271 UnlockSemaphoreInfo(cache_info->file_semaphore);
5272 return(MagickFalse);
5274 if ((cache_info->columns == nexus_info->region.width) &&
5275 (extent <= MagickMaxBufferExtent))
5280 for (y=0; y < (ssize_t) rows; y++)
5282 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5283 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5285 if (count != (MagickOffsetType) length)
5287 p+=cache_info->number_channels*nexus_info->region.width;
5288 offset+=cache_info->columns;
5290 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5291 (void) ClosePixelCacheOnDisk(cache_info);
5292 UnlockSemaphoreInfo(cache_info->file_semaphore);
5295 case DistributedCache:
5301 Write pixels to distributed cache.
5303 LockSemaphoreInfo(cache_info->file_semaphore);
5304 region=nexus_info->region;
5305 if ((cache_info->columns != nexus_info->region.width) ||
5306 (extent > MagickMaxBufferExtent))
5313 for (y=0; y < (ssize_t) rows; y++)
5315 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5316 cache_info->server_info,®ion,length,(const unsigned char *) p);
5317 if (count != (MagickOffsetType) length)
5319 p+=cache_info->number_channels*nexus_info->region.width;
5322 UnlockSemaphoreInfo(cache_info->file_semaphore);
5328 if (y < (ssize_t) rows)
5330 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5331 cache_info->cache_filename);
5332 return(MagickFalse);
5334 if ((cache_info->debug != MagickFalse) &&
5335 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5336 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5337 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5338 nexus_info->region.width,(double) nexus_info->region.height,(double)
5339 nexus_info->region.x,(double) nexus_info->region.y);