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 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
547 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
548 sizeof(cache_info->metacontent));
552 Mismatched pixel cache morphology.
554 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
555 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
556 if ((cache_nexus == (NexusInfo **) NULL) ||
557 (clone_nexus == (NexusInfo **) NULL))
558 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
559 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
560 optimize=(cache_info->number_channels == clone_info->number_channels) &&
561 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
562 MagickTrue : MagickFalse;
563 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
564 clone_info->columns*clone_info->number_channels);
566 #if defined(MAGICKCORE_OPENMP_SUPPORT)
567 #pragma omp parallel for schedule(static,4) shared(status) \
568 cache_threads(cache_info,clone_info,cache_info->rows)
570 for (y=0; y < (ssize_t) cache_info->rows; y++)
573 id = GetOpenMPThreadId();
584 if (status == MagickFalse)
586 if (y >= (ssize_t) clone_info->rows)
588 region.width=cache_info->columns;
592 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
594 if (pixels == (Quantum *) NULL)
596 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
597 if (status == MagickFalse)
599 region.width=clone_info->columns;
600 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
601 clone_nexus[id],exception);
602 if (pixels == (Quantum *) NULL)
604 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,clone_nexus[id]->length);
605 if (optimize != MagickFalse)
606 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
610 register const Quantum
617 Mismatched pixel channel map.
619 p=cache_nexus[id]->pixels;
620 q=clone_nexus[id]->pixels;
621 for (x=0; x < (ssize_t) cache_info->columns; x++)
626 if (x == (ssize_t) clone_info->columns)
628 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
636 channel=clone_info->channel_map[i].channel;
637 traits=cache_info->channel_map[channel].traits;
638 if (traits != UndefinedPixelTrait)
639 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
643 p+=cache_info->number_channels;
646 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
648 if ((cache_info->metacontent_extent != 0) &&
649 (clone_info->metacontent_extent != 0))
654 length=(size_t) MagickMin(cache_info->metacontent_extent,
655 clone_info->metacontent_extent);
656 #if defined(MAGICKCORE_OPENMP_SUPPORT)
657 #pragma omp parallel for schedule(static,4) shared(status) \
658 cache_threads(cache_info,clone_info,cache_info->rows)
660 for (y=0; y < (ssize_t) cache_info->rows; y++)
663 id = GetOpenMPThreadId();
671 if (status == MagickFalse)
673 if (y >= (ssize_t) clone_info->rows)
675 region.width=cache_info->columns;
679 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
680 cache_nexus[id],exception);
681 if (pixels == (Quantum *) NULL)
683 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
684 if (status == MagickFalse)
686 region.width=clone_info->columns;
687 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
688 clone_nexus[id],exception);
689 if (pixels == (Quantum *) NULL)
691 if (clone_nexus[id]->metacontent != (void *) NULL)
692 (void) memcpy(clone_nexus[id]->metacontent,
693 cache_nexus[id]->metacontent,length*
694 sizeof(cache_nexus[id]->metacontent));
695 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
698 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
699 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
700 if (cache_info->debug != MagickFalse)
703 message[MaxTextExtent];
705 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
706 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
707 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718 + D e s t r o y I m a g e P i x e l C a c h e %
722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
724 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
726 % The format of the DestroyImagePixelCache() method is:
728 % void DestroyImagePixelCache(Image *image)
730 % A description of each parameter follows:
732 % o image: the image.
735 static void DestroyImagePixelCache(Image *image)
737 assert(image != (Image *) NULL);
738 assert(image->signature == MagickSignature);
739 if (image->debug != MagickFalse)
740 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
741 if (image->cache == (void *) NULL)
743 image->cache=DestroyPixelCache(image->cache);
747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751 + D e s t r o y I m a g e P i x e l s %
755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757 % DestroyImagePixels() deallocates memory associated with the pixel cache.
759 % The format of the DestroyImagePixels() method is:
761 % void DestroyImagePixels(Image *image)
763 % A description of each parameter follows:
765 % o image: the image.
768 MagickExport void DestroyImagePixels(Image *image)
771 *restrict cache_info;
773 assert(image != (const Image *) NULL);
774 assert(image->signature == MagickSignature);
775 if (image->debug != MagickFalse)
776 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
777 assert(image->cache != (Cache) NULL);
778 cache_info=(CacheInfo *) image->cache;
779 assert(cache_info->signature == MagickSignature);
780 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
782 cache_info->methods.destroy_pixel_handler(image);
785 image->cache=DestroyPixelCache(image->cache);
789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793 + D e s t r o y P i x e l C a c h e %
797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799 % DestroyPixelCache() deallocates memory associated with the pixel cache.
801 % The format of the DestroyPixelCache() method is:
803 % Cache DestroyPixelCache(Cache cache)
805 % A description of each parameter follows:
807 % o cache: the pixel cache.
811 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
817 if (cache_info->file != -1)
819 status=close(cache_info->file);
820 cache_info->file=(-1);
821 RelinquishMagickResource(FileResource,1);
823 return(status == -1 ? MagickFalse : MagickTrue);
826 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
828 switch (cache_info->type)
832 if (cache_info->mapped == MagickFalse)
833 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
837 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
838 cache_info->pixels=(Quantum *) NULL;
840 RelinquishMagickResource(MemoryResource,cache_info->length);
845 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
846 cache_info->pixels=(Quantum *) NULL;
847 if (cache_info->mode != ReadMode)
848 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
849 *cache_info->cache_filename='\0';
850 RelinquishMagickResource(MapResource,cache_info->length);
854 if (cache_info->file != -1)
855 (void) ClosePixelCacheOnDisk(cache_info);
856 if (cache_info->mode != ReadMode)
857 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
858 *cache_info->cache_filename='\0';
859 RelinquishMagickResource(DiskResource,cache_info->length);
862 case DistributedCache:
864 *cache_info->cache_filename='\0';
865 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
866 cache_info->server_info);
872 cache_info->type=UndefinedCache;
873 cache_info->mapped=MagickFalse;
874 cache_info->metacontent=(void *) NULL;
877 MagickPrivate Cache DestroyPixelCache(Cache cache)
880 *restrict cache_info;
882 assert(cache != (Cache) NULL);
883 cache_info=(CacheInfo *) cache;
884 assert(cache_info->signature == MagickSignature);
885 if (cache_info->debug != MagickFalse)
886 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
887 cache_info->filename);
888 LockSemaphoreInfo(cache_info->semaphore);
889 cache_info->reference_count--;
890 if (cache_info->reference_count != 0)
892 UnlockSemaphoreInfo(cache_info->semaphore);
893 return((Cache) NULL);
895 UnlockSemaphoreInfo(cache_info->semaphore);
896 if (cache_info->debug != MagickFalse)
899 message[MaxTextExtent];
901 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
902 cache_info->filename);
903 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
905 RelinquishPixelCachePixels(cache_info);
906 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
907 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
908 cache_info->server_info);
909 if (cache_info->nexus_info != (NexusInfo **) NULL)
910 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
911 cache_info->number_threads);
912 if (cache_info->random_info != (RandomInfo *) NULL)
913 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
914 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
915 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
916 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
917 RelinquishSemaphoreInfo(&cache_info->semaphore);
918 cache_info->signature=(~MagickSignature);
919 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 + D e s t r o y P i x e l C a c h e N e x u s %
933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
937 % The format of the DestroyPixelCacheNexus() method is:
939 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
940 % const size_t number_threads)
942 % A description of each parameter follows:
944 % o nexus_info: the nexus to destroy.
946 % o number_threads: the number of nexus threads.
950 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
952 if (nexus_info->mapped == MagickFalse)
953 (void) RelinquishAlignedMemory(nexus_info->cache);
955 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
956 nexus_info->cache=(Quantum *) NULL;
957 nexus_info->pixels=(Quantum *) NULL;
958 nexus_info->metacontent=(void *) NULL;
959 nexus_info->length=0;
960 nexus_info->mapped=MagickFalse;
963 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
964 const size_t number_threads)
969 assert(nexus_info != (NexusInfo **) NULL);
970 for (i=0; i < (ssize_t) number_threads; i++)
972 if (nexus_info[i]->cache != (Quantum *) NULL)
973 RelinquishCacheNexusPixels(nexus_info[i]);
974 nexus_info[i]->signature=(~MagickSignature);
976 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
977 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 % G e t A u t h e n t i c M e t a c o n t e n t %
990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
993 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
994 % returned if the associated pixels are not available.
996 % The format of the GetAuthenticMetacontent() method is:
998 % void *GetAuthenticMetacontent(const Image *image)
1000 % A description of each parameter follows:
1002 % o image: the image.
1005 MagickExport void *GetAuthenticMetacontent(const Image *image)
1008 *restrict cache_info;
1011 id = GetOpenMPThreadId();
1013 assert(image != (const Image *) NULL);
1014 assert(image->signature == MagickSignature);
1015 assert(image->cache != (Cache) NULL);
1016 cache_info=(CacheInfo *) image->cache;
1017 assert(cache_info->signature == MagickSignature);
1018 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1019 (GetAuthenticMetacontentFromHandler) NULL)
1024 metacontent=cache_info->methods.
1025 get_authentic_metacontent_from_handler(image);
1026 return(metacontent);
1028 assert(id < (int) cache_info->number_threads);
1029 return(cache_info->nexus_info[id]->metacontent);
1033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1037 + 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 %
1041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1043 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1044 % with the last call to QueueAuthenticPixelsCache() or
1045 % GetAuthenticPixelsCache().
1047 % The format of the GetAuthenticMetacontentFromCache() method is:
1049 % void *GetAuthenticMetacontentFromCache(const Image *image)
1051 % A description of each parameter follows:
1053 % o image: the image.
1056 static void *GetAuthenticMetacontentFromCache(const Image *image)
1059 *restrict cache_info;
1062 id = GetOpenMPThreadId();
1064 assert(image != (const Image *) NULL);
1065 assert(image->signature == MagickSignature);
1066 assert(image->cache != (Cache) NULL);
1067 cache_info=(CacheInfo *) image->cache;
1068 assert(cache_info->signature == MagickSignature);
1069 assert(id < (int) cache_info->number_threads);
1070 return(cache_info->nexus_info[id]->metacontent);
1074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 + 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 %
1082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1085 % disk pixel cache as defined by the geometry parameters. A pointer to the
1086 % pixels is returned if the pixels are transferred, otherwise a NULL is
1089 % The format of the GetAuthenticPixelCacheNexus() method is:
1091 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1092 % const ssize_t y,const size_t columns,const size_t rows,
1093 % NexusInfo *nexus_info,ExceptionInfo *exception)
1095 % A description of each parameter follows:
1097 % o image: the image.
1099 % o x,y,columns,rows: These values define the perimeter of a region of
1102 % o nexus_info: the cache nexus to return.
1104 % o exception: return any errors or warnings in this structure.
1108 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1109 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1110 ExceptionInfo *exception)
1113 *restrict cache_info;
1119 Transfer pixels from the cache.
1121 assert(image != (Image *) NULL);
1122 assert(image->signature == MagickSignature);
1123 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1124 nexus_info,exception);
1125 if (pixels == (Quantum *) NULL)
1126 return((Quantum *) NULL);
1127 cache_info=(CacheInfo *) image->cache;
1128 assert(cache_info->signature == MagickSignature);
1129 if (nexus_info->authentic_pixel_cache != MagickFalse)
1131 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1132 return((Quantum *) NULL);
1133 if (cache_info->metacontent_extent != 0)
1134 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1135 return((Quantum *) NULL);
1140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1144 + 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 %
1148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1150 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1151 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1153 % The format of the GetAuthenticPixelsFromCache() method is:
1155 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1157 % A description of each parameter follows:
1159 % o image: the image.
1162 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1165 *restrict cache_info;
1168 id = GetOpenMPThreadId();
1170 assert(image != (const Image *) NULL);
1171 assert(image->signature == MagickSignature);
1172 assert(image->cache != (Cache) NULL);
1173 cache_info=(CacheInfo *) image->cache;
1174 assert(cache_info->signature == MagickSignature);
1175 assert(id < (int) cache_info->number_threads);
1176 return(cache_info->nexus_info[id]->pixels);
1180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1184 % G e t A u t h e n t i c P i x e l Q u e u e %
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1190 % GetAuthenticPixelQueue() returns the authentic pixels associated
1191 % corresponding with the last call to QueueAuthenticPixels() or
1192 % GetAuthenticPixels().
1194 % The format of the GetAuthenticPixelQueue() method is:
1196 % Quantum *GetAuthenticPixelQueue(const Image image)
1198 % A description of each parameter follows:
1200 % o image: the image.
1203 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1206 *restrict cache_info;
1209 id = GetOpenMPThreadId();
1211 assert(image != (const Image *) NULL);
1212 assert(image->signature == MagickSignature);
1213 assert(image->cache != (Cache) NULL);
1214 cache_info=(CacheInfo *) image->cache;
1215 assert(cache_info->signature == MagickSignature);
1216 if (cache_info->methods.get_authentic_pixels_from_handler !=
1217 (GetAuthenticPixelsFromHandler) NULL)
1218 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1219 assert(id < (int) cache_info->number_threads);
1220 return(cache_info->nexus_info[id]->pixels);
1224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1228 % G e t A u t h e n t i c P i x e l s %
1231 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1233 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1234 % region is successfully accessed, a pointer to a Quantum array
1235 % representing the region is returned, otherwise NULL is returned.
1237 % The returned pointer may point to a temporary working copy of the pixels
1238 % or it may point to the original pixels in memory. Performance is maximized
1239 % if the selected region is part of one row, or one or more full rows, since
1240 % then there is opportunity to access the pixels in-place (without a copy)
1241 % if the image is in memory, or in a memory-mapped file. The returned pointer
1242 % must *never* be deallocated by the user.
1244 % Pixels accessed via the returned pointer represent a simple array of type
1245 % Quantum. If the image has corresponding metacontent,call
1246 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1247 % meta-content corresponding to the region. Once the Quantum array has
1248 % been updated, the changes must be saved back to the underlying image using
1249 % SyncAuthenticPixels() or they may be lost.
1251 % The format of the GetAuthenticPixels() method is:
1253 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1254 % const ssize_t y,const size_t columns,const size_t rows,
1255 % ExceptionInfo *exception)
1257 % A description of each parameter follows:
1259 % o image: the image.
1261 % o x,y,columns,rows: These values define the perimeter of a region of
1264 % o exception: return any errors or warnings in this structure.
1267 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1268 const ssize_t y,const size_t columns,const size_t rows,
1269 ExceptionInfo *exception)
1272 *restrict cache_info;
1275 id = GetOpenMPThreadId();
1280 assert(image != (Image *) NULL);
1281 assert(image->signature == MagickSignature);
1282 assert(image->cache != (Cache) NULL);
1283 cache_info=(CacheInfo *) image->cache;
1284 assert(cache_info->signature == MagickSignature);
1285 if (cache_info->methods.get_authentic_pixels_handler !=
1286 (GetAuthenticPixelsHandler) NULL)
1288 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1292 assert(id < (int) cache_info->number_threads);
1293 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1294 cache_info->nexus_info[id],exception);
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 + G e t A u t h e n t i c P i x e l s C a c h e %
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1310 % as defined by the geometry parameters. A pointer to the pixels is returned
1311 % if the pixels are transferred, otherwise a NULL is returned.
1313 % The format of the GetAuthenticPixelsCache() method is:
1315 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1316 % const ssize_t y,const size_t columns,const size_t rows,
1317 % ExceptionInfo *exception)
1319 % A description of each parameter follows:
1321 % o image: the image.
1323 % o x,y,columns,rows: These values define the perimeter of a region of
1326 % o exception: return any errors or warnings in this structure.
1329 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1330 const ssize_t y,const size_t columns,const size_t rows,
1331 ExceptionInfo *exception)
1334 *restrict cache_info;
1337 id = GetOpenMPThreadId();
1342 assert(image != (const Image *) NULL);
1343 assert(image->signature == MagickSignature);
1344 assert(image->cache != (Cache) NULL);
1345 cache_info=(CacheInfo *) image->cache;
1346 if (cache_info == (Cache) NULL)
1347 return((Quantum *) NULL);
1348 assert(cache_info->signature == MagickSignature);
1349 assert(id < (int) cache_info->number_threads);
1350 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1351 cache_info->nexus_info[id],exception);
1356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360 + G e t I m a g e E x t e n t %
1364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366 % GetImageExtent() returns the extent of the pixels associated corresponding
1367 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1369 % The format of the GetImageExtent() method is:
1371 % MagickSizeType GetImageExtent(const Image *image)
1373 % A description of each parameter follows:
1375 % o image: the image.
1378 MagickExport MagickSizeType GetImageExtent(const Image *image)
1381 *restrict cache_info;
1384 id = GetOpenMPThreadId();
1386 assert(image != (Image *) NULL);
1387 assert(image->signature == MagickSignature);
1388 if (image->debug != MagickFalse)
1389 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1390 assert(image->cache != (Cache) NULL);
1391 cache_info=(CacheInfo *) image->cache;
1392 assert(cache_info->signature == MagickSignature);
1393 assert(id < (int) cache_info->number_threads);
1394 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 + G e t I m a g e P i x e l C a c h e %
1406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408 % GetImagePixelCache() ensures that there is only a single reference to the
1409 % pixel cache to be modified, updating the provided cache pointer to point to
1410 % a clone of the original pixel cache if necessary.
1412 % The format of the GetImagePixelCache method is:
1414 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1415 % ExceptionInfo *exception)
1417 % A description of each parameter follows:
1419 % o image: the image.
1421 % o clone: any value other than MagickFalse clones the cache pixels.
1423 % o exception: return any errors or warnings in this structure.
1427 static inline MagickBooleanType ValidatePixelCacheMorphology(
1428 const Image *restrict image)
1431 *restrict cache_info;
1433 const PixelChannelMap
1438 Does the image match the pixel cache morphology?
1440 cache_info=(CacheInfo *) image->cache;
1441 p=image->channel_map;
1442 q=cache_info->channel_map;
1443 if ((image->storage_class != cache_info->storage_class) ||
1444 (image->colorspace != cache_info->colorspace) ||
1445 (image->alpha_trait != cache_info->alpha_trait) ||
1446 (image->read_mask != cache_info->read_mask) ||
1447 (image->write_mask != cache_info->write_mask) ||
1448 (image->columns != cache_info->columns) ||
1449 (image->rows != cache_info->rows) ||
1450 (image->number_channels != cache_info->number_channels) ||
1451 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1452 (image->metacontent_extent != cache_info->metacontent_extent) ||
1453 (cache_info->nexus_info == (NexusInfo **) NULL))
1454 return(MagickFalse);
1458 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1459 ExceptionInfo *exception)
1462 *restrict cache_info;
1468 static MagickSizeType
1474 cache_timestamp = 0;
1477 LockSemaphoreInfo(image->semaphore);
1478 if (cpu_throttle == 0)
1479 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1480 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1481 MagickDelay(cpu_throttle);
1482 if (time_limit == 0)
1485 Set the expire time in seconds.
1487 time_limit=GetMagickResourceLimit(TimeResource);
1488 cache_timestamp=time((time_t *) NULL);
1490 if ((time_limit != MagickResourceInfinity) &&
1491 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1493 #if defined(ECANCELED)
1496 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1498 assert(image->cache != (Cache) NULL);
1499 cache_info=(CacheInfo *) image->cache;
1500 destroy=MagickFalse;
1501 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1503 LockSemaphoreInfo(cache_info->semaphore);
1504 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1515 clone_image=(*image);
1516 clone_image.semaphore=AcquireSemaphoreInfo();
1517 clone_image.reference_count=1;
1518 clone_image.cache=ClonePixelCache(cache_info);
1519 clone_info=(CacheInfo *) clone_image.cache;
1520 status=OpenPixelCache(&clone_image,IOMode,exception);
1521 if (status != MagickFalse)
1523 if (clone != MagickFalse)
1524 status=ClonePixelCacheRepository(clone_info,cache_info,
1526 if (status != MagickFalse)
1528 if (cache_info->reference_count == 1)
1529 cache_info->nexus_info=(NexusInfo **) NULL;
1531 image->cache=clone_image.cache;
1534 RelinquishSemaphoreInfo(&clone_image.semaphore);
1536 UnlockSemaphoreInfo(cache_info->semaphore);
1538 if (destroy != MagickFalse)
1539 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1540 if (status != MagickFalse)
1543 Ensure the image matches the pixel cache morphology.
1545 image->taint=MagickTrue;
1546 image->type=UndefinedType;
1547 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1549 status=OpenPixelCache(image,IOMode,exception);
1550 cache_info=(CacheInfo *) image->cache;
1551 if (cache_info->type == DiskCache)
1552 (void) ClosePixelCacheOnDisk(cache_info);
1555 UnlockSemaphoreInfo(image->semaphore);
1556 if (status == MagickFalse)
1557 return((Cache) NULL);
1558 return(image->cache);
1562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566 + G e t I m a g e P i x e l C a c h e T y p e %
1570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1572 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1573 % DiskCache, MemoryCache, MapCache, or PingCache.
1575 % The format of the GetImagePixelCacheType() method is:
1577 % CacheType GetImagePixelCacheType(const Image *image)
1579 % A description of each parameter follows:
1581 % o image: the image.
1584 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1587 *restrict cache_info;
1589 assert(image != (Image *) NULL);
1590 assert(image->signature == MagickSignature);
1591 assert(image->cache != (Cache) NULL);
1592 cache_info=(CacheInfo *) image->cache;
1593 assert(cache_info->signature == MagickSignature);
1594 return(cache_info->type);
1598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602 % G e t O n e A u t h e n t i c P i x e l %
1606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1608 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1609 % location. The image background color is returned if an error occurs.
1611 % The format of the GetOneAuthenticPixel() method is:
1613 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1614 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1616 % A description of each parameter follows:
1618 % o image: the image.
1620 % o x,y: These values define the location of the pixel to return.
1622 % o pixel: return a pixel at the specified (x,y) location.
1624 % o exception: return any errors or warnings in this structure.
1627 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1628 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1631 *restrict cache_info;
1639 assert(image != (Image *) NULL);
1640 assert(image->signature == MagickSignature);
1641 assert(image->cache != (Cache) NULL);
1642 cache_info=(CacheInfo *) image->cache;
1643 assert(cache_info->signature == MagickSignature);
1644 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1645 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1646 (GetOneAuthenticPixelFromHandler) NULL)
1647 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1649 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1650 if (q == (Quantum *) NULL)
1652 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1653 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1654 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1655 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1656 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1657 return(MagickFalse);
1659 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1661 PixelChannel channel=GetPixelChannelChannel(image,i);
1662 pixel[channel]=q[i];
1668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672 + 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 %
1676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1678 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1679 % location. The image background color is returned if an error occurs.
1681 % The format of the GetOneAuthenticPixelFromCache() method is:
1683 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1684 % const ssize_t x,const ssize_t y,Quantum *pixel,
1685 % ExceptionInfo *exception)
1687 % A description of each parameter follows:
1689 % o image: the image.
1691 % o x,y: These values define the location of the pixel to return.
1693 % o pixel: return a pixel at the specified (x,y) location.
1695 % o exception: return any errors or warnings in this structure.
1698 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1699 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1702 *restrict cache_info;
1705 id = GetOpenMPThreadId();
1713 assert(image != (const Image *) NULL);
1714 assert(image->signature == MagickSignature);
1715 assert(image->cache != (Cache) NULL);
1716 cache_info=(CacheInfo *) image->cache;
1717 assert(cache_info->signature == MagickSignature);
1718 assert(id < (int) cache_info->number_threads);
1719 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1720 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1722 if (q == (Quantum *) NULL)
1724 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1725 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1726 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1727 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1728 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1729 return(MagickFalse);
1731 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1733 PixelChannel channel=GetPixelChannelChannel(image,i);
1734 pixel[channel]=q[i];
1740 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744 % G e t O n e V i r t u a l P i x e l %
1748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1750 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1751 % (x,y) location. The image background color is returned if an error occurs.
1752 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1754 % The format of the GetOneVirtualPixel() method is:
1756 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1757 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1759 % A description of each parameter follows:
1761 % o image: the image.
1763 % o x,y: These values define the location of the pixel to return.
1765 % o pixel: return a pixel at the specified (x,y) location.
1767 % o exception: return any errors or warnings in this structure.
1770 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1771 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1774 *restrict cache_info;
1777 id = GetOpenMPThreadId();
1785 assert(image != (const Image *) NULL);
1786 assert(image->signature == MagickSignature);
1787 assert(image->cache != (Cache) NULL);
1788 cache_info=(CacheInfo *) image->cache;
1789 assert(cache_info->signature == MagickSignature);
1790 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1791 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1792 (GetOneVirtualPixelFromHandler) NULL)
1793 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1794 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1795 assert(id < (int) cache_info->number_threads);
1796 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1797 1UL,1UL,cache_info->nexus_info[id],exception);
1798 if (p == (const Quantum *) NULL)
1800 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1801 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1802 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1803 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1804 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1805 return(MagickFalse);
1807 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1809 PixelChannel channel=GetPixelChannelChannel(image,i);
1810 pixel[channel]=p[i];
1816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1820 + 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 %
1824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1826 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1827 % specified (x,y) location. The image background color is returned if an
1830 % The format of the GetOneVirtualPixelFromCache() method is:
1832 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1833 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1834 % Quantum *pixel,ExceptionInfo *exception)
1836 % A description of each parameter follows:
1838 % o image: the image.
1840 % o virtual_pixel_method: the virtual pixel method.
1842 % o x,y: These values define the location of the pixel to return.
1844 % o pixel: return a pixel at the specified (x,y) location.
1846 % o exception: return any errors or warnings in this structure.
1849 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1850 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1851 Quantum *pixel,ExceptionInfo *exception)
1854 *restrict cache_info;
1857 id = GetOpenMPThreadId();
1865 assert(image != (const Image *) NULL);
1866 assert(image->signature == MagickSignature);
1867 assert(image->cache != (Cache) NULL);
1868 cache_info=(CacheInfo *) image->cache;
1869 assert(cache_info->signature == MagickSignature);
1870 assert(id < (int) cache_info->number_threads);
1871 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1872 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1873 cache_info->nexus_info[id],exception);
1874 if (p == (const Quantum *) NULL)
1876 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1877 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1878 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1879 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1880 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1881 return(MagickFalse);
1883 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1885 PixelChannel channel=GetPixelChannelChannel(image,i);
1886 pixel[channel]=p[i];
1892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1896 % G e t O n e V i r t u a l P i x e l I n f o %
1900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1902 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1903 % location. The image background color is returned if an error occurs. If
1904 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1906 % The format of the GetOneVirtualPixelInfo() method is:
1908 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1909 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1910 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1912 % A description of each parameter follows:
1914 % o image: the image.
1916 % o virtual_pixel_method: the virtual pixel method.
1918 % o x,y: these values define the location of the pixel to return.
1920 % o pixel: return a pixel at the specified (x,y) location.
1922 % o exception: return any errors or warnings in this structure.
1925 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1926 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1927 PixelInfo *pixel,ExceptionInfo *exception)
1930 *restrict cache_info;
1933 id = GetOpenMPThreadId();
1935 register const Quantum
1938 assert(image != (const Image *) NULL);
1939 assert(image->signature == MagickSignature);
1940 assert(image->cache != (Cache) NULL);
1941 cache_info=(CacheInfo *) image->cache;
1942 assert(cache_info->signature == MagickSignature);
1943 assert(id < (int) cache_info->number_threads);
1944 GetPixelInfo(image,pixel);
1945 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1946 cache_info->nexus_info[id],exception);
1947 if (p == (const Quantum *) NULL)
1948 return(MagickFalse);
1949 GetPixelInfoPixel(image,p,pixel);
1954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958 + G e t P i x e l C a c h e C o l o r s p a c e %
1962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1966 % The format of the GetPixelCacheColorspace() method is:
1968 % Colorspace GetPixelCacheColorspace(Cache cache)
1970 % A description of each parameter follows:
1972 % o cache: the pixel cache.
1975 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1978 *restrict cache_info;
1980 assert(cache != (Cache) NULL);
1981 cache_info=(CacheInfo *) cache;
1982 assert(cache_info->signature == MagickSignature);
1983 if (cache_info->debug != MagickFalse)
1984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1985 cache_info->filename);
1986 return(cache_info->colorspace);
1990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1994 + G e t P i x e l C a c h e M e t h o d s %
1998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000 % GetPixelCacheMethods() initializes the CacheMethods structure.
2002 % The format of the GetPixelCacheMethods() method is:
2004 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2006 % A description of each parameter follows:
2008 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2011 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2013 assert(cache_methods != (CacheMethods *) NULL);
2014 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2015 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2016 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2017 cache_methods->get_virtual_metacontent_from_handler=
2018 GetVirtualMetacontentFromCache;
2019 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2020 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2021 cache_methods->get_authentic_metacontent_from_handler=
2022 GetAuthenticMetacontentFromCache;
2023 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2024 cache_methods->get_one_authentic_pixel_from_handler=
2025 GetOneAuthenticPixelFromCache;
2026 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2027 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2028 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2036 + G e t P i x e l C a c h e N e x u s E x t e n t %
2040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2042 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2043 % corresponding with the last call to SetPixelCacheNexusPixels() or
2044 % GetPixelCacheNexusPixels().
2046 % The format of the GetPixelCacheNexusExtent() method is:
2048 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2049 % NexusInfo *nexus_info)
2051 % A description of each parameter follows:
2053 % o nexus_info: the nexus info.
2056 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2057 NexusInfo *restrict nexus_info)
2060 *restrict cache_info;
2065 assert(cache != NULL);
2066 cache_info=(CacheInfo *) cache;
2067 assert(cache_info->signature == MagickSignature);
2068 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2070 return((MagickSizeType) cache_info->columns*cache_info->rows);
2075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2079 + G e t P i x e l C a c h e P i x e l s %
2083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2085 % GetPixelCachePixels() returns the pixels associated with the specified image.
2087 % The format of the GetPixelCachePixels() method is:
2089 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2090 % ExceptionInfo *exception)
2092 % A description of each parameter follows:
2094 % o image: the image.
2096 % o length: the pixel cache length.
2098 % o exception: return any errors or warnings in this structure.
2101 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2102 ExceptionInfo *exception)
2105 *restrict cache_info;
2107 assert(image != (const Image *) NULL);
2108 assert(image->signature == MagickSignature);
2109 assert(image->cache != (Cache) NULL);
2110 assert(length != (MagickSizeType *) NULL);
2111 assert(exception != (ExceptionInfo *) NULL);
2112 assert(exception->signature == MagickSignature);
2113 cache_info=(CacheInfo *) image->cache;
2114 assert(cache_info->signature == MagickSignature);
2116 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2117 return((void *) NULL);
2118 *length=cache_info->length;
2119 return((void *) cache_info->pixels);
2123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2127 + 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 %
2131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2133 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2135 % The format of the GetPixelCacheStorageClass() method is:
2137 % ClassType GetPixelCacheStorageClass(Cache cache)
2139 % A description of each parameter follows:
2141 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2143 % o cache: the pixel cache.
2146 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2149 *restrict cache_info;
2151 assert(cache != (Cache) NULL);
2152 cache_info=(CacheInfo *) cache;
2153 assert(cache_info->signature == MagickSignature);
2154 if (cache_info->debug != MagickFalse)
2155 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2156 cache_info->filename);
2157 return(cache_info->storage_class);
2161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2165 + G e t P i x e l C a c h e T i l e S i z e %
2169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2171 % GetPixelCacheTileSize() returns the pixel cache tile size.
2173 % The format of the GetPixelCacheTileSize() method is:
2175 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2178 % A description of each parameter follows:
2180 % o image: the image.
2182 % o width: the optimize cache tile width in pixels.
2184 % o height: the optimize cache tile height in pixels.
2187 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2191 *restrict cache_info;
2193 assert(image != (Image *) NULL);
2194 assert(image->signature == MagickSignature);
2195 if (image->debug != MagickFalse)
2196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2197 cache_info=(CacheInfo *) image->cache;
2198 assert(cache_info->signature == MagickSignature);
2199 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2200 if (GetImagePixelCacheType(image) == DiskCache)
2201 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2210 + 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 %
2214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2217 % pixel cache. A virtual pixel is any pixel access that is outside the
2218 % boundaries of the image cache.
2220 % The format of the GetPixelCacheVirtualMethod() method is:
2222 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2224 % A description of each parameter follows:
2226 % o image: the image.
2229 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2232 *restrict cache_info;
2234 assert(image != (Image *) NULL);
2235 assert(image->signature == MagickSignature);
2236 assert(image->cache != (Cache) NULL);
2237 cache_info=(CacheInfo *) image->cache;
2238 assert(cache_info->signature == MagickSignature);
2239 return(cache_info->virtual_pixel_method);
2243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247 + 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 %
2251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2253 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2254 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2256 % The format of the GetVirtualMetacontentFromCache() method is:
2258 % void *GetVirtualMetacontentFromCache(const Image *image)
2260 % A description of each parameter follows:
2262 % o image: the image.
2265 static const void *GetVirtualMetacontentFromCache(const Image *image)
2268 *restrict cache_info;
2271 id = GetOpenMPThreadId();
2274 *restrict metacontent;
2276 assert(image != (const Image *) NULL);
2277 assert(image->signature == MagickSignature);
2278 assert(image->cache != (Cache) NULL);
2279 cache_info=(CacheInfo *) image->cache;
2280 assert(cache_info->signature == MagickSignature);
2281 assert(id < (int) cache_info->number_threads);
2282 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2283 cache_info->nexus_info[id]);
2284 return(metacontent);
2288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2292 + 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 %
2296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2298 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2301 % The format of the GetVirtualMetacontentFromNexus() method is:
2303 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2304 % NexusInfo *nexus_info)
2306 % A description of each parameter follows:
2308 % o cache: the pixel cache.
2310 % o nexus_info: the cache nexus to return the meta-content.
2313 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2314 NexusInfo *restrict nexus_info)
2317 *restrict cache_info;
2319 assert(cache != (Cache) NULL);
2320 cache_info=(CacheInfo *) cache;
2321 assert(cache_info->signature == MagickSignature);
2322 if (cache_info->storage_class == UndefinedClass)
2323 return((void *) NULL);
2324 return(nexus_info->metacontent);
2328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2332 % G e t V i r t u a l M e t a c o n t e n t %
2336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2338 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2339 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2340 % returned if the meta-content are not available.
2342 % The format of the GetVirtualMetacontent() method is:
2344 % const void *GetVirtualMetacontent(const Image *image)
2346 % A description of each parameter follows:
2348 % o image: the image.
2351 MagickExport const void *GetVirtualMetacontent(const Image *image)
2354 *restrict cache_info;
2357 id = GetOpenMPThreadId();
2360 *restrict metacontent;
2362 assert(image != (const Image *) NULL);
2363 assert(image->signature == MagickSignature);
2364 assert(image->cache != (Cache) NULL);
2365 cache_info=(CacheInfo *) image->cache;
2366 assert(cache_info->signature == MagickSignature);
2367 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2368 if (metacontent != (void *) NULL)
2369 return(metacontent);
2370 assert(id < (int) cache_info->number_threads);
2371 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2372 cache_info->nexus_info[id]);
2373 return(metacontent);
2377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381 + 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 %
2385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2387 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2388 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2389 % is returned if the pixels are transferred, otherwise a NULL is returned.
2391 % The format of the GetVirtualPixelsFromNexus() method is:
2393 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2394 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2395 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2396 % ExceptionInfo *exception)
2398 % A description of each parameter follows:
2400 % o image: the image.
2402 % o virtual_pixel_method: the virtual pixel method.
2404 % o x,y,columns,rows: These values define the perimeter of a region of
2407 % o nexus_info: the cache nexus to acquire.
2409 % o exception: return any errors or warnings in this structure.
2416 0, 48, 12, 60, 3, 51, 15, 63,
2417 32, 16, 44, 28, 35, 19, 47, 31,
2418 8, 56, 4, 52, 11, 59, 7, 55,
2419 40, 24, 36, 20, 43, 27, 39, 23,
2420 2, 50, 14, 62, 1, 49, 13, 61,
2421 34, 18, 46, 30, 33, 17, 45, 29,
2422 10, 58, 6, 54, 9, 57, 5, 53,
2423 42, 26, 38, 22, 41, 25, 37, 21
2426 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2431 index=x+DitherMatrix[x & 0x07]-32L;
2434 if (index >= (ssize_t) columns)
2435 return((ssize_t) columns-1L);
2439 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2444 index=y+DitherMatrix[y & 0x07]-32L;
2447 if (index >= (ssize_t) rows)
2448 return((ssize_t) rows-1L);
2452 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2456 if (x >= (ssize_t) columns)
2457 return((ssize_t) (columns-1));
2461 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2465 if (y >= (ssize_t) rows)
2466 return((ssize_t) (rows-1));
2470 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2472 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2475 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2477 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2480 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2481 const size_t extent)
2487 Compute the remainder of dividing offset by extent. It returns not only
2488 the quotient (tile the offset falls in) but also the positive remainer
2489 within that tile such that 0 <= remainder < extent. This method is
2490 essentially a ldiv() using a floored modulo division rather than the
2491 normal default truncated modulo division.
2493 modulo.quotient=offset/(ssize_t) extent;
2496 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2500 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2501 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2502 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2503 ExceptionInfo *exception)
2506 *restrict cache_info;
2516 **restrict virtual_nexus;
2520 virtual_pixel[MaxPixelChannels];
2525 register const Quantum
2538 register unsigned char
2545 *restrict virtual_metacontent;
2550 assert(image != (const Image *) NULL);
2551 assert(image->signature == MagickSignature);
2552 assert(image->cache != (Cache) NULL);
2553 cache_info=(CacheInfo *) image->cache;
2554 assert(cache_info->signature == MagickSignature);
2555 if (cache_info->type == UndefinedCache)
2556 return((const Quantum *) NULL);
2559 region.width=columns;
2561 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2563 if (pixels == (Quantum *) NULL)
2564 return((const Quantum *) NULL);
2566 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2567 nexus_info->region.x;
2568 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2569 nexus_info->region.width-1L;
2570 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2571 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2572 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2573 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2579 Pixel request is inside cache extents.
2581 if (nexus_info->authentic_pixel_cache != MagickFalse)
2583 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2584 if (status == MagickFalse)
2585 return((const Quantum *) NULL);
2586 if (cache_info->metacontent_extent != 0)
2588 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2589 if (status == MagickFalse)
2590 return((const Quantum *) NULL);
2595 Pixel request is outside cache extents.
2597 s=(unsigned char *) nexus_info->metacontent;
2598 virtual_nexus=AcquirePixelCacheNexus(1);
2599 if (virtual_nexus == (NexusInfo **) NULL)
2601 if (virtual_nexus != (NexusInfo **) NULL)
2602 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2603 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2604 "UnableToGetCacheNexus","`%s'",image->filename);
2605 return((const Quantum *) NULL);
2607 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2608 sizeof(*virtual_pixel));
2609 virtual_metacontent=(void *) NULL;
2610 switch (virtual_pixel_method)
2612 case BackgroundVirtualPixelMethod:
2613 case BlackVirtualPixelMethod:
2614 case GrayVirtualPixelMethod:
2615 case TransparentVirtualPixelMethod:
2616 case MaskVirtualPixelMethod:
2617 case WhiteVirtualPixelMethod:
2618 case EdgeVirtualPixelMethod:
2619 case CheckerTileVirtualPixelMethod:
2620 case HorizontalTileVirtualPixelMethod:
2621 case VerticalTileVirtualPixelMethod:
2623 if (cache_info->metacontent_extent != 0)
2626 Acquire a metacontent buffer.
2628 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2629 cache_info->metacontent_extent);
2630 if (virtual_metacontent == (void *) NULL)
2632 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2633 (void) ThrowMagickException(exception,GetMagickModule(),
2634 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2635 return((const Quantum *) NULL);
2637 (void) ResetMagickMemory(virtual_metacontent,0,
2638 cache_info->metacontent_extent);
2640 switch (virtual_pixel_method)
2642 case BlackVirtualPixelMethod:
2644 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2645 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2646 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2649 case GrayVirtualPixelMethod:
2651 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2652 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2654 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2657 case TransparentVirtualPixelMethod:
2659 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2660 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2661 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2664 case MaskVirtualPixelMethod:
2665 case WhiteVirtualPixelMethod:
2667 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2668 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2669 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2674 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2676 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2678 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2680 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2682 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2692 for (v=0; v < (ssize_t) rows; v++)
2698 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2699 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2700 y_offset=EdgeY(y_offset,cache_info->rows);
2701 for (u=0; u < (ssize_t) columns; u+=length)
2707 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2708 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2709 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2717 Transfer a single pixel.
2719 length=(MagickSizeType) 1;
2720 switch (virtual_pixel_method)
2722 case EdgeVirtualPixelMethod:
2725 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2726 EdgeX(x_offset,cache_info->columns),
2727 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2729 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2732 case RandomVirtualPixelMethod:
2734 if (cache_info->random_info == (RandomInfo *) NULL)
2735 cache_info->random_info=AcquireRandomInfo();
2736 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2737 RandomX(cache_info->random_info,cache_info->columns),
2738 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2739 *virtual_nexus,exception);
2740 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2743 case DitherVirtualPixelMethod:
2745 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2746 DitherX(x_offset,cache_info->columns),
2747 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2749 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2752 case TileVirtualPixelMethod:
2754 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2755 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2756 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2757 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2759 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2762 case MirrorVirtualPixelMethod:
2764 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2765 if ((x_modulo.quotient & 0x01) == 1L)
2766 x_modulo.remainder=(ssize_t) cache_info->columns-
2767 x_modulo.remainder-1L;
2768 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2769 if ((y_modulo.quotient & 0x01) == 1L)
2770 y_modulo.remainder=(ssize_t) cache_info->rows-
2771 y_modulo.remainder-1L;
2772 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2773 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2775 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2778 case HorizontalTileEdgeVirtualPixelMethod:
2780 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2781 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2782 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2783 *virtual_nexus,exception);
2784 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2787 case VerticalTileEdgeVirtualPixelMethod:
2789 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2790 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2791 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2792 *virtual_nexus,exception);
2793 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2796 case BackgroundVirtualPixelMethod:
2797 case BlackVirtualPixelMethod:
2798 case GrayVirtualPixelMethod:
2799 case TransparentVirtualPixelMethod:
2800 case MaskVirtualPixelMethod:
2801 case WhiteVirtualPixelMethod:
2804 r=virtual_metacontent;
2807 case CheckerTileVirtualPixelMethod:
2809 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2810 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2811 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2814 r=virtual_metacontent;
2817 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2818 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2820 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2823 case HorizontalTileVirtualPixelMethod:
2825 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2828 r=virtual_metacontent;
2831 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2832 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2833 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2834 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2836 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2839 case VerticalTileVirtualPixelMethod:
2841 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2844 r=virtual_metacontent;
2847 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2848 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2849 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2850 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2852 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2856 if (p == (const Quantum *) NULL)
2858 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2860 q+=cache_info->number_channels;
2861 if ((s != (void *) NULL) && (r != (const void *) NULL))
2863 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2864 s+=cache_info->metacontent_extent;
2869 Transfer a run of pixels.
2871 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2872 (size_t) length,1UL,*virtual_nexus,exception);
2873 if (p == (const Quantum *) NULL)
2875 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2876 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2877 q+=length*cache_info->number_channels;
2878 if ((r != (void *) NULL) && (s != (const void *) NULL))
2880 (void) memcpy(s,r,(size_t) length);
2881 s+=length*cache_info->metacontent_extent;
2888 if (virtual_metacontent != (void *) NULL)
2889 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2890 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2899 + G e t V i r t u a l P i x e l C a c h e %
2903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2905 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2906 % cache as defined by the geometry parameters. A pointer to the pixels
2907 % is returned if the pixels are transferred, otherwise a NULL is returned.
2909 % The format of the GetVirtualPixelCache() method is:
2911 % const Quantum *GetVirtualPixelCache(const Image *image,
2912 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2913 % const ssize_t y,const size_t columns,const size_t rows,
2914 % ExceptionInfo *exception)
2916 % A description of each parameter follows:
2918 % o image: the image.
2920 % o virtual_pixel_method: the virtual pixel method.
2922 % o x,y,columns,rows: These values define the perimeter of a region of
2925 % o exception: return any errors or warnings in this structure.
2928 static const Quantum *GetVirtualPixelCache(const Image *image,
2929 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2930 const size_t columns,const size_t rows,ExceptionInfo *exception)
2933 *restrict cache_info;
2936 id = GetOpenMPThreadId();
2941 assert(image != (const Image *) NULL);
2942 assert(image->signature == MagickSignature);
2943 assert(image->cache != (Cache) NULL);
2944 cache_info=(CacheInfo *) image->cache;
2945 assert(cache_info->signature == MagickSignature);
2946 assert(id < (int) cache_info->number_threads);
2947 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2948 cache_info->nexus_info[id],exception);
2953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2957 % G e t V i r t u a l P i x e l Q u e u e %
2961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2964 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2966 % The format of the GetVirtualPixelQueue() method is:
2968 % const Quantum *GetVirtualPixelQueue(const Image image)
2970 % A description of each parameter follows:
2972 % o image: the image.
2975 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2978 *restrict cache_info;
2981 id = GetOpenMPThreadId();
2983 assert(image != (const Image *) NULL);
2984 assert(image->signature == MagickSignature);
2985 assert(image->cache != (Cache) NULL);
2986 cache_info=(CacheInfo *) image->cache;
2987 assert(cache_info->signature == MagickSignature);
2988 if (cache_info->methods.get_virtual_pixels_handler !=
2989 (GetVirtualPixelsHandler) NULL)
2990 return(cache_info->methods.get_virtual_pixels_handler(image));
2991 assert(id < (int) cache_info->number_threads);
2992 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3000 % G e t V i r t u a l P i x e l s %
3004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006 % GetVirtualPixels() returns an immutable pixel region. If the
3007 % region is successfully accessed, a pointer to it is returned, otherwise
3008 % NULL is returned. The returned pointer may point to a temporary working
3009 % copy of the pixels or it may point to the original pixels in memory.
3010 % Performance is maximized if the selected region is part of one row, or one
3011 % or more full rows, since there is opportunity to access the pixels in-place
3012 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3013 % returned pointer must *never* be deallocated by the user.
3015 % Pixels accessed via the returned pointer represent a simple array of type
3016 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3017 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3018 % access the meta-content (of type void) corresponding to the the
3021 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3023 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3024 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3025 % GetCacheViewAuthenticPixels() instead.
3027 % The format of the GetVirtualPixels() method is:
3029 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3030 % const ssize_t y,const size_t columns,const size_t rows,
3031 % ExceptionInfo *exception)
3033 % A description of each parameter follows:
3035 % o image: the image.
3037 % o x,y,columns,rows: These values define the perimeter of a region of
3040 % o exception: return any errors or warnings in this structure.
3043 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3044 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3045 ExceptionInfo *exception)
3048 *restrict cache_info;
3051 id = GetOpenMPThreadId();
3056 assert(image != (const Image *) NULL);
3057 assert(image->signature == MagickSignature);
3058 assert(image->cache != (Cache) NULL);
3059 cache_info=(CacheInfo *) image->cache;
3060 assert(cache_info->signature == MagickSignature);
3061 if (cache_info->methods.get_virtual_pixel_handler !=
3062 (GetVirtualPixelHandler) NULL)
3063 return(cache_info->methods.get_virtual_pixel_handler(image,
3064 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3065 assert(id < (int) cache_info->number_threads);
3066 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3067 columns,rows,cache_info->nexus_info[id],exception);
3072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3076 + 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 %
3080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3082 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3083 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3085 % The format of the GetVirtualPixelsCache() method is:
3087 % Quantum *GetVirtualPixelsCache(const Image *image)
3089 % A description of each parameter follows:
3091 % o image: the image.
3094 static const Quantum *GetVirtualPixelsCache(const Image *image)
3097 *restrict cache_info;
3100 id = GetOpenMPThreadId();
3102 assert(image != (const Image *) NULL);
3103 assert(image->signature == MagickSignature);
3104 assert(image->cache != (Cache) NULL);
3105 cache_info=(CacheInfo *) image->cache;
3106 assert(cache_info->signature == MagickSignature);
3107 assert(id < (int) cache_info->number_threads);
3108 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3116 + G e t V i r t u a l P i x e l s N e x u s %
3120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3122 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3125 % The format of the GetVirtualPixelsNexus() method is:
3127 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3128 % NexusInfo *nexus_info)
3130 % A description of each parameter follows:
3132 % o cache: the pixel cache.
3134 % o nexus_info: the cache nexus to return the colormap pixels.
3137 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3138 NexusInfo *restrict nexus_info)
3141 *restrict cache_info;
3143 assert(cache != (Cache) NULL);
3144 cache_info=(CacheInfo *) cache;
3145 assert(cache_info->signature == MagickSignature);
3146 if (cache_info->storage_class == UndefinedClass)
3147 return((Quantum *) NULL);
3148 return((const Quantum *) nexus_info->pixels);
3152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3156 + O p e n P i x e l C a c h e %
3160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3162 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3163 % dimensions, allocating space for the image pixels and optionally the
3164 % metacontent, and memory mapping the cache if it is disk based. The cache
3165 % nexus array is initialized as well.
3167 % The format of the OpenPixelCache() method is:
3169 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3170 % ExceptionInfo *exception)
3172 % A description of each parameter follows:
3174 % o image: the image.
3176 % o mode: ReadMode, WriteMode, or IOMode.
3178 % o exception: return any errors or warnings in this structure.
3182 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3184 cache_info->mapped=MagickFalse;
3185 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3186 (size_t) cache_info->length));
3187 if (cache_info->pixels == (Quantum *) NULL)
3189 cache_info->mapped=MagickTrue;
3190 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3191 cache_info->length);
3195 #if defined(__cplusplus) || defined(c_plusplus)
3200 static void CacheSignalHandler(int status)
3202 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3206 #if defined(__cplusplus) || defined(c_plusplus)
3210 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3217 Open pixel cache on disk.
3219 if (cache_info->file != -1)
3220 return(MagickTrue); /* cache already open */
3221 if (*cache_info->cache_filename == '\0')
3222 file=AcquireUniqueFileResource(cache_info->cache_filename);
3228 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3233 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3234 O_BINARY | O_EXCL,S_MODE);
3236 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3242 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3245 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3250 return(MagickFalse);
3251 (void) AcquireMagickResource(FileResource,1);
3252 cache_info->file=file;
3253 cache_info->mode=mode;
3257 static inline MagickOffsetType WritePixelCacheRegion(
3258 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3259 const MagickSizeType length,const unsigned char *restrict buffer)
3261 register MagickOffsetType
3267 #if !defined(MAGICKCORE_HAVE_PWRITE)
3268 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3269 return((MagickOffsetType) -1);
3272 for (i=0; i < (MagickOffsetType) length; i+=count)
3274 #if !defined(MAGICKCORE_HAVE_PWRITE)
3275 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3276 (MagickSizeType) SSIZE_MAX));
3278 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3279 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3291 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3294 *restrict cache_info;
3301 cache_info=(CacheInfo *) image->cache;
3302 if (image->debug != MagickFalse)
3305 format[MaxTextExtent],
3306 message[MaxTextExtent];
3308 (void) FormatMagickSize(length,MagickFalse,format);
3309 (void) FormatLocaleString(message,MaxTextExtent,
3310 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3311 cache_info->cache_filename,cache_info->file,format);
3312 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3314 if (length != (MagickSizeType) ((MagickOffsetType) length))
3315 return(MagickFalse);
3316 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3318 return(MagickFalse);
3319 if ((MagickSizeType) offset >= length)
3321 extent=(MagickOffsetType) length-1;
3322 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3323 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3324 if (cache_info->synchronize != MagickFalse)
3329 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3331 return(MagickFalse);
3335 (void) signal(SIGBUS,CacheSignalHandler);
3337 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3340 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3341 ExceptionInfo *exception)
3344 *restrict cache_info,
3348 format[MaxTextExtent],
3349 message[MaxTextExtent];
3365 assert(image != (const Image *) NULL);
3366 assert(image->signature == MagickSignature);
3367 assert(image->cache != (Cache) NULL);
3368 if (image->debug != MagickFalse)
3369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3370 if ((image->columns == 0) || (image->rows == 0))
3371 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3372 cache_info=(CacheInfo *) image->cache;
3373 assert(cache_info->signature == MagickSignature);
3374 source_info=(*cache_info);
3375 source_info.file=(-1);
3376 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3377 image->filename,(double) GetImageIndexInList(image));
3378 cache_info->storage_class=image->storage_class;
3379 cache_info->colorspace=image->colorspace;
3380 cache_info->alpha_trait=image->alpha_trait;
3381 cache_info->read_mask=image->read_mask;
3382 cache_info->write_mask=image->write_mask;
3383 cache_info->rows=image->rows;
3384 cache_info->columns=image->columns;
3385 InitializePixelChannelMap(image);
3386 cache_info->number_channels=GetPixelChannels(image);
3387 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3388 sizeof(*image->channel_map));
3389 cache_info->metacontent_extent=image->metacontent_extent;
3390 cache_info->mode=mode;
3391 if (image->ping != MagickFalse)
3393 cache_info->type=PingCache;
3394 cache_info->pixels=(Quantum *) NULL;
3395 cache_info->metacontent=(void *) NULL;
3396 cache_info->length=0;
3399 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3400 packet_size=cache_info->number_channels*sizeof(Quantum);
3401 if (image->metacontent_extent != 0)
3402 packet_size+=cache_info->metacontent_extent;
3403 length=number_pixels*packet_size;
3404 columns=(size_t) (length/cache_info->rows/packet_size);
3405 if (cache_info->columns != columns)
3406 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3408 cache_info->length=length;
3409 status=AcquireMagickResource(AreaResource,cache_info->length);
3410 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3411 cache_info->metacontent_extent);
3412 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3414 status=AcquireMagickResource(MemoryResource,cache_info->length);
3415 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3416 (cache_info->type == MemoryCache))
3418 AllocatePixelCachePixels(cache_info);
3419 if (cache_info->pixels == (Quantum *) NULL)
3420 cache_info->pixels=source_info.pixels;
3424 Create memory pixel cache.
3427 cache_info->type=MemoryCache;
3428 cache_info->metacontent=(void *) NULL;
3429 if (cache_info->metacontent_extent != 0)
3430 cache_info->metacontent=(void *) (cache_info->pixels+
3431 number_pixels*cache_info->number_channels);
3432 if ((source_info.storage_class != UndefinedClass) &&
3435 status=ClonePixelCacheRepository(cache_info,&source_info,
3437 RelinquishPixelCachePixels(&source_info);
3439 if (image->debug != MagickFalse)
3441 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3442 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3444 (void) FormatLocaleString(message,MaxTextExtent,
3445 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3446 cache_info->filename,cache_info->mapped != MagickFalse ?
3447 "Anonymous" : "Heap",type,(double) cache_info->columns,
3448 (double) cache_info->rows,(double)
3449 cache_info->number_channels,format);
3450 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3456 RelinquishMagickResource(MemoryResource,cache_info->length);
3459 Create pixel cache on disk.
3461 status=AcquireMagickResource(DiskResource,cache_info->length);
3462 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3467 if (cache_info->type == DistributedCache)
3468 RelinquishMagickResource(DiskResource,cache_info->length);
3469 server_info=AcquireDistributeCacheInfo(exception);
3470 if (server_info != (DistributeCacheInfo *) NULL)
3472 status=OpenDistributePixelCache(server_info,image);
3473 if (status == MagickFalse)
3475 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3476 GetDistributeCacheHostname(server_info));
3477 server_info=DestroyDistributeCacheInfo(server_info);
3482 Create a distributed pixel cache.
3484 cache_info->type=DistributedCache;
3485 cache_info->server_info=server_info;
3486 (void) FormatLocaleString(cache_info->cache_filename,
3487 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3488 (DistributeCacheInfo *) cache_info->server_info),
3489 GetDistributeCachePort((DistributeCacheInfo *)
3490 cache_info->server_info));
3491 if ((source_info.storage_class != UndefinedClass) &&
3494 status=ClonePixelCacheRepository(cache_info,&source_info,
3496 RelinquishPixelCachePixels(&source_info);
3498 if (image->debug != MagickFalse)
3500 (void) FormatMagickSize(cache_info->length,MagickFalse,
3502 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3504 (void) FormatLocaleString(message,MaxTextExtent,
3505 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3506 cache_info->filename,cache_info->cache_filename,
3507 GetDistributeCacheFile((DistributeCacheInfo *)
3508 cache_info->server_info),type,(double) cache_info->columns,
3509 (double) cache_info->rows,(double)
3510 cache_info->number_channels,format);
3511 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3517 RelinquishMagickResource(DiskResource,cache_info->length);
3518 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3519 "CacheResourcesExhausted","`%s'",image->filename);
3520 return(MagickFalse);
3522 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3524 (void) ClosePixelCacheOnDisk(cache_info);
3525 *cache_info->cache_filename='\0';
3527 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3529 RelinquishMagickResource(DiskResource,cache_info->length);
3530 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3532 return(MagickFalse);
3534 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3535 cache_info->length);
3536 if (status == MagickFalse)
3538 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3540 return(MagickFalse);
3542 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3543 cache_info->metacontent_extent);
3544 if (length != (MagickSizeType) ((size_t) length))
3545 cache_info->type=DiskCache;
3548 status=AcquireMagickResource(MapResource,cache_info->length);
3549 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3550 (cache_info->type != MemoryCache))
3551 cache_info->type=DiskCache;
3554 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3555 cache_info->offset,(size_t) cache_info->length);
3556 if (cache_info->pixels == (Quantum *) NULL)
3558 cache_info->type=DiskCache;
3559 cache_info->pixels=source_info.pixels;
3564 Create file-backed memory-mapped pixel cache.
3567 (void) ClosePixelCacheOnDisk(cache_info);
3568 cache_info->type=MapCache;
3569 cache_info->mapped=MagickTrue;
3570 cache_info->metacontent=(void *) NULL;
3571 if (cache_info->metacontent_extent != 0)
3572 cache_info->metacontent=(void *) (cache_info->pixels+
3573 number_pixels*cache_info->number_channels);
3574 if ((source_info.storage_class != UndefinedClass) &&
3577 status=ClonePixelCacheRepository(cache_info,&source_info,
3579 RelinquishPixelCachePixels(&source_info);
3581 if (image->debug != MagickFalse)
3583 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3584 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3586 (void) FormatLocaleString(message,MaxTextExtent,
3587 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3588 cache_info->filename,cache_info->cache_filename,
3589 cache_info->file,type,(double) cache_info->columns,(double)
3590 cache_info->rows,(double) cache_info->number_channels,
3592 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3598 RelinquishMagickResource(MapResource,cache_info->length);
3601 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3603 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3604 RelinquishPixelCachePixels(&source_info);
3606 if (image->debug != MagickFalse)
3608 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3609 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3611 (void) FormatLocaleString(message,MaxTextExtent,
3612 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3613 cache_info->cache_filename,cache_info->file,type,(double)
3614 cache_info->columns,(double) cache_info->rows,(double)
3615 cache_info->number_channels,format);
3616 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3626 + P e r s i s t P i x e l C a c h e %
3630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3632 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3633 % persistent pixel cache is one that resides on disk and is not destroyed
3634 % when the program exits.
3636 % The format of the PersistPixelCache() method is:
3638 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3639 % const MagickBooleanType attach,MagickOffsetType *offset,
3640 % ExceptionInfo *exception)
3642 % A description of each parameter follows:
3644 % o image: the image.
3646 % o filename: the persistent pixel cache filename.
3648 % o attach: A value other than zero initializes the persistent pixel cache.
3650 % o initialize: A value other than zero initializes the persistent pixel
3653 % o offset: the offset in the persistent cache to store pixels.
3655 % o exception: return any errors or warnings in this structure.
3658 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3659 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3660 ExceptionInfo *exception)
3663 *restrict cache_info,
3664 *restrict clone_info;
3675 assert(image != (Image *) NULL);
3676 assert(image->signature == MagickSignature);
3677 if (image->debug != MagickFalse)
3678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3679 assert(image->cache != (void *) NULL);
3680 assert(filename != (const char *) NULL);
3681 assert(offset != (MagickOffsetType *) NULL);
3682 page_size=GetMagickPageSize();
3683 cache_info=(CacheInfo *) image->cache;
3684 assert(cache_info->signature == MagickSignature);
3685 if (attach != MagickFalse)
3688 Attach existing persistent pixel cache.
3690 if (image->debug != MagickFalse)
3691 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3692 "attach persistent cache");
3693 (void) CopyMagickString(cache_info->cache_filename,filename,
3695 cache_info->type=DiskCache;
3696 cache_info->offset=(*offset);
3697 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3698 return(MagickFalse);
3699 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3702 if ((cache_info->mode != ReadMode) &&
3703 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3704 (cache_info->reference_count == 1))
3706 LockSemaphoreInfo(cache_info->semaphore);
3707 if ((cache_info->mode != ReadMode) &&
3708 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3709 (cache_info->reference_count == 1))
3715 Usurp existing persistent pixel cache.
3717 status=rename_utf8(cache_info->cache_filename,filename);
3720 (void) CopyMagickString(cache_info->cache_filename,filename,
3722 *offset+=cache_info->length+page_size-(cache_info->length %
3724 UnlockSemaphoreInfo(cache_info->semaphore);
3725 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3726 if (image->debug != MagickFalse)
3727 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3728 "Usurp resident persistent cache");
3732 UnlockSemaphoreInfo(cache_info->semaphore);
3735 Clone persistent pixel cache.
3737 clone_image=(*image);
3738 clone_info=(CacheInfo *) clone_image.cache;
3739 image->cache=ClonePixelCache(cache_info);
3740 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3741 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3742 cache_info->type=DiskCache;
3743 cache_info->offset=(*offset);
3744 cache_info=(CacheInfo *) image->cache;
3745 status=OpenPixelCache(image,IOMode,exception);
3746 if (status != MagickFalse)
3747 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3748 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3749 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3758 + 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 %
3762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3764 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3765 % defined by the region rectangle and returns a pointer to the region. This
3766 % region is subsequently transferred from the pixel cache with
3767 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3768 % pixels are transferred, otherwise a NULL is returned.
3770 % The format of the QueueAuthenticPixelCacheNexus() method is:
3772 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3773 % const ssize_t y,const size_t columns,const size_t rows,
3774 % const MagickBooleanType clone,NexusInfo *nexus_info,
3775 % ExceptionInfo *exception)
3777 % A description of each parameter follows:
3779 % o image: the image.
3781 % o x,y,columns,rows: These values define the perimeter of a region of
3784 % o nexus_info: the cache nexus to set.
3786 % o clone: clone the pixel cache.
3788 % o exception: return any errors or warnings in this structure.
3791 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3792 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3793 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3796 *restrict cache_info;
3811 Validate pixel cache geometry.
3813 assert(image != (const Image *) NULL);
3814 assert(image->signature == MagickSignature);
3815 assert(image->cache != (Cache) NULL);
3816 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3817 if (cache_info == (Cache) NULL)
3818 return((Quantum *) NULL);
3819 assert(cache_info->signature == MagickSignature);
3820 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3821 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3822 (y >= (ssize_t) cache_info->rows))
3824 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3825 "PixelsAreNotAuthentic","`%s'",image->filename);
3826 return((Quantum *) NULL);
3828 offset=(MagickOffsetType) y*cache_info->columns+x;
3830 return((Quantum *) NULL);
3831 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3832 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3833 if ((MagickSizeType) offset >= number_pixels)
3834 return((Quantum *) NULL);
3840 region.width=columns;
3842 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3852 + 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 %
3856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3858 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3859 % defined by the region rectangle and returns a pointer to the region. This
3860 % region is subsequently transferred from the pixel cache with
3861 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3862 % pixels are transferred, otherwise a NULL is returned.
3864 % The format of the QueueAuthenticPixelsCache() method is:
3866 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3867 % const ssize_t y,const size_t columns,const size_t rows,
3868 % ExceptionInfo *exception)
3870 % A description of each parameter follows:
3872 % o image: the image.
3874 % o x,y,columns,rows: These values define the perimeter of a region of
3877 % o exception: return any errors or warnings in this structure.
3880 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3881 const ssize_t y,const size_t columns,const size_t rows,
3882 ExceptionInfo *exception)
3885 *restrict cache_info;
3888 id = GetOpenMPThreadId();
3893 assert(image != (const Image *) NULL);
3894 assert(image->signature == MagickSignature);
3895 assert(image->cache != (Cache) NULL);
3896 cache_info=(CacheInfo *) image->cache;
3897 assert(cache_info->signature == MagickSignature);
3898 assert(id < (int) cache_info->number_threads);
3899 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3900 cache_info->nexus_info[id],exception);
3905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3909 % Q u e u e A u t h e n t i c P i x e l s %
3913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3915 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3916 % successfully initialized a pointer to a Quantum array representing the
3917 % region is returned, otherwise NULL is returned. The returned pointer may
3918 % point to a temporary working buffer for the pixels or it may point to the
3919 % final location of the pixels in memory.
3921 % Write-only access means that any existing pixel values corresponding to
3922 % the region are ignored. This is useful if the initial image is being
3923 % created from scratch, or if the existing pixel values are to be
3924 % completely replaced without need to refer to their pre-existing values.
3925 % The application is free to read and write the pixel buffer returned by
3926 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3927 % initialize the pixel array values. Initializing pixel array values is the
3928 % application's responsibility.
3930 % Performance is maximized if the selected region is part of one row, or
3931 % one or more full rows, since then there is opportunity to access the
3932 % pixels in-place (without a copy) if the image is in memory, or in a
3933 % memory-mapped file. The returned pointer must *never* be deallocated
3936 % Pixels accessed via the returned pointer represent a simple array of type
3937 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3938 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3939 % obtain the meta-content (of type void) corresponding to the region.
3940 % Once the Quantum (and/or Quantum) array has been updated, the
3941 % changes must be saved back to the underlying image using
3942 % SyncAuthenticPixels() or they may be lost.
3944 % The format of the QueueAuthenticPixels() method is:
3946 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3947 % const ssize_t y,const size_t columns,const size_t rows,
3948 % ExceptionInfo *exception)
3950 % A description of each parameter follows:
3952 % o image: the image.
3954 % o x,y,columns,rows: These values define the perimeter of a region of
3957 % o exception: return any errors or warnings in this structure.
3960 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3961 const ssize_t y,const size_t columns,const size_t rows,
3962 ExceptionInfo *exception)
3965 *restrict cache_info;
3968 id = GetOpenMPThreadId();
3973 assert(image != (Image *) NULL);
3974 assert(image->signature == MagickSignature);
3975 assert(image->cache != (Cache) NULL);
3976 cache_info=(CacheInfo *) image->cache;
3977 assert(cache_info->signature == MagickSignature);
3978 if (cache_info->methods.queue_authentic_pixels_handler !=
3979 (QueueAuthenticPixelsHandler) NULL)
3981 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3982 columns,rows,exception);
3985 assert(id < (int) cache_info->number_threads);
3986 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3987 cache_info->nexus_info[id],exception);
3992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3996 + 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 %
4000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4002 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4005 % The format of the ReadPixelCacheMetacontent() method is:
4007 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4008 % NexusInfo *nexus_info,ExceptionInfo *exception)
4010 % A description of each parameter follows:
4012 % o cache_info: the pixel cache.
4014 % o nexus_info: the cache nexus to read the metacontent.
4016 % o exception: return any errors or warnings in this structure.
4020 static inline MagickOffsetType ReadPixelCacheRegion(
4021 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4022 const MagickSizeType length,unsigned char *restrict buffer)
4024 register MagickOffsetType
4030 #if !defined(MAGICKCORE_HAVE_PREAD)
4031 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4032 return((MagickOffsetType) -1);
4035 for (i=0; i < (MagickOffsetType) length; i+=count)
4037 #if !defined(MAGICKCORE_HAVE_PREAD)
4038 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4039 (MagickSizeType) SSIZE_MAX));
4041 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4042 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4054 static MagickBooleanType ReadPixelCacheMetacontent(
4055 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4056 ExceptionInfo *exception)
4069 register unsigned char
4075 if (cache_info->metacontent_extent == 0)
4076 return(MagickFalse);
4077 if (nexus_info->authentic_pixel_cache != MagickFalse)
4079 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4080 nexus_info->region.x;
4081 length=(MagickSizeType) nexus_info->region.width*
4082 cache_info->metacontent_extent;
4083 extent=length*nexus_info->region.height;
4084 rows=nexus_info->region.height;
4086 q=(unsigned char *) nexus_info->metacontent;
4087 switch (cache_info->type)
4092 register unsigned char
4096 Read meta-content from memory.
4098 if ((cache_info->columns == nexus_info->region.width) &&
4099 (extent == (MagickSizeType) ((size_t) extent)))
4104 p=(unsigned char *) cache_info->metacontent+offset*
4105 cache_info->metacontent_extent;
4106 for (y=0; y < (ssize_t) rows; y++)
4108 (void) memcpy(q,p,(size_t) length);
4109 p+=cache_info->metacontent_extent*cache_info->columns;
4110 q+=cache_info->metacontent_extent*nexus_info->region.width;
4117 Read meta content from disk.
4119 LockSemaphoreInfo(cache_info->file_semaphore);
4120 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4122 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4123 cache_info->cache_filename);
4124 UnlockSemaphoreInfo(cache_info->file_semaphore);
4125 return(MagickFalse);
4127 if ((cache_info->columns == nexus_info->region.width) &&
4128 (extent <= MagickMaxBufferExtent))
4133 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4134 for (y=0; y < (ssize_t) rows; y++)
4136 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4137 cache_info->number_channels*sizeof(Quantum)+offset*
4138 cache_info->metacontent_extent,length,(unsigned char *) q);
4139 if (count != (MagickOffsetType) length)
4141 offset+=cache_info->columns;
4142 q+=cache_info->metacontent_extent*nexus_info->region.width;
4144 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4145 (void) ClosePixelCacheOnDisk(cache_info);
4146 UnlockSemaphoreInfo(cache_info->file_semaphore);
4149 case DistributedCache:
4155 Read metacontent from distributed cache.
4157 LockSemaphoreInfo(cache_info->file_semaphore);
4158 region=nexus_info->region;
4159 if ((cache_info->columns != nexus_info->region.width) ||
4160 (extent > MagickMaxBufferExtent))
4167 for (y=0; y < (ssize_t) rows; y++)
4169 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4170 cache_info->server_info,®ion,length,(unsigned char *) q);
4171 if (count != (MagickOffsetType) length)
4173 q+=cache_info->metacontent_extent*nexus_info->region.width;
4176 UnlockSemaphoreInfo(cache_info->file_semaphore);
4182 if (y < (ssize_t) rows)
4184 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4185 cache_info->cache_filename);
4186 return(MagickFalse);
4188 if ((cache_info->debug != MagickFalse) &&
4189 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4190 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4191 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4192 nexus_info->region.width,(double) nexus_info->region.height,(double)
4193 nexus_info->region.x,(double) nexus_info->region.y);
4198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4202 + R e a d P i x e l C a c h e P i x e l s %
4206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4208 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4211 % The format of the ReadPixelCachePixels() method is:
4213 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4214 % NexusInfo *nexus_info,ExceptionInfo *exception)
4216 % A description of each parameter follows:
4218 % o cache_info: the pixel cache.
4220 % o nexus_info: the cache nexus to read the pixels.
4222 % o exception: return any errors or warnings in this structure.
4225 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4226 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4245 if (nexus_info->authentic_pixel_cache != MagickFalse)
4247 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4248 nexus_info->region.x;
4249 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4251 extent=length*nexus_info->region.height;
4252 rows=nexus_info->region.height;
4254 q=nexus_info->pixels;
4255 switch (cache_info->type)
4264 Read pixels from memory.
4266 if ((cache_info->columns == nexus_info->region.width) &&
4267 (extent == (MagickSizeType) ((size_t) extent)))
4272 p=cache_info->pixels+offset*cache_info->number_channels;
4273 for (y=0; y < (ssize_t) rows; y++)
4275 (void) memcpy(q,p,(size_t) length);
4276 p+=cache_info->number_channels*cache_info->columns;
4277 q+=cache_info->number_channels*nexus_info->region.width;
4284 Read pixels from disk.
4286 LockSemaphoreInfo(cache_info->file_semaphore);
4287 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4289 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4290 cache_info->cache_filename);
4291 UnlockSemaphoreInfo(cache_info->file_semaphore);
4292 return(MagickFalse);
4294 if ((cache_info->columns == nexus_info->region.width) &&
4295 (extent <= MagickMaxBufferExtent))
4300 for (y=0; y < (ssize_t) rows; y++)
4302 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4303 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4304 if (count != (MagickOffsetType) length)
4306 offset+=cache_info->columns;
4307 q+=cache_info->number_channels*nexus_info->region.width;
4309 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4310 (void) ClosePixelCacheOnDisk(cache_info);
4311 UnlockSemaphoreInfo(cache_info->file_semaphore);
4314 case DistributedCache:
4320 Read pixels from distributed cache.
4322 LockSemaphoreInfo(cache_info->file_semaphore);
4323 region=nexus_info->region;
4324 if ((cache_info->columns != nexus_info->region.width) ||
4325 (extent > MagickMaxBufferExtent))
4332 for (y=0; y < (ssize_t) rows; y++)
4334 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4335 cache_info->server_info,®ion,length,(unsigned char *) q);
4336 if (count != (MagickOffsetType) length)
4338 q+=cache_info->number_channels*nexus_info->region.width;
4341 UnlockSemaphoreInfo(cache_info->file_semaphore);
4347 if (y < (ssize_t) rows)
4349 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4350 cache_info->cache_filename);
4351 return(MagickFalse);
4353 if ((cache_info->debug != MagickFalse) &&
4354 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4355 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4356 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4357 nexus_info->region.width,(double) nexus_info->region.height,(double)
4358 nexus_info->region.x,(double) nexus_info->region.y);
4363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4367 + R e f e r e n c e P i x e l C a c h e %
4371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4373 % ReferencePixelCache() increments the reference count associated with the
4374 % pixel cache returning a pointer to the cache.
4376 % The format of the ReferencePixelCache method is:
4378 % Cache ReferencePixelCache(Cache cache_info)
4380 % A description of each parameter follows:
4382 % o cache_info: the pixel cache.
4385 MagickPrivate Cache ReferencePixelCache(Cache cache)
4388 *restrict cache_info;
4390 assert(cache != (Cache *) NULL);
4391 cache_info=(CacheInfo *) cache;
4392 assert(cache_info->signature == MagickSignature);
4393 LockSemaphoreInfo(cache_info->semaphore);
4394 cache_info->reference_count++;
4395 UnlockSemaphoreInfo(cache_info->semaphore);
4400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4404 + S e t P i x e l C a c h e M e t h o d s %
4408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4410 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4412 % The format of the SetPixelCacheMethods() method is:
4414 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4416 % A description of each parameter follows:
4418 % o cache: the pixel cache.
4420 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4423 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4426 *restrict cache_info;
4428 GetOneAuthenticPixelFromHandler
4429 get_one_authentic_pixel_from_handler;
4431 GetOneVirtualPixelFromHandler
4432 get_one_virtual_pixel_from_handler;
4435 Set cache pixel methods.
4437 assert(cache != (Cache) NULL);
4438 assert(cache_methods != (CacheMethods *) NULL);
4439 cache_info=(CacheInfo *) cache;
4440 assert(cache_info->signature == MagickSignature);
4441 if (cache_info->debug != MagickFalse)
4442 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4443 cache_info->filename);
4444 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4445 cache_info->methods.get_virtual_pixel_handler=
4446 cache_methods->get_virtual_pixel_handler;
4447 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4448 cache_info->methods.destroy_pixel_handler=
4449 cache_methods->destroy_pixel_handler;
4450 if (cache_methods->get_virtual_metacontent_from_handler !=
4451 (GetVirtualMetacontentFromHandler) NULL)
4452 cache_info->methods.get_virtual_metacontent_from_handler=
4453 cache_methods->get_virtual_metacontent_from_handler;
4454 if (cache_methods->get_authentic_pixels_handler !=
4455 (GetAuthenticPixelsHandler) NULL)
4456 cache_info->methods.get_authentic_pixels_handler=
4457 cache_methods->get_authentic_pixels_handler;
4458 if (cache_methods->queue_authentic_pixels_handler !=
4459 (QueueAuthenticPixelsHandler) NULL)
4460 cache_info->methods.queue_authentic_pixels_handler=
4461 cache_methods->queue_authentic_pixels_handler;
4462 if (cache_methods->sync_authentic_pixels_handler !=
4463 (SyncAuthenticPixelsHandler) NULL)
4464 cache_info->methods.sync_authentic_pixels_handler=
4465 cache_methods->sync_authentic_pixels_handler;
4466 if (cache_methods->get_authentic_pixels_from_handler !=
4467 (GetAuthenticPixelsFromHandler) NULL)
4468 cache_info->methods.get_authentic_pixels_from_handler=
4469 cache_methods->get_authentic_pixels_from_handler;
4470 if (cache_methods->get_authentic_metacontent_from_handler !=
4471 (GetAuthenticMetacontentFromHandler) NULL)
4472 cache_info->methods.get_authentic_metacontent_from_handler=
4473 cache_methods->get_authentic_metacontent_from_handler;
4474 get_one_virtual_pixel_from_handler=
4475 cache_info->methods.get_one_virtual_pixel_from_handler;
4476 if (get_one_virtual_pixel_from_handler !=
4477 (GetOneVirtualPixelFromHandler) NULL)
4478 cache_info->methods.get_one_virtual_pixel_from_handler=
4479 cache_methods->get_one_virtual_pixel_from_handler;
4480 get_one_authentic_pixel_from_handler=
4481 cache_methods->get_one_authentic_pixel_from_handler;
4482 if (get_one_authentic_pixel_from_handler !=
4483 (GetOneAuthenticPixelFromHandler) NULL)
4484 cache_info->methods.get_one_authentic_pixel_from_handler=
4485 cache_methods->get_one_authentic_pixel_from_handler;
4489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493 + S e t P i x e l C a c h e N e x u s P i x e l s %
4497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4499 % SetPixelCacheNexusPixels() defines the region of the cache for the
4500 % specified cache nexus.
4502 % The format of the SetPixelCacheNexusPixels() method is:
4504 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4505 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4506 % ExceptionInfo *exception)
4508 % A description of each parameter follows:
4510 % o cache_info: the pixel cache.
4512 % o mode: ReadMode, WriteMode, or IOMode.
4514 % o region: A pointer to the RectangleInfo structure that defines the
4515 % region of this particular cache nexus.
4517 % o nexus_info: the cache nexus to set.
4519 % o exception: return any errors or warnings in this structure.
4523 static inline MagickBooleanType AcquireCacheNexusPixels(
4524 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4525 ExceptionInfo *exception)
4527 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4528 return(MagickFalse);
4529 nexus_info->mapped=MagickFalse;
4530 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4531 (size_t) nexus_info->length));
4532 if (nexus_info->cache == (Quantum *) NULL)
4534 nexus_info->mapped=MagickTrue;
4535 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4536 nexus_info->length);
4538 if (nexus_info->cache == (Quantum *) NULL)
4540 (void) ThrowMagickException(exception,GetMagickModule(),
4541 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4542 cache_info->filename);
4543 return(MagickFalse);
4548 static inline MagickBooleanType IsPixelCacheAuthentic(
4549 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4558 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4560 if (cache_info->type == PingCache)
4562 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4563 nexus_info->region.x;
4564 status=nexus_info->pixels == (cache_info->pixels+offset*
4565 cache_info->number_channels) ? MagickTrue : MagickFalse;
4569 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4572 if (mode == ReadMode)
4574 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4577 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4580 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4581 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4582 ExceptionInfo *exception)
4591 assert(cache_info != (const CacheInfo *) NULL);
4592 assert(cache_info->signature == MagickSignature);
4593 if (cache_info->type == UndefinedCache)
4594 return((Quantum *) NULL);
4595 nexus_info->region=(*region);
4596 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4602 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4603 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4604 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4605 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4606 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4607 ((nexus_info->region.width == cache_info->columns) ||
4608 ((nexus_info->region.width % cache_info->columns) == 0)))))
4614 Pixels are accessed directly from memory.
4616 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4617 nexus_info->region.x;
4618 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4620 nexus_info->metacontent=(void *) NULL;
4621 if (cache_info->metacontent_extent != 0)
4622 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4623 offset*cache_info->metacontent_extent;
4624 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4625 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4627 return(nexus_info->pixels);
4631 Pixels are stored in a staging region until they are synced to the cache.
4633 number_pixels=(MagickSizeType) nexus_info->region.width*
4634 nexus_info->region.height;
4635 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4636 if (cache_info->metacontent_extent != 0)
4637 length+=number_pixels*cache_info->metacontent_extent;
4638 if (nexus_info->cache == (Quantum *) NULL)
4640 nexus_info->length=length;
4641 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4642 if (status == MagickFalse)
4644 nexus_info->length=0;
4645 return((Quantum *) NULL);
4649 if (nexus_info->length < length)
4651 RelinquishCacheNexusPixels(nexus_info);
4652 nexus_info->length=length;
4653 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4654 if (status == MagickFalse)
4656 nexus_info->length=0;
4657 return((Quantum *) NULL);
4660 nexus_info->pixels=nexus_info->cache;
4661 nexus_info->metacontent=(void *) NULL;
4662 if (cache_info->metacontent_extent != 0)
4663 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4664 cache_info->number_channels);
4665 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4666 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4668 return(nexus_info->pixels);
4672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4676 % 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 %
4680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4682 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4683 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4684 % access that is outside the boundaries of the image cache.
4686 % The format of the SetPixelCacheVirtualMethod() method is:
4688 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4689 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4691 % A description of each parameter follows:
4693 % o image: the image.
4695 % o virtual_pixel_method: choose the type of virtual pixel.
4697 % o exception: return any errors or warnings in this structure.
4701 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4702 ExceptionInfo *exception)
4705 *restrict cache_info;
4708 *restrict image_view;
4716 assert(image != (Image *) NULL);
4717 assert(image->signature == MagickSignature);
4718 if (image->debug != MagickFalse)
4719 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4720 assert(image->cache != (Cache) NULL);
4721 cache_info=(CacheInfo *) image->cache;
4722 assert(cache_info->signature == MagickSignature);
4723 image->alpha_trait=BlendPixelTrait;
4725 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4726 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4727 #pragma omp parallel for schedule(static,4) shared(status) \
4728 magick_threads(image,image,1,1)
4730 for (y=0; y < (ssize_t) image->rows; y++)
4738 if (status == MagickFalse)
4740 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4741 if (q == (Quantum *) NULL)
4746 for (x=0; x < (ssize_t) image->columns; x++)
4748 SetPixelAlpha(image,alpha,q);
4749 q+=GetPixelChannels(image);
4751 status=SyncCacheViewAuthenticPixels(image_view,exception);
4753 image_view=DestroyCacheView(image_view);
4757 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4758 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4761 *restrict cache_info;
4766 assert(image != (Image *) NULL);
4767 assert(image->signature == MagickSignature);
4768 if (image->debug != MagickFalse)
4769 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4770 assert(image->cache != (Cache) NULL);
4771 cache_info=(CacheInfo *) image->cache;
4772 assert(cache_info->signature == MagickSignature);
4773 method=cache_info->virtual_pixel_method;
4774 cache_info->virtual_pixel_method=virtual_pixel_method;
4775 if ((image->columns != 0) && (image->rows != 0))
4776 switch (virtual_pixel_method)
4778 case BackgroundVirtualPixelMethod:
4780 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4781 (image->alpha_trait != BlendPixelTrait))
4782 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4783 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4784 (IsGrayColorspace(image->colorspace) != MagickFalse))
4785 (void) SetImageColorspace(image,sRGBColorspace,exception);
4788 case TransparentVirtualPixelMethod:
4790 if (image->alpha_trait != BlendPixelTrait)
4791 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4805 + 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 %
4809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4811 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4812 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4813 % is synced, otherwise MagickFalse.
4815 % The format of the SyncAuthenticPixelCacheNexus() method is:
4817 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4818 % NexusInfo *nexus_info,ExceptionInfo *exception)
4820 % A description of each parameter follows:
4822 % o image: the image.
4824 % o nexus_info: the cache nexus to sync.
4826 % o exception: return any errors or warnings in this structure.
4829 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4830 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4833 *restrict cache_info;
4839 Transfer pixels to the cache.
4841 assert(image != (Image *) NULL);
4842 assert(image->signature == MagickSignature);
4843 if (image->cache == (Cache) NULL)
4844 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4845 cache_info=(CacheInfo *) image->cache;
4846 assert(cache_info->signature == MagickSignature);
4847 if (cache_info->type == UndefinedCache)
4848 return(MagickFalse);
4849 if (nexus_info->authentic_pixel_cache != MagickFalse)
4851 assert(cache_info->signature == MagickSignature);
4852 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4853 if ((cache_info->metacontent_extent != 0) &&
4854 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4855 return(MagickFalse);
4860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4864 + S y n c A u t h e n t i c P i x e l C a c h e %
4868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4871 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4872 % otherwise MagickFalse.
4874 % The format of the SyncAuthenticPixelsCache() method is:
4876 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4877 % ExceptionInfo *exception)
4879 % A description of each parameter follows:
4881 % o image: the image.
4883 % o exception: return any errors or warnings in this structure.
4886 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4887 ExceptionInfo *exception)
4890 *restrict cache_info;
4893 id = GetOpenMPThreadId();
4898 assert(image != (Image *) NULL);
4899 assert(image->signature == MagickSignature);
4900 assert(image->cache != (Cache) NULL);
4901 cache_info=(CacheInfo *) image->cache;
4902 assert(cache_info->signature == MagickSignature);
4903 assert(id < (int) cache_info->number_threads);
4904 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4914 % S y n c A u t h e n t i c P i x e l s %
4918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4920 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4921 % The method returns MagickTrue if the pixel region is flushed, otherwise
4924 % The format of the SyncAuthenticPixels() method is:
4926 % MagickBooleanType SyncAuthenticPixels(Image *image,
4927 % ExceptionInfo *exception)
4929 % A description of each parameter follows:
4931 % o image: the image.
4933 % o exception: return any errors or warnings in this structure.
4936 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4937 ExceptionInfo *exception)
4940 *restrict cache_info;
4943 id = GetOpenMPThreadId();
4948 assert(image != (Image *) NULL);
4949 assert(image->signature == MagickSignature);
4950 assert(image->cache != (Cache) NULL);
4951 cache_info=(CacheInfo *) image->cache;
4952 assert(cache_info->signature == MagickSignature);
4953 if (cache_info->methods.sync_authentic_pixels_handler !=
4954 (SyncAuthenticPixelsHandler) NULL)
4956 status=cache_info->methods.sync_authentic_pixels_handler(image,
4960 assert(id < (int) cache_info->number_threads);
4961 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4971 + S y n c I m a g e P i x e l C a c h e %
4975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4977 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4978 % The method returns MagickTrue if the pixel region is flushed, otherwise
4981 % The format of the SyncImagePixelCache() method is:
4983 % MagickBooleanType SyncImagePixelCache(Image *image,
4984 % ExceptionInfo *exception)
4986 % A description of each parameter follows:
4988 % o image: the image.
4990 % o exception: return any errors or warnings in this structure.
4993 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4994 ExceptionInfo *exception)
4997 *restrict cache_info;
4999 assert(image != (Image *) NULL);
5000 assert(exception != (ExceptionInfo *) NULL);
5001 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5002 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5010 + 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 %
5014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5016 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5017 % of the pixel cache.
5019 % The format of the WritePixelCacheMetacontent() method is:
5021 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5022 % NexusInfo *nexus_info,ExceptionInfo *exception)
5024 % A description of each parameter follows:
5026 % o cache_info: the pixel cache.
5028 % o nexus_info: the cache nexus to write the meta-content.
5030 % o exception: return any errors or warnings in this structure.
5033 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5034 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5044 register const unsigned char
5053 if (cache_info->metacontent_extent == 0)
5054 return(MagickFalse);
5055 if (nexus_info->authentic_pixel_cache != MagickFalse)
5057 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5058 nexus_info->region.x;
5059 length=(MagickSizeType) nexus_info->region.width*
5060 cache_info->metacontent_extent;
5061 extent=(MagickSizeType) length*nexus_info->region.height;
5062 rows=nexus_info->region.height;
5064 p=(unsigned char *) nexus_info->metacontent;
5065 switch (cache_info->type)
5070 register unsigned char
5074 Write associated pixels to memory.
5076 if ((cache_info->columns == nexus_info->region.width) &&
5077 (extent == (MagickSizeType) ((size_t) extent)))
5082 q=(unsigned char *) cache_info->metacontent+offset*
5083 cache_info->metacontent_extent;
5084 for (y=0; y < (ssize_t) rows; y++)
5086 (void) memcpy(q,p,(size_t) length);
5087 p+=nexus_info->region.width*cache_info->metacontent_extent;
5088 q+=cache_info->columns*cache_info->metacontent_extent;
5095 Write associated pixels to disk.
5097 LockSemaphoreInfo(cache_info->file_semaphore);
5098 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5100 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5101 cache_info->cache_filename);
5102 UnlockSemaphoreInfo(cache_info->file_semaphore);
5103 return(MagickFalse);
5105 if ((cache_info->columns == nexus_info->region.width) &&
5106 (extent <= MagickMaxBufferExtent))
5111 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5112 for (y=0; y < (ssize_t) rows; y++)
5114 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5115 cache_info->number_channels*sizeof(Quantum)+offset*
5116 cache_info->metacontent_extent,length,(const unsigned char *) p);
5117 if (count != (MagickOffsetType) length)
5119 p+=cache_info->metacontent_extent*nexus_info->region.width;
5120 offset+=cache_info->columns;
5122 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5123 (void) ClosePixelCacheOnDisk(cache_info);
5124 UnlockSemaphoreInfo(cache_info->file_semaphore);
5127 case DistributedCache:
5133 Write metacontent to distributed cache.
5135 LockSemaphoreInfo(cache_info->file_semaphore);
5136 region=nexus_info->region;
5137 if ((cache_info->columns != nexus_info->region.width) ||
5138 (extent > MagickMaxBufferExtent))
5145 for (y=0; y < (ssize_t) rows; y++)
5147 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5148 cache_info->server_info,®ion,length,(const unsigned char *) p);
5149 if (count != (MagickOffsetType) length)
5151 p+=cache_info->metacontent_extent*nexus_info->region.width;
5154 UnlockSemaphoreInfo(cache_info->file_semaphore);
5160 if (y < (ssize_t) rows)
5162 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5163 cache_info->cache_filename);
5164 return(MagickFalse);
5166 if ((cache_info->debug != MagickFalse) &&
5167 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5168 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5169 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5170 nexus_info->region.width,(double) nexus_info->region.height,(double)
5171 nexus_info->region.x,(double) nexus_info->region.y);
5176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5180 + W r i t e C a c h e P i x e l s %
5184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5186 % WritePixelCachePixels() writes image pixels to the specified region of the
5189 % The format of the WritePixelCachePixels() method is:
5191 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5192 % NexusInfo *nexus_info,ExceptionInfo *exception)
5194 % A description of each parameter follows:
5196 % o cache_info: the pixel cache.
5198 % o nexus_info: the cache nexus to write the pixels.
5200 % o exception: return any errors or warnings in this structure.
5203 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5204 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5214 register const Quantum
5223 if (nexus_info->authentic_pixel_cache != MagickFalse)
5225 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5226 nexus_info->region.x;
5227 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5229 extent=length*nexus_info->region.height;
5230 rows=nexus_info->region.height;
5232 p=nexus_info->pixels;
5233 switch (cache_info->type)
5242 Write pixels to memory.
5244 if ((cache_info->columns == nexus_info->region.width) &&
5245 (extent == (MagickSizeType) ((size_t) extent)))
5250 q=cache_info->pixels+offset*cache_info->number_channels;
5251 for (y=0; y < (ssize_t) rows; y++)
5253 (void) memcpy(q,p,(size_t) length);
5254 p+=cache_info->number_channels*nexus_info->region.width;
5255 q+=cache_info->columns*cache_info->number_channels;
5262 Write pixels to disk.
5264 LockSemaphoreInfo(cache_info->file_semaphore);
5265 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5267 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5268 cache_info->cache_filename);
5269 UnlockSemaphoreInfo(cache_info->file_semaphore);
5270 return(MagickFalse);
5272 if ((cache_info->columns == nexus_info->region.width) &&
5273 (extent <= MagickMaxBufferExtent))
5278 for (y=0; y < (ssize_t) rows; y++)
5280 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5281 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5283 if (count != (MagickOffsetType) length)
5285 p+=cache_info->number_channels*nexus_info->region.width;
5286 offset+=cache_info->columns;
5288 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5289 (void) ClosePixelCacheOnDisk(cache_info);
5290 UnlockSemaphoreInfo(cache_info->file_semaphore);
5293 case DistributedCache:
5299 Write pixels to distributed cache.
5301 LockSemaphoreInfo(cache_info->file_semaphore);
5302 region=nexus_info->region;
5303 if ((cache_info->columns != nexus_info->region.width) ||
5304 (extent > MagickMaxBufferExtent))
5311 for (y=0; y < (ssize_t) rows; y++)
5313 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5314 cache_info->server_info,®ion,length,(const unsigned char *) p);
5315 if (count != (MagickOffsetType) length)
5317 p+=cache_info->number_channels*nexus_info->region.width;
5320 UnlockSemaphoreInfo(cache_info->file_semaphore);
5326 if (y < (ssize_t) rows)
5328 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5329 cache_info->cache_filename);
5330 return(MagickFalse);
5332 if ((cache_info->debug != MagickFalse) &&
5333 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5334 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5335 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5336 nexus_info->region.width,(double) nexus_info->region.height,(double)
5337 nexus_info->region.x,(double) nexus_info->region.y);