2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
120 Forward declarations.
122 #if defined(__cplusplus) || defined(c_plusplus)
127 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
131 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
132 const ssize_t,const size_t,const size_t,ExceptionInfo *),
133 *GetVirtualPixelsCache(const Image *);
136 *GetVirtualMetacontentFromCache(const Image *);
138 static MagickBooleanType
139 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
141 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
142 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
143 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
144 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
146 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
147 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
148 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
151 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
152 const size_t,ExceptionInfo *),
153 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
154 const size_t,ExceptionInfo *),
155 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
156 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
158 #if defined(__cplusplus) || defined(c_plusplus)
165 static volatile MagickBooleanType
166 instantiate_cache = MagickFalse;
169 *cache_semaphore = (SemaphoreInfo *) NULL;
172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 + A c q u i r e P i x e l C a c h e %
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 % AcquirePixelCache() acquires a pixel cache.
184 % The format of the AcquirePixelCache() method is:
186 % Cache AcquirePixelCache(const size_t number_threads)
188 % A description of each parameter follows:
190 % o number_threads: the number of nexus threads.
193 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
201 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
202 if (cache_info == (CacheInfo *) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
205 cache_info->type=UndefinedCache;
206 cache_info->mode=IOMode;
207 cache_info->colorspace=sRGBColorspace;
208 cache_info->file=(-1);
209 cache_info->id=GetMagickThreadId();
210 cache_info->number_threads=number_threads;
211 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
212 cache_info->number_threads=GetOpenMPMaximumThreads();
213 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
214 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
215 if (cache_info->number_threads == 0)
216 cache_info->number_threads=1;
217 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
218 if (cache_info->nexus_info == (NexusInfo **) NULL)
219 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
220 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
221 if (synchronize != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(synchronize);
224 synchronize=DestroyString(synchronize);
226 cache_info->semaphore=AllocateSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AllocateSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickSignature;
231 return((Cache ) cache_info);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % A c q u i r e P i x e l C a c h e N e x u s %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
247 % The format of the AcquirePixelCacheNexus method is:
249 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 % A description of each parameter follows:
253 % o number_threads: the number of nexus threads.
256 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
264 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
265 number_threads,sizeof(*nexus_info)));
266 if (nexus_info == (NexusInfo **) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
269 sizeof(**nexus_info));
270 if (nexus_info[0] == (NexusInfo *) NULL)
271 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
272 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
273 for (i=0; i < (ssize_t) number_threads; i++)
275 nexus_info[i]=(&nexus_info[0][i]);
276 nexus_info[i]->signature=MagickSignature;
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 + A c q u i r e P i x e l C a c h e P i x e l s %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % AcquirePixelCachePixels() returns the pixels associated with the specified
295 % The format of the AcquirePixelCachePixels() method is:
297 % const void *AcquirePixelCachePixels(const Image *image,
298 % MagickSizeType *length,ExceptionInfo *exception)
300 % A description of each parameter follows:
302 % o image: the image.
304 % o length: the pixel cache length.
306 % o exception: return any errors or warnings in this structure.
309 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
310 MagickSizeType *length,ExceptionInfo *exception)
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickSignature);
323 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
324 return((const void *) NULL);
325 *length=cache_info->length;
326 return((const void *) cache_info->pixels);
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 + C a c h e C o m p o n e n t G e n e s i s %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % CacheComponentGenesis() instantiates the cache component.
342 % The format of the CacheComponentGenesis method is:
344 % MagickBooleanType CacheComponentGenesis(void)
347 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
349 AcquireSemaphoreInfo(&cache_semaphore);
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 + C a c h e C o m p o n e n t T e r m i n u s %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 % CacheComponentTerminus() destroys the cache component.
366 % The format of the CacheComponentTerminus() method is:
368 % CacheComponentTerminus(void)
371 MagickPrivate void CacheComponentTerminus(void)
373 if (cache_semaphore == (SemaphoreInfo *) NULL)
374 AcquireSemaphoreInfo(&cache_semaphore);
375 LockSemaphoreInfo(cache_semaphore);
376 instantiate_cache=MagickFalse;
377 UnlockSemaphoreInfo(cache_semaphore);
378 DestroySemaphoreInfo(&cache_semaphore);
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 + C l o n e P i x e l C a c h e %
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 % ClonePixelCache() clones a pixel cache.
394 % The format of the ClonePixelCache() method is:
396 % Cache ClonePixelCache(const Cache cache)
398 % A description of each parameter follows:
400 % o cache: the pixel cache.
403 MagickPrivate Cache ClonePixelCache(const Cache cache)
411 assert(cache != NULL);
412 cache_info=(const CacheInfo *) cache;
413 assert(cache_info->signature == MagickSignature);
414 if (cache_info->debug != MagickFalse)
415 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
416 cache_info->filename);
417 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
418 if (clone_info == (Cache) NULL)
419 return((Cache) NULL);
420 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
421 return((Cache ) clone_info);
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 + C l o n e P i x e l C a c h e M e t h o d s %
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
438 % The format of the ClonePixelCacheMethods() method is:
440 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
442 % A description of each parameter follows:
444 % o clone: Specifies a pointer to a Cache structure.
446 % o cache: the pixel cache.
449 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
455 assert(clone != (Cache) NULL);
456 source_info=(CacheInfo *) clone;
457 assert(source_info->signature == MagickSignature);
458 if (source_info->debug != MagickFalse)
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
460 source_info->filename);
461 assert(cache != (Cache) NULL);
462 cache_info=(CacheInfo *) cache;
463 assert(cache_info->signature == MagickSignature);
464 source_info->methods=cache_info->methods;
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 + 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 %
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
477 % ClonePixelCacheRepository() clones the source pixel cache to the destination
480 % The format of the ClonePixelCacheRepository() method is:
482 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
483 % CacheInfo *source_info,ExceptionInfo *exception)
485 % A description of each parameter follows:
487 % o cache_info: the pixel cache.
489 % o source_info: the source pixel cache.
491 % o exception: return any errors or warnings in this structure.
495 static inline MagickSizeType MagickMin(const MagickSizeType x,
496 const MagickSizeType y)
503 static MagickBooleanType ClonePixelCacheRepository(CacheInfo *clone_info,
504 CacheInfo *cache_info,ExceptionInfo *exception)
506 #define MaxCacheThreads 2
507 #define cache_threads(source,destination,chunk) \
508 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
509 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? 1 : \
526 assert(cache_info != (CacheInfo *) NULL);
527 assert(clone_info != (CacheInfo *) NULL);
528 assert(exception != (ExceptionInfo *) NULL);
529 if (cache_info->type == PingCache)
531 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
532 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
533 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
534 (cache_info->columns == clone_info->columns) &&
535 (cache_info->rows == clone_info->rows) &&
536 (cache_info->number_channels == clone_info->number_channels) &&
537 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0))
540 Identical pixel cache morphology.
542 (void) memcpy(clone_info->pixels,cache_info->pixels,cache_info->columns*
543 cache_info->number_channels*cache_info->rows*
544 sizeof(*cache_info->pixels));
545 if ((cache_info->metacontent_extent != 0) &&
546 (clone_info->metacontent_extent != 0) &&
547 (cache_info->metacontent_extent == clone_info->metacontent_extent))
548 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
549 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
550 sizeof(*cache_info->metacontent));
554 Mismatched pixel cache morphology.
556 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
557 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
558 if ((cache_nexus == (NexusInfo **) NULL) ||
559 (clone_nexus == (NexusInfo **) NULL))
560 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
561 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
562 optimize=(cache_info->number_channels == clone_info->number_channels) &&
563 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
564 MagickTrue : MagickFalse;
565 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
566 clone_info->columns*clone_info->number_channels);
568 #if defined(MAGICKCORE_OPENMP_SUPPORT)
569 #pragma omp parallel for schedule(static,4) shared(status) \
570 cache_threads(cache_info,clone_info,cache_info->rows)
572 for (y=0; y < (ssize_t) cache_info->rows; y++)
575 id = GetOpenMPThreadId();
586 if (status == MagickFalse)
588 if (y >= (ssize_t) clone_info->rows)
590 region.width=cache_info->columns;
594 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
596 if (pixels == (Quantum *) NULL)
598 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
599 if (status == MagickFalse)
601 region.width=clone_info->columns;
603 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
604 clone_nexus[id],exception);
605 if (pixels == (Quantum *) NULL)
607 if (optimize != MagickFalse)
608 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
612 register const Quantum
619 Mismatched pixel channel map.
621 p=cache_nexus[id]->pixels;
622 q=clone_nexus[id]->pixels;
623 for (x=0; x < (ssize_t) cache_info->columns; x++)
628 if (x == (ssize_t) clone_info->columns)
630 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
638 channel=clone_info->channel_map[i].channel;
639 traits=cache_info->channel_map[channel].traits;
640 if (traits != UndefinedPixelTrait)
641 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
645 p+=cache_info->number_channels;
648 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
650 if ((cache_info->metacontent_extent != 0) &&
651 (clone_info->metacontent_extent != 0))
656 length=(size_t) MagickMin(cache_info->metacontent_extent,
657 clone_info->metacontent_extent);
658 for (y=0; y < (ssize_t) cache_info->rows; y++)
661 id = GetOpenMPThreadId();
669 if (status == MagickFalse)
671 if (y >= (ssize_t) clone_info->rows)
673 region.width=cache_info->columns;
677 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
678 cache_nexus[id],exception);
679 if (pixels == (Quantum *) NULL)
681 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
682 if (status == MagickFalse)
684 region.width=clone_info->columns;
686 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
687 clone_nexus[id],exception);
688 if (pixels == (Quantum *) NULL)
690 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
691 length*sizeof(*cache_nexus[id]->metacontent));
692 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
695 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
696 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
697 if (cache_info->debug != MagickFalse)
700 message[MaxTextExtent];
702 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
703 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
704 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
705 (void) LogMagickEvent(CacheEvent,GetMagickModule(),message);
711 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715 + D e s t r o y I m a g e P i x e l C a c h e %
719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
723 % The format of the DestroyImagePixelCache() method is:
725 % void DestroyImagePixelCache(Image *image)
727 % A description of each parameter follows:
729 % o image: the image.
732 static void DestroyImagePixelCache(Image *image)
734 assert(image != (Image *) NULL);
735 assert(image->signature == MagickSignature);
736 if (image->debug != MagickFalse)
737 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
738 if (image->cache == (void *) NULL)
740 image->cache=DestroyPixelCache(image->cache);
744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 + D e s t r o y I m a g e P i x e l s %
752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754 % DestroyImagePixels() deallocates memory associated with the pixel cache.
756 % The format of the DestroyImagePixels() method is:
758 % void DestroyImagePixels(Image *image)
760 % A description of each parameter follows:
762 % o image: the image.
765 MagickExport void DestroyImagePixels(Image *image)
770 assert(image != (const Image *) NULL);
771 assert(image->signature == MagickSignature);
772 if (image->debug != MagickFalse)
773 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
774 assert(image->cache != (Cache) NULL);
775 cache_info=(CacheInfo *) image->cache;
776 assert(cache_info->signature == MagickSignature);
777 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
779 cache_info->methods.destroy_pixel_handler(image);
782 image->cache=DestroyPixelCache(image->cache);
786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790 + D e s t r o y P i x e l C a c h e %
794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
796 % DestroyPixelCache() deallocates memory associated with the pixel cache.
798 % The format of the DestroyPixelCache() method is:
800 % Cache DestroyPixelCache(Cache cache)
802 % A description of each parameter follows:
804 % o cache: the pixel cache.
808 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
814 if (cache_info->file != -1)
816 status=close(cache_info->file);
817 cache_info->file=(-1);
818 RelinquishMagickResource(FileResource,1);
820 return(status == -1 ? MagickFalse : MagickTrue);
823 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
825 switch (cache_info->type)
829 if (cache_info->mapped == MagickFalse)
830 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
833 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
834 (size_t) cache_info->length);
835 RelinquishMagickResource(MemoryResource,cache_info->length);
840 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
842 if (cache_info->mode != ReadMode)
843 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
844 *cache_info->cache_filename='\0';
845 RelinquishMagickResource(MapResource,cache_info->length);
849 if (cache_info->file != -1)
850 (void) ClosePixelCacheOnDisk(cache_info);
851 if (cache_info->mode != ReadMode)
852 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
853 *cache_info->cache_filename='\0';
854 RelinquishMagickResource(DiskResource,cache_info->length);
857 case DistributedCache:
859 *cache_info->cache_filename='\0';
860 (void) RelinquishDistributePixelCache(cache_info->server_info);
866 cache_info->type=UndefinedCache;
867 cache_info->mapped=MagickFalse;
868 cache_info->metacontent=(void *) NULL;
871 MagickPrivate Cache DestroyPixelCache(Cache cache)
876 assert(cache != (Cache) NULL);
877 cache_info=(CacheInfo *) cache;
878 assert(cache_info->signature == MagickSignature);
879 if (cache_info->debug != MagickFalse)
880 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
881 cache_info->filename);
882 LockSemaphoreInfo(cache_info->semaphore);
883 cache_info->reference_count--;
884 if (cache_info->reference_count != 0)
886 UnlockSemaphoreInfo(cache_info->semaphore);
887 return((Cache) NULL);
889 UnlockSemaphoreInfo(cache_info->semaphore);
890 if (cache_info->debug != MagickFalse)
893 message[MaxTextExtent];
895 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
896 cache_info->filename);
897 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
899 RelinquishPixelCachePixels(cache_info);
900 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
901 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
902 if (cache_info->nexus_info != (NexusInfo **) NULL)
903 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
904 cache_info->number_threads);
905 if (cache_info->random_info != (RandomInfo *) NULL)
906 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
907 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
908 DestroySemaphoreInfo(&cache_info->file_semaphore);
909 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
910 DestroySemaphoreInfo(&cache_info->semaphore);
911 cache_info->signature=(~MagickSignature);
912 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922 + D e s t r o y P i x e l C a c h e N e x u s %
926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
930 % The format of the DestroyPixelCacheNexus() method is:
932 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
933 % const size_t number_threads)
935 % A description of each parameter follows:
937 % o nexus_info: the nexus to destroy.
939 % o number_threads: the number of nexus threads.
943 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
945 if (nexus_info->mapped == MagickFalse)
946 (void) RelinquishAlignedMemory(nexus_info->cache);
948 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
949 nexus_info->cache=(Quantum *) NULL;
950 nexus_info->pixels=(Quantum *) NULL;
951 nexus_info->metacontent=(void *) NULL;
952 nexus_info->length=0;
953 nexus_info->mapped=MagickFalse;
956 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
957 const size_t number_threads)
962 assert(nexus_info != (NexusInfo **) NULL);
963 for (i=0; i < (ssize_t) number_threads; i++)
965 if (nexus_info[i]->cache != (Quantum *) NULL)
966 RelinquishCacheNexusPixels(nexus_info[i]);
967 nexus_info[i]->signature=(~MagickSignature);
969 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
970 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
979 % G e t A u t h e n t i c M e t a c o n t e n t %
983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
985 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
986 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
987 % returned if the associated pixels are not available.
989 % The format of the GetAuthenticMetacontent() method is:
991 % void *GetAuthenticMetacontent(const Image *image)
993 % A description of each parameter follows:
995 % o image: the image.
998 MagickExport void *GetAuthenticMetacontent(const Image *image)
1004 id = GetOpenMPThreadId();
1009 assert(image != (const Image *) NULL);
1010 assert(image->signature == MagickSignature);
1011 assert(image->cache != (Cache) NULL);
1012 cache_info=(CacheInfo *) image->cache;
1013 assert(cache_info->signature == MagickSignature);
1014 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1015 (GetAuthenticMetacontentFromHandler) NULL)
1017 metacontent=cache_info->methods.
1018 get_authentic_metacontent_from_handler(image);
1019 return(metacontent);
1021 assert(id < (int) cache_info->number_threads);
1022 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1023 cache_info->nexus_info[id]);
1024 return(metacontent);
1028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1032 + 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 %
1036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1039 % with the last call to QueueAuthenticPixelsCache() or
1040 % GetAuthenticPixelsCache().
1042 % The format of the GetAuthenticMetacontentFromCache() method is:
1044 % void *GetAuthenticMetacontentFromCache(const Image *image)
1046 % A description of each parameter follows:
1048 % o image: the image.
1051 static void *GetAuthenticMetacontentFromCache(const Image *image)
1057 id = GetOpenMPThreadId();
1062 assert(image != (const Image *) NULL);
1063 assert(image->signature == MagickSignature);
1064 assert(image->cache != (Cache) NULL);
1065 cache_info=(CacheInfo *) image->cache;
1066 assert(cache_info->signature == MagickSignature);
1067 assert(id < (int) cache_info->number_threads);
1068 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1069 cache_info->nexus_info[id]);
1070 return(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 static inline MagickBooleanType IsPixelAuthentic(
1109 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1117 if (cache_info->type == PingCache)
1119 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1120 nexus_info->region.x;
1121 status=nexus_info->pixels == (cache_info->pixels+offset*
1122 cache_info->number_channels) ? MagickTrue : MagickFalse;
1126 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1127 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1128 NexusInfo *nexus_info,ExceptionInfo *exception)
1137 Transfer pixels from the cache.
1139 assert(image != (Image *) NULL);
1140 assert(image->signature == MagickSignature);
1141 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1143 if (q == (Quantum *) NULL)
1144 return((Quantum *) NULL);
1145 cache_info=(CacheInfo *) image->cache;
1146 assert(cache_info->signature == MagickSignature);
1147 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1149 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1150 return((Quantum *) NULL);
1151 if (cache_info->metacontent_extent != 0)
1152 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1153 return((Quantum *) NULL);
1158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162 + 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 %
1166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1169 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1171 % The format of the GetAuthenticPixelsFromCache() method is:
1173 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1175 % A description of each parameter follows:
1177 % o image: the image.
1180 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1186 id = GetOpenMPThreadId();
1188 assert(image != (const Image *) NULL);
1189 assert(image->signature == MagickSignature);
1190 assert(image->cache != (Cache) NULL);
1191 cache_info=(CacheInfo *) image->cache;
1192 assert(cache_info->signature == MagickSignature);
1193 assert(id < (int) cache_info->number_threads);
1194 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202 % G e t A u t h e n t i c P i x e l Q u e u e %
1206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1208 % GetAuthenticPixelQueue() returns the authentic pixels associated
1209 % corresponding with the last call to QueueAuthenticPixels() or
1210 % GetAuthenticPixels().
1212 % The format of the GetAuthenticPixelQueue() method is:
1214 % Quantum *GetAuthenticPixelQueue(const Image image)
1216 % A description of each parameter follows:
1218 % o image: the image.
1221 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1227 id = GetOpenMPThreadId();
1229 assert(image != (const Image *) NULL);
1230 assert(image->signature == MagickSignature);
1231 assert(image->cache != (Cache) NULL);
1232 cache_info=(CacheInfo *) image->cache;
1233 assert(cache_info->signature == MagickSignature);
1234 if (cache_info->methods.get_authentic_pixels_from_handler !=
1235 (GetAuthenticPixelsFromHandler) NULL)
1236 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1237 assert(id < (int) cache_info->number_threads);
1238 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1246 % G e t A u t h e n t i c P i x e l s %
1249 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1251 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1252 % region is successfully accessed, a pointer to a Quantum array
1253 % representing the region is returned, otherwise NULL is returned.
1255 % The returned pointer may point to a temporary working copy of the pixels
1256 % or it may point to the original pixels in memory. Performance is maximized
1257 % if the selected region is part of one row, or one or more full rows, since
1258 % then there is opportunity to access the pixels in-place (without a copy)
1259 % if the image is in memory, or in a memory-mapped file. The returned pointer
1260 % must *never* be deallocated by the user.
1262 % Pixels accessed via the returned pointer represent a simple array of type
1263 % Quantum. If the image has corresponding metacontent,call
1264 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1265 % meta-content corresponding to the region. Once the Quantum array has
1266 % been updated, the changes must be saved back to the underlying image using
1267 % SyncAuthenticPixels() or they may be lost.
1269 % The format of the GetAuthenticPixels() method is:
1271 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1272 % const ssize_t y,const size_t columns,const size_t rows,
1273 % ExceptionInfo *exception)
1275 % A description of each parameter follows:
1277 % o image: the image.
1279 % o x,y,columns,rows: These values define the perimeter of a region of
1282 % o exception: return any errors or warnings in this structure.
1285 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1286 const ssize_t y,const size_t columns,const size_t rows,
1287 ExceptionInfo *exception)
1293 id = GetOpenMPThreadId();
1298 assert(image != (Image *) NULL);
1299 assert(image->signature == MagickSignature);
1300 assert(image->cache != (Cache) NULL);
1301 cache_info=(CacheInfo *) image->cache;
1302 assert(cache_info->signature == MagickSignature);
1303 if (cache_info->methods.get_authentic_pixels_handler !=
1304 (GetAuthenticPixelsHandler) NULL)
1306 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1310 assert(id < (int) cache_info->number_threads);
1311 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1312 cache_info->nexus_info[id],exception);
1317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1321 + G e t A u t h e n t i c P i x e l s C a c h e %
1325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1327 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1328 % as defined by the geometry parameters. A pointer to the pixels is returned
1329 % if the pixels are transferred, otherwise a NULL is returned.
1331 % The format of the GetAuthenticPixelsCache() method is:
1333 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1334 % const ssize_t y,const size_t columns,const size_t rows,
1335 % ExceptionInfo *exception)
1337 % A description of each parameter follows:
1339 % o image: the image.
1341 % o x,y,columns,rows: These values define the perimeter of a region of
1344 % o exception: return any errors or warnings in this structure.
1347 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1348 const ssize_t y,const size_t columns,const size_t rows,
1349 ExceptionInfo *exception)
1355 id = GetOpenMPThreadId();
1360 assert(image != (const Image *) NULL);
1361 assert(image->signature == MagickSignature);
1362 assert(image->cache != (Cache) NULL);
1363 cache_info=(CacheInfo *) image->cache;
1364 if (cache_info == (Cache) NULL)
1365 return((Quantum *) NULL);
1366 assert(cache_info->signature == MagickSignature);
1367 assert(id < (int) cache_info->number_threads);
1368 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1369 cache_info->nexus_info[id],exception);
1374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378 + G e t I m a g e E x t e n t %
1382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1384 % GetImageExtent() returns the extent of the pixels associated corresponding
1385 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1387 % The format of the GetImageExtent() method is:
1389 % MagickSizeType GetImageExtent(const Image *image)
1391 % A description of each parameter follows:
1393 % o image: the image.
1396 MagickExport MagickSizeType GetImageExtent(const Image *image)
1402 id = GetOpenMPThreadId();
1404 assert(image != (Image *) NULL);
1405 assert(image->signature == MagickSignature);
1406 if (image->debug != MagickFalse)
1407 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1408 assert(image->cache != (Cache) NULL);
1409 cache_info=(CacheInfo *) image->cache;
1410 assert(cache_info->signature == MagickSignature);
1411 assert(id < (int) cache_info->number_threads);
1412 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 + G e t I m a g e P i x e l C a c h e %
1424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426 % GetImagePixelCache() ensures that there is only a single reference to the
1427 % pixel cache to be modified, updating the provided cache pointer to point to
1428 % a clone of the original pixel cache if necessary.
1430 % The format of the GetImagePixelCache method is:
1432 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1433 % ExceptionInfo *exception)
1435 % A description of each parameter follows:
1437 % o image: the image.
1439 % o clone: any value other than MagickFalse clones the cache pixels.
1441 % o exception: return any errors or warnings in this structure.
1445 static inline MagickBooleanType ValidatePixelCacheMorphology(
1446 const Image *restrict image)
1449 *restrict cache_info;
1451 const PixelChannelMap
1456 Does the image match the pixel cache morphology?
1458 cache_info=(CacheInfo *) image->cache;
1459 p=image->channel_map;
1460 q=cache_info->channel_map;
1461 if ((image->storage_class != cache_info->storage_class) ||
1462 (image->colorspace != cache_info->colorspace) ||
1463 (image->alpha_trait != cache_info->alpha_trait) ||
1464 (image->mask != cache_info->mask) ||
1465 (image->columns != cache_info->columns) ||
1466 (image->rows != cache_info->rows) ||
1467 (image->number_channels != cache_info->number_channels) ||
1468 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1469 (image->metacontent_extent != cache_info->metacontent_extent) ||
1470 (cache_info->nexus_info == (NexusInfo **) NULL))
1471 return(MagickFalse);
1475 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1476 ExceptionInfo *exception)
1485 static MagickSizeType
1491 cache_timestamp = 0;
1494 LockSemaphoreInfo(image->semaphore);
1495 if (cpu_throttle == 0)
1501 Set CPU throttle in milleseconds.
1503 cpu_throttle=MagickResourceInfinity;
1504 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1505 if (limit == (char *) NULL)
1506 limit=GetPolicyValue("throttle");
1507 if (limit != (char *) NULL)
1509 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1510 limit=DestroyString(limit);
1513 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1514 MagickDelay(cpu_throttle);
1515 if (time_limit == 0)
1518 Set the expire time in seconds.
1520 time_limit=GetMagickResourceLimit(TimeResource);
1521 cache_timestamp=time((time_t *) NULL);
1523 if ((time_limit != MagickResourceInfinity) &&
1524 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1525 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1526 assert(image->cache != (Cache) NULL);
1527 cache_info=(CacheInfo *) image->cache;
1528 destroy=MagickFalse;
1529 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1531 LockSemaphoreInfo(cache_info->semaphore);
1532 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1543 clone_image=(*image);
1544 clone_image.semaphore=AllocateSemaphoreInfo();
1545 clone_image.reference_count=1;
1546 clone_image.cache=ClonePixelCache(cache_info);
1547 clone_info=(CacheInfo *) clone_image.cache;
1548 status=OpenPixelCache(&clone_image,IOMode,exception);
1549 if (status != MagickFalse)
1551 if (clone != MagickFalse)
1552 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
1553 if (status != MagickFalse)
1555 if (cache_info->reference_count == 1)
1556 cache_info->nexus_info=(NexusInfo **) NULL;
1558 image->cache=clone_image.cache;
1561 DestroySemaphoreInfo(&clone_image.semaphore);
1563 UnlockSemaphoreInfo(cache_info->semaphore);
1565 if (destroy != MagickFalse)
1566 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1567 if (status != MagickFalse)
1570 Ensure the image matches the pixel cache morphology.
1572 image->taint=MagickTrue;
1573 image->type=UndefinedType;
1574 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1576 status=OpenPixelCache(image,IOMode,exception);
1577 cache_info=(CacheInfo *) image->cache;
1578 if (cache_info->type == DiskCache)
1579 (void) ClosePixelCacheOnDisk(cache_info);
1582 UnlockSemaphoreInfo(image->semaphore);
1583 if (status == MagickFalse)
1584 return((Cache) NULL);
1585 return(image->cache);
1589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593 + G e t I m a g e P i x e l C a c h e T y p e %
1597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1600 % DiskCache, MemoryCache, MapCache, or PingCache.
1602 % The format of the GetImagePixelCacheType() method is:
1604 % CacheType GetImagePixelCacheType(const Image *image)
1606 % A description of each parameter follows:
1608 % o image: the image.
1611 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1616 assert(image != (Image *) NULL);
1617 assert(image->signature == MagickSignature);
1618 assert(image->cache != (Cache) NULL);
1619 cache_info=(CacheInfo *) image->cache;
1620 assert(cache_info->signature == MagickSignature);
1621 return(cache_info->type);
1625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629 % G e t O n e A u t h e n t i c P i x e l %
1633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1635 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1636 % location. The image background color is returned if an error occurs.
1638 % The format of the GetOneAuthenticPixel() method is:
1640 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1641 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1643 % A description of each parameter follows:
1645 % o image: the image.
1647 % o x,y: These values define the location of the pixel to return.
1649 % o pixel: return a pixel at the specified (x,y) location.
1651 % o exception: return any errors or warnings in this structure.
1654 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1655 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1666 assert(image != (Image *) NULL);
1667 assert(image->signature == MagickSignature);
1668 assert(image->cache != (Cache) NULL);
1669 cache_info=(CacheInfo *) image->cache;
1670 assert(cache_info->signature == MagickSignature);
1671 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1672 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1673 (GetOneAuthenticPixelFromHandler) NULL)
1674 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1676 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1677 if (q == (Quantum *) NULL)
1679 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1680 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1681 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1682 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1683 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1684 return(MagickFalse);
1686 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1691 channel=GetPixelChannelChannel(image,i);
1692 pixel[channel]=q[i];
1698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1702 + 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 %
1706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1709 % location. The image background color is returned if an error occurs.
1711 % The format of the GetOneAuthenticPixelFromCache() method is:
1713 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1714 % const ssize_t x,const ssize_t y,Quantum *pixel,
1715 % ExceptionInfo *exception)
1717 % A description of each parameter follows:
1719 % o image: the image.
1721 % o x,y: These values define the location of the pixel to return.
1723 % o pixel: return a pixel at the specified (x,y) location.
1725 % o exception: return any errors or warnings in this structure.
1728 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1729 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1735 id = GetOpenMPThreadId();
1743 assert(image != (const Image *) NULL);
1744 assert(image->signature == MagickSignature);
1745 assert(image->cache != (Cache) NULL);
1746 cache_info=(CacheInfo *) image->cache;
1747 assert(cache_info->signature == MagickSignature);
1748 assert(id < (int) cache_info->number_threads);
1749 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1750 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1752 if (q == (Quantum *) NULL)
1754 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1755 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1756 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1757 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1758 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1759 return(MagickFalse);
1761 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1766 channel=GetPixelChannelChannel(image,i);
1767 pixel[channel]=q[i];
1773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1777 % G e t O n e V i r t u a l P i x e l %
1781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1784 % (x,y) location. The image background color is returned if an error occurs.
1785 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1787 % The format of the GetOneVirtualPixel() method is:
1789 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1790 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1792 % A description of each parameter follows:
1794 % o image: the image.
1796 % o x,y: These values define the location of the pixel to return.
1798 % o pixel: return a pixel at the specified (x,y) location.
1800 % o exception: return any errors or warnings in this structure.
1803 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1804 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1810 id = GetOpenMPThreadId();
1818 assert(image != (const Image *) NULL);
1819 assert(image->signature == MagickSignature);
1820 assert(image->cache != (Cache) NULL);
1821 cache_info=(CacheInfo *) image->cache;
1822 assert(cache_info->signature == MagickSignature);
1823 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1824 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1825 (GetOneVirtualPixelFromHandler) NULL)
1826 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1827 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1828 assert(id < (int) cache_info->number_threads);
1829 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1830 1UL,1UL,cache_info->nexus_info[id],exception);
1831 if (p == (const Quantum *) NULL)
1833 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1834 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1835 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1836 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1837 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1838 return(MagickFalse);
1840 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1845 channel=GetPixelChannelChannel(image,i);
1846 pixel[channel]=p[i];
1852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1856 + 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 %
1860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1863 % specified (x,y) location. The image background color is returned if an
1866 % The format of the GetOneVirtualPixelFromCache() method is:
1868 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1869 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1870 % Quantum *pixel,ExceptionInfo *exception)
1872 % A description of each parameter follows:
1874 % o image: the image.
1876 % o virtual_pixel_method: the virtual pixel method.
1878 % o x,y: These values define the location of the pixel to return.
1880 % o pixel: return a pixel at the specified (x,y) location.
1882 % o exception: return any errors or warnings in this structure.
1885 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1886 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1887 Quantum *pixel,ExceptionInfo *exception)
1893 id = GetOpenMPThreadId();
1901 assert(image != (const Image *) NULL);
1902 assert(image->signature == MagickSignature);
1903 assert(image->cache != (Cache) NULL);
1904 cache_info=(CacheInfo *) image->cache;
1905 assert(cache_info->signature == MagickSignature);
1906 assert(id < (int) cache_info->number_threads);
1907 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1908 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1909 cache_info->nexus_info[id],exception);
1910 if (p == (const Quantum *) NULL)
1912 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1913 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1914 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1915 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1916 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1917 return(MagickFalse);
1919 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1924 channel=GetPixelChannelChannel(image,i);
1925 pixel[channel]=p[i];
1931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1935 % G e t O n e V i r t u a l P i x e l I n f o %
1939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1941 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1942 % location. The image background color is returned if an error occurs. If
1943 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1945 % The format of the GetOneVirtualPixelInfo() method is:
1947 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1948 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1949 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1951 % A description of each parameter follows:
1953 % o image: the image.
1955 % o virtual_pixel_method: the virtual pixel method.
1957 % o x,y: these values define the location of the pixel to return.
1959 % o pixel: return a pixel at the specified (x,y) location.
1961 % o exception: return any errors or warnings in this structure.
1964 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1965 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1966 PixelInfo *pixel,ExceptionInfo *exception)
1972 id = GetOpenMPThreadId();
1974 register const Quantum
1977 assert(image != (const Image *) NULL);
1978 assert(image->signature == MagickSignature);
1979 assert(image->cache != (Cache) NULL);
1980 cache_info=(CacheInfo *) image->cache;
1981 assert(cache_info->signature == MagickSignature);
1982 assert(id < (int) cache_info->number_threads);
1983 GetPixelInfo(image,pixel);
1984 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1985 cache_info->nexus_info[id],exception);
1986 if (p == (const Quantum *) NULL)
1987 return(MagickFalse);
1988 GetPixelInfoPixel(image,p,pixel);
1993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1997 + G e t P i x e l C a c h e C o l o r s p a c e %
2001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2003 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2005 % The format of the GetPixelCacheColorspace() method is:
2007 % Colorspace GetPixelCacheColorspace(Cache cache)
2009 % A description of each parameter follows:
2011 % o cache: the pixel cache.
2014 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2019 assert(cache != (Cache) NULL);
2020 cache_info=(CacheInfo *) cache;
2021 assert(cache_info->signature == MagickSignature);
2022 if (cache_info->debug != MagickFalse)
2023 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2024 cache_info->filename);
2025 return(cache_info->colorspace);
2029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2033 + G e t P i x e l C a c h e M e t h o d s %
2037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2039 % GetPixelCacheMethods() initializes the CacheMethods structure.
2041 % The format of the GetPixelCacheMethods() method is:
2043 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2045 % A description of each parameter follows:
2047 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2050 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2052 assert(cache_methods != (CacheMethods *) NULL);
2053 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2054 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2055 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2056 cache_methods->get_virtual_metacontent_from_handler=
2057 GetVirtualMetacontentFromCache;
2058 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2059 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2060 cache_methods->get_authentic_metacontent_from_handler=
2061 GetAuthenticMetacontentFromCache;
2062 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2063 cache_methods->get_one_authentic_pixel_from_handler=
2064 GetOneAuthenticPixelFromCache;
2065 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2066 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2067 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2075 + G e t P i x e l C a c h e N e x u s E x t e n t %
2079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2081 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2082 % corresponding with the last call to SetPixelCacheNexusPixels() or
2083 % GetPixelCacheNexusPixels().
2085 % The format of the GetPixelCacheNexusExtent() method is:
2087 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2088 % NexusInfo *nexus_info)
2090 % A description of each parameter follows:
2092 % o nexus_info: the nexus info.
2095 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2096 NexusInfo *nexus_info)
2104 assert(cache != NULL);
2105 cache_info=(CacheInfo *) cache;
2106 assert(cache_info->signature == MagickSignature);
2107 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2109 return((MagickSizeType) cache_info->columns*cache_info->rows);
2114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2118 + G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
2122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2124 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2127 % The format of the GetPixelCacheNexusMetacontent() method is:
2129 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2130 % NexusInfo *nexus_info)
2132 % A description of each parameter follows:
2134 % o cache: the pixel cache.
2136 % o nexus_info: the cache nexus to return the meta-content.
2139 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2140 NexusInfo *nexus_info)
2145 assert(cache != NULL);
2146 cache_info=(CacheInfo *) cache;
2147 assert(cache_info->signature == MagickSignature);
2148 if (cache_info->storage_class == UndefinedClass)
2149 return((void *) NULL);
2150 return(nexus_info->metacontent);
2154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158 + G e t P i x e l C a c h e N e x u s P i x e l s %
2162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2167 % The format of the GetPixelCacheNexusPixels() method is:
2169 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2170 % NexusInfo *nexus_info)
2172 % A description of each parameter follows:
2174 % o cache: the pixel cache.
2176 % o nexus_info: the cache nexus to return the pixels.
2179 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2180 NexusInfo *nexus_info)
2185 assert(cache != NULL);
2186 cache_info=(CacheInfo *) cache;
2187 assert(cache_info->signature == MagickSignature);
2188 if (cache_info->storage_class == UndefinedClass)
2189 return((Quantum *) NULL);
2190 return(nexus_info->pixels);
2194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2198 + G e t P i x e l C a c h e P i x e l s %
2202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204 % GetPixelCachePixels() returns the pixels associated with the specified image.
2206 % The format of the GetPixelCachePixels() method is:
2208 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2209 % ExceptionInfo *exception)
2211 % A description of each parameter follows:
2213 % o image: the image.
2215 % o length: the pixel cache length.
2217 % o exception: return any errors or warnings in this structure.
2220 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2221 ExceptionInfo *exception)
2226 assert(image != (const Image *) NULL);
2227 assert(image->signature == MagickSignature);
2228 assert(image->cache != (Cache) NULL);
2229 assert(length != (MagickSizeType *) NULL);
2230 assert(exception != (ExceptionInfo *) NULL);
2231 assert(exception->signature == MagickSignature);
2232 cache_info=(CacheInfo *) image->cache;
2233 assert(cache_info->signature == MagickSignature);
2235 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2236 return((void *) NULL);
2237 *length=cache_info->length;
2238 return((void *) cache_info->pixels);
2242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2246 + 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 %
2250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2252 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2254 % The format of the GetPixelCacheStorageClass() method is:
2256 % ClassType GetPixelCacheStorageClass(Cache cache)
2258 % A description of each parameter follows:
2260 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2262 % o cache: the pixel cache.
2265 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2270 assert(cache != (Cache) NULL);
2271 cache_info=(CacheInfo *) cache;
2272 assert(cache_info->signature == MagickSignature);
2273 if (cache_info->debug != MagickFalse)
2274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2275 cache_info->filename);
2276 return(cache_info->storage_class);
2280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284 + G e t P i x e l C a c h e T i l e S i z e %
2288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2290 % GetPixelCacheTileSize() returns the pixel cache tile size.
2292 % The format of the GetPixelCacheTileSize() method is:
2294 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2297 % A description of each parameter follows:
2299 % o image: the image.
2301 % o width: the optimize cache tile width in pixels.
2303 % o height: the optimize cache tile height in pixels.
2306 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2312 assert(image != (Image *) NULL);
2313 assert(image->signature == MagickSignature);
2314 if (image->debug != MagickFalse)
2315 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2316 cache_info=(CacheInfo *) image->cache;
2317 assert(cache_info->signature == MagickSignature);
2318 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2319 if (GetImagePixelCacheType(image) == DiskCache)
2320 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2329 + 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 %
2333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2335 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2336 % pixel cache. A virtual pixel is any pixel access that is outside the
2337 % boundaries of the image cache.
2339 % The format of the GetPixelCacheVirtualMethod() method is:
2341 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2343 % A description of each parameter follows:
2345 % o image: the image.
2348 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2353 assert(image != (Image *) NULL);
2354 assert(image->signature == MagickSignature);
2355 assert(image->cache != (Cache) NULL);
2356 cache_info=(CacheInfo *) image->cache;
2357 assert(cache_info->signature == MagickSignature);
2358 return(cache_info->virtual_pixel_method);
2362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2366 + 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 %
2370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2372 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2373 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2375 % The format of the GetVirtualMetacontentFromCache() method is:
2377 % void *GetVirtualMetacontentFromCache(const Image *image)
2379 % A description of each parameter follows:
2381 % o image: the image.
2384 static const void *GetVirtualMetacontentFromCache(const Image *image)
2390 id = GetOpenMPThreadId();
2395 assert(image != (const Image *) NULL);
2396 assert(image->signature == MagickSignature);
2397 assert(image->cache != (Cache) NULL);
2398 cache_info=(CacheInfo *) image->cache;
2399 assert(cache_info->signature == MagickSignature);
2400 assert(id < (int) cache_info->number_threads);
2401 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2402 cache_info->nexus_info[id]);
2403 return(metacontent);
2407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2411 + 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 %
2415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2417 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2420 % The format of the GetVirtualMetacontentFromNexus() method is:
2422 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2423 % NexusInfo *nexus_info)
2425 % A description of each parameter follows:
2427 % o cache: the pixel cache.
2429 % o nexus_info: the cache nexus to return the meta-content.
2432 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2433 NexusInfo *nexus_info)
2438 assert(cache != (Cache) NULL);
2439 cache_info=(CacheInfo *) cache;
2440 assert(cache_info->signature == MagickSignature);
2441 if (cache_info->storage_class == UndefinedClass)
2442 return((void *) NULL);
2443 return(nexus_info->metacontent);
2447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2451 % G e t V i r t u a l M e t a c o n t e n t %
2455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2457 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2458 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2459 % returned if the meta-content are not available.
2461 % The format of the GetVirtualMetacontent() method is:
2463 % const void *GetVirtualMetacontent(const Image *image)
2465 % A description of each parameter follows:
2467 % o image: the image.
2470 MagickExport const void *GetVirtualMetacontent(const Image *image)
2476 id = GetOpenMPThreadId();
2481 assert(image != (const Image *) NULL);
2482 assert(image->signature == MagickSignature);
2483 assert(image->cache != (Cache) NULL);
2484 cache_info=(CacheInfo *) image->cache;
2485 assert(cache_info->signature == MagickSignature);
2486 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2487 if (metacontent != (void *) NULL)
2488 return(metacontent);
2489 assert(id < (int) cache_info->number_threads);
2490 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2491 cache_info->nexus_info[id]);
2492 return(metacontent);
2496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2500 + 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 %
2504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2506 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2507 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2508 % is returned if the pixels are transferred, otherwise a NULL is returned.
2510 % The format of the GetVirtualPixelsFromNexus() method is:
2512 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2513 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2514 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2515 % ExceptionInfo *exception)
2517 % A description of each parameter follows:
2519 % o image: the image.
2521 % o virtual_pixel_method: the virtual pixel method.
2523 % o x,y,columns,rows: These values define the perimeter of a region of
2526 % o nexus_info: the cache nexus to acquire.
2528 % o exception: return any errors or warnings in this structure.
2535 0, 48, 12, 60, 3, 51, 15, 63,
2536 32, 16, 44, 28, 35, 19, 47, 31,
2537 8, 56, 4, 52, 11, 59, 7, 55,
2538 40, 24, 36, 20, 43, 27, 39, 23,
2539 2, 50, 14, 62, 1, 49, 13, 61,
2540 34, 18, 46, 30, 33, 17, 45, 29,
2541 10, 58, 6, 54, 9, 57, 5, 53,
2542 42, 26, 38, 22, 41, 25, 37, 21
2545 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2550 index=x+DitherMatrix[x & 0x07]-32L;
2553 if (index >= (ssize_t) columns)
2554 return((ssize_t) columns-1L);
2558 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2563 index=y+DitherMatrix[y & 0x07]-32L;
2566 if (index >= (ssize_t) rows)
2567 return((ssize_t) rows-1L);
2571 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2575 if (x >= (ssize_t) columns)
2576 return((ssize_t) (columns-1));
2580 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2584 if (y >= (ssize_t) rows)
2585 return((ssize_t) (rows-1));
2589 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2591 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2594 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2596 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2599 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2600 const size_t extent)
2606 Compute the remainder of dividing offset by extent. It returns not only
2607 the quotient (tile the offset falls in) but also the positive remainer
2608 within that tile such that 0 <= remainder < extent. This method is
2609 essentially a ldiv() using a floored modulo division rather than the
2610 normal default truncated modulo division.
2612 modulo.quotient=offset/(ssize_t) extent;
2615 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2619 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2620 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2621 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2622 ExceptionInfo *exception)
2639 virtual_pixel[CompositePixelChannel];
2644 register const Quantum
2657 register unsigned char
2664 *virtual_metacontent;
2669 assert(image != (const Image *) NULL);
2670 assert(image->signature == MagickSignature);
2671 assert(image->cache != (Cache) NULL);
2672 cache_info=(CacheInfo *) image->cache;
2673 assert(cache_info->signature == MagickSignature);
2674 if (cache_info->type == UndefinedCache)
2675 return((const Quantum *) NULL);
2678 region.width=columns;
2680 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2682 if (pixels == (Quantum *) NULL)
2683 return((const Quantum *) NULL);
2685 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2686 nexus_info->region.x;
2687 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2688 nexus_info->region.width-1L;
2689 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2690 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2691 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2692 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2698 Pixel request is inside cache extents.
2700 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2702 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2703 if (status == MagickFalse)
2704 return((const Quantum *) NULL);
2705 if (cache_info->metacontent_extent != 0)
2707 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2708 if (status == MagickFalse)
2709 return((const Quantum *) NULL);
2714 Pixel request is outside cache extents.
2716 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2717 virtual_nexus=AcquirePixelCacheNexus(1);
2718 if (virtual_nexus == (NexusInfo **) NULL)
2720 if (virtual_nexus != (NexusInfo **) NULL)
2721 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2722 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2723 "UnableToGetCacheNexus","`%s'",image->filename);
2724 return((const Quantum *) NULL);
2726 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2727 sizeof(*virtual_pixel));
2728 virtual_metacontent=(void *) NULL;
2729 switch (virtual_pixel_method)
2731 case BackgroundVirtualPixelMethod:
2732 case BlackVirtualPixelMethod:
2733 case GrayVirtualPixelMethod:
2734 case TransparentVirtualPixelMethod:
2735 case MaskVirtualPixelMethod:
2736 case WhiteVirtualPixelMethod:
2737 case EdgeVirtualPixelMethod:
2738 case CheckerTileVirtualPixelMethod:
2739 case HorizontalTileVirtualPixelMethod:
2740 case VerticalTileVirtualPixelMethod:
2742 if (cache_info->metacontent_extent != 0)
2745 Acquire a metacontent buffer.
2747 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2748 cache_info->metacontent_extent);
2749 if (virtual_metacontent == (void *) NULL)
2751 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2752 (void) ThrowMagickException(exception,GetMagickModule(),
2753 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2754 return((const Quantum *) NULL);
2756 (void) ResetMagickMemory(virtual_metacontent,0,
2757 cache_info->metacontent_extent);
2759 switch (virtual_pixel_method)
2761 case BlackVirtualPixelMethod:
2763 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2764 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2765 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2768 case GrayVirtualPixelMethod:
2770 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2771 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2773 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2776 case TransparentVirtualPixelMethod:
2778 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2779 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2780 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2783 case MaskVirtualPixelMethod:
2784 case WhiteVirtualPixelMethod:
2786 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2787 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2788 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2793 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2795 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2797 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2799 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2801 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2811 for (v=0; v < (ssize_t) rows; v++)
2813 for (u=0; u < (ssize_t) columns; u+=length)
2815 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
2816 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
2817 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
2825 Transfer a single pixel.
2827 length=(MagickSizeType) 1;
2828 switch (virtual_pixel_method)
2832 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2833 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
2834 1UL,1UL,*virtual_nexus,exception);
2835 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2838 case RandomVirtualPixelMethod:
2840 if (cache_info->random_info == (RandomInfo *) NULL)
2841 cache_info->random_info=AcquireRandomInfo();
2842 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2843 RandomX(cache_info->random_info,cache_info->columns),
2844 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2845 *virtual_nexus,exception);
2846 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2849 case DitherVirtualPixelMethod:
2851 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2852 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
2853 1UL,1UL,*virtual_nexus,exception);
2854 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2857 case TileVirtualPixelMethod:
2859 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2860 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2861 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2862 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2864 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2867 case MirrorVirtualPixelMethod:
2869 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2870 if ((x_modulo.quotient & 0x01) == 1L)
2871 x_modulo.remainder=(ssize_t) cache_info->columns-
2872 x_modulo.remainder-1L;
2873 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2874 if ((y_modulo.quotient & 0x01) == 1L)
2875 y_modulo.remainder=(ssize_t) cache_info->rows-
2876 y_modulo.remainder-1L;
2877 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2878 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2880 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2883 case HorizontalTileEdgeVirtualPixelMethod:
2885 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2886 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2887 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
2888 *virtual_nexus,exception);
2889 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2892 case VerticalTileEdgeVirtualPixelMethod:
2894 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2895 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2896 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
2897 *virtual_nexus,exception);
2898 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2901 case BackgroundVirtualPixelMethod:
2902 case BlackVirtualPixelMethod:
2903 case GrayVirtualPixelMethod:
2904 case TransparentVirtualPixelMethod:
2905 case MaskVirtualPixelMethod:
2906 case WhiteVirtualPixelMethod:
2909 r=virtual_metacontent;
2912 case EdgeVirtualPixelMethod:
2913 case CheckerTileVirtualPixelMethod:
2915 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2916 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2917 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2920 r=virtual_metacontent;
2923 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2924 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2926 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2929 case HorizontalTileVirtualPixelMethod:
2931 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
2934 r=virtual_metacontent;
2937 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2938 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2939 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2940 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2942 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2945 case VerticalTileVirtualPixelMethod:
2947 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
2950 r=virtual_metacontent;
2953 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2954 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2955 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2956 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2958 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2962 if (p == (const Quantum *) NULL)
2964 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2966 q+=cache_info->number_channels;
2967 if ((s != (void *) NULL) && (r != (const void *) NULL))
2969 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2970 s+=cache_info->metacontent_extent;
2975 Transfer a run of pixels.
2977 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
2978 length,1UL,*virtual_nexus,exception);
2979 if (p == (const Quantum *) NULL)
2981 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2982 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2983 q+=length*cache_info->number_channels;
2984 if ((r != (void *) NULL) && (s != (const void *) NULL))
2986 (void) memcpy(s,r,(size_t) length);
2987 s+=length*cache_info->metacontent_extent;
2994 if (virtual_metacontent != (void *) NULL)
2995 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2996 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3005 + G e t V i r t u a l P i x e l C a c h e %
3009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3011 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3012 % cache as defined by the geometry parameters. A pointer to the pixels
3013 % is returned if the pixels are transferred, otherwise a NULL is returned.
3015 % The format of the GetVirtualPixelCache() method is:
3017 % const Quantum *GetVirtualPixelCache(const Image *image,
3018 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3019 % const ssize_t y,const size_t columns,const size_t rows,
3020 % ExceptionInfo *exception)
3022 % A description of each parameter follows:
3024 % o image: the image.
3026 % o virtual_pixel_method: the virtual pixel method.
3028 % o x,y,columns,rows: These values define the perimeter of a region of
3031 % o exception: return any errors or warnings in this structure.
3034 static const Quantum *GetVirtualPixelCache(const Image *image,
3035 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3036 const size_t columns,const size_t rows,ExceptionInfo *exception)
3042 id = GetOpenMPThreadId();
3047 assert(image != (const Image *) NULL);
3048 assert(image->signature == MagickSignature);
3049 assert(image->cache != (Cache) NULL);
3050 cache_info=(CacheInfo *) image->cache;
3051 assert(cache_info->signature == MagickSignature);
3052 assert(id < (int) cache_info->number_threads);
3053 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3054 cache_info->nexus_info[id],exception);
3059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3063 % G e t V i r t u a l P i x e l Q u e u e %
3067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3069 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3070 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3072 % The format of the GetVirtualPixelQueue() method is:
3074 % const Quantum *GetVirtualPixelQueue(const Image image)
3076 % A description of each parameter follows:
3078 % o image: the image.
3081 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3087 id = GetOpenMPThreadId();
3089 assert(image != (const Image *) NULL);
3090 assert(image->signature == MagickSignature);
3091 assert(image->cache != (Cache) NULL);
3092 cache_info=(CacheInfo *) image->cache;
3093 assert(cache_info->signature == MagickSignature);
3094 if (cache_info->methods.get_virtual_pixels_handler !=
3095 (GetVirtualPixelsHandler) NULL)
3096 return(cache_info->methods.get_virtual_pixels_handler(image));
3097 assert(id < (int) cache_info->number_threads);
3098 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3106 % G e t V i r t u a l P i x e l s %
3110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3112 % GetVirtualPixels() returns an immutable pixel region. If the
3113 % region is successfully accessed, a pointer to it is returned, otherwise
3114 % NULL is returned. The returned pointer may point to a temporary working
3115 % copy of the pixels or it may point to the original pixels in memory.
3116 % Performance is maximized if the selected region is part of one row, or one
3117 % or more full rows, since there is opportunity to access the pixels in-place
3118 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3119 % returned pointer must *never* be deallocated by the user.
3121 % Pixels accessed via the returned pointer represent a simple array of type
3122 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3123 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3124 % access the meta-content (of type void) corresponding to the the
3127 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3129 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3130 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3131 % GetCacheViewAuthenticPixels() instead.
3133 % The format of the GetVirtualPixels() method is:
3135 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3136 % const ssize_t y,const size_t columns,const size_t rows,
3137 % ExceptionInfo *exception)
3139 % A description of each parameter follows:
3141 % o image: the image.
3143 % o x,y,columns,rows: These values define the perimeter of a region of
3146 % o exception: return any errors or warnings in this structure.
3149 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3150 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3151 ExceptionInfo *exception)
3157 id = GetOpenMPThreadId();
3162 assert(image != (const Image *) NULL);
3163 assert(image->signature == MagickSignature);
3164 assert(image->cache != (Cache) NULL);
3165 cache_info=(CacheInfo *) image->cache;
3166 assert(cache_info->signature == MagickSignature);
3167 if (cache_info->methods.get_virtual_pixel_handler !=
3168 (GetVirtualPixelHandler) NULL)
3169 return(cache_info->methods.get_virtual_pixel_handler(image,
3170 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3171 assert(id < (int) cache_info->number_threads);
3172 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3173 columns,rows,cache_info->nexus_info[id],exception);
3178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3182 + 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 %
3186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3188 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3189 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3191 % The format of the GetVirtualPixelsCache() method is:
3193 % Quantum *GetVirtualPixelsCache(const Image *image)
3195 % A description of each parameter follows:
3197 % o image: the image.
3200 static const Quantum *GetVirtualPixelsCache(const Image *image)
3206 id = GetOpenMPThreadId();
3208 assert(image != (const Image *) NULL);
3209 assert(image->signature == MagickSignature);
3210 assert(image->cache != (Cache) NULL);
3211 cache_info=(CacheInfo *) image->cache;
3212 assert(cache_info->signature == MagickSignature);
3213 assert(id < (int) cache_info->number_threads);
3214 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3222 + G e t V i r t u a l P i x e l s N e x u s %
3226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3228 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3231 % The format of the GetVirtualPixelsNexus() method is:
3233 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3234 % NexusInfo *nexus_info)
3236 % A description of each parameter follows:
3238 % o cache: the pixel cache.
3240 % o nexus_info: the cache nexus to return the colormap pixels.
3243 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3244 NexusInfo *nexus_info)
3249 assert(cache != (Cache) NULL);
3250 cache_info=(CacheInfo *) cache;
3251 assert(cache_info->signature == MagickSignature);
3252 if (cache_info->storage_class == UndefinedClass)
3253 return((Quantum *) NULL);
3254 return((const Quantum *) nexus_info->pixels);
3258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3262 + O p e n P i x e l C a c h e %
3266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3268 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3269 % dimensions, allocating space for the image pixels and optionally the
3270 % metacontent, and memory mapping the cache if it is disk based. The cache
3271 % nexus array is initialized as well.
3273 % The format of the OpenPixelCache() method is:
3275 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3276 % ExceptionInfo *exception)
3278 % A description of each parameter follows:
3280 % o image: the image.
3282 % o mode: ReadMode, WriteMode, or IOMode.
3284 % o exception: return any errors or warnings in this structure.
3288 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3290 cache_info->mapped=MagickFalse;
3291 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3292 (size_t) cache_info->length));
3293 if (cache_info->pixels == (Quantum *) NULL)
3295 cache_info->mapped=MagickTrue;
3296 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3297 cache_info->length);
3301 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3308 Open pixel cache on disk.
3310 if (cache_info->file != -1)
3311 return(MagickTrue); /* cache already open */
3312 if (*cache_info->cache_filename == '\0')
3313 file=AcquireUniqueFileResource(cache_info->cache_filename);
3319 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3324 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3325 O_BINARY | O_EXCL,S_MODE);
3327 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3333 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3336 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3341 return(MagickFalse);
3342 (void) AcquireMagickResource(FileResource,1);
3343 cache_info->file=file;
3344 cache_info->mode=mode;
3348 static inline MagickOffsetType WritePixelCacheRegion(
3349 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3350 const MagickSizeType length,const unsigned char *restrict buffer)
3352 register MagickOffsetType
3358 #if !defined(MAGICKCORE_HAVE_PWRITE)
3359 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3360 return((MagickOffsetType) -1);
3363 for (i=0; i < (MagickOffsetType) length; i+=count)
3365 #if !defined(MAGICKCORE_HAVE_PWRITE)
3366 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3367 (MagickSizeType) SSIZE_MAX));
3369 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3370 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3382 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3392 cache_info=(CacheInfo *) image->cache;
3393 if (image->debug != MagickFalse)
3396 format[MaxTextExtent],
3397 message[MaxTextExtent];
3399 (void) FormatMagickSize(length,MagickFalse,format);
3400 (void) FormatLocaleString(message,MaxTextExtent,
3401 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3402 cache_info->cache_filename,cache_info->file,format);
3403 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3405 if (length != (MagickSizeType) ((MagickOffsetType) length))
3406 return(MagickFalse);
3407 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3409 return(MagickFalse);
3410 if ((MagickSizeType) offset >= length)
3412 extent=(MagickOffsetType) length-1;
3413 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3414 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3415 if (cache_info->synchronize != MagickFalse)
3420 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3422 return(MagickFalse);
3425 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3428 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3429 ExceptionInfo *exception)
3436 format[MaxTextExtent],
3437 message[MaxTextExtent];
3453 assert(image != (const Image *) NULL);
3454 assert(image->signature == MagickSignature);
3455 assert(image->cache != (Cache) NULL);
3456 if (image->debug != MagickFalse)
3457 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3458 if ((image->columns == 0) || (image->rows == 0))
3459 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3460 cache_info=(CacheInfo *) image->cache;
3461 assert(cache_info->signature == MagickSignature);
3462 source_info=(*cache_info);
3463 source_info.file=(-1);
3464 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3465 image->filename,(double) GetImageIndexInList(image));
3466 cache_info->storage_class=image->storage_class;
3467 cache_info->colorspace=image->colorspace;
3468 cache_info->alpha_trait=image->alpha_trait;
3469 cache_info->mask=image->mask;
3470 cache_info->rows=image->rows;
3471 cache_info->columns=image->columns;
3472 InitializePixelChannelMap(image);
3473 cache_info->number_channels=GetPixelChannels(image);
3474 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3475 sizeof(*image->channel_map));
3476 cache_info->metacontent_extent=image->metacontent_extent;
3477 cache_info->mode=mode;
3478 if (image->ping != MagickFalse)
3480 cache_info->type=PingCache;
3481 cache_info->pixels=(Quantum *) NULL;
3482 cache_info->metacontent=(void *) NULL;
3483 cache_info->length=0;
3486 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3487 packet_size=cache_info->number_channels*sizeof(Quantum);
3488 if (image->metacontent_extent != 0)
3489 packet_size+=cache_info->metacontent_extent;
3490 length=number_pixels*packet_size;
3491 columns=(size_t) (length/cache_info->rows/packet_size);
3492 if (cache_info->columns != columns)
3493 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3495 cache_info->length=length;
3496 status=AcquireMagickResource(AreaResource,cache_info->length);
3497 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3498 cache_info->metacontent_extent);
3499 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3501 status=AcquireMagickResource(MemoryResource,cache_info->length);
3502 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3503 (cache_info->type == MemoryCache))
3505 AllocatePixelCachePixels(cache_info);
3506 if (cache_info->pixels == (Quantum *) NULL)
3507 cache_info->pixels=source_info.pixels;
3511 Create memory pixel cache.
3514 cache_info->type=MemoryCache;
3515 cache_info->metacontent=(void *) NULL;
3516 if (cache_info->metacontent_extent != 0)
3517 cache_info->metacontent=(void *) (cache_info->pixels+
3518 number_pixels*cache_info->number_channels);
3519 if ((source_info.storage_class != UndefinedClass) &&
3522 status=ClonePixelCacheRepository(cache_info,&source_info,
3524 RelinquishPixelCachePixels(&source_info);
3526 if (image->debug != MagickFalse)
3528 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3529 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3531 (void) FormatLocaleString(message,MaxTextExtent,
3532 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3533 cache_info->filename,cache_info->mapped != MagickFalse ?
3534 "Anonymous" : "Heap",type,(double) cache_info->columns,
3535 (double) cache_info->rows,(double)
3536 cache_info->number_channels,format);
3537 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3543 RelinquishMagickResource(MemoryResource,cache_info->length);
3546 Create pixel cache on disk.
3548 status=AcquireMagickResource(DiskResource,cache_info->length);
3549 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3554 if (cache_info->type == DistributedCache)
3555 RelinquishMagickResource(DiskResource,cache_info->length);
3556 server_info=AcquireDistributeCacheInfo(exception);
3557 if (server_info != (DistributeCacheInfo *) NULL)
3559 status=OpenDistributePixelCache(server_info,image);
3560 if (status == MagickFalse)
3561 server_info=DestroyDistributeCacheInfo(server_info);
3565 Create a distributed pixel cache.
3567 cache_info->type=DistributedCache;
3568 cache_info->server_info=server_info;
3569 (void) FormatLocaleString(cache_info->cache_filename,
3570 MaxTextExtent,"%s:%d",
3571 GetDistributeCacheHostname(cache_info->server_info),
3572 GetDistributeCachePort(cache_info->server_info));
3573 if ((source_info.storage_class != UndefinedClass) &&
3576 status=ClonePixelCacheRepository(cache_info,&source_info,
3578 RelinquishPixelCachePixels(&source_info);
3580 if (image->debug != MagickFalse)
3582 (void) FormatMagickSize(cache_info->length,MagickFalse,
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 GetDistributeCacheFile(cache_info->server_info),type,
3590 (double) cache_info->columns,(double) cache_info->rows,
3591 (double) cache_info->number_channels,format);
3592 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3598 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3599 "CacheResourcesExhausted","`%s'",image->filename);
3600 return(MagickFalse);
3602 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3604 (void) ClosePixelCacheOnDisk(cache_info);
3605 *cache_info->cache_filename='\0';
3607 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3609 RelinquishMagickResource(DiskResource,cache_info->length);
3610 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3612 return(MagickFalse);
3614 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3615 cache_info->length);
3616 if (status == MagickFalse)
3618 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3620 return(MagickFalse);
3622 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3623 cache_info->metacontent_extent);
3624 if (length != (MagickSizeType) ((size_t) length))
3625 cache_info->type=DiskCache;
3628 status=AcquireMagickResource(MapResource,cache_info->length);
3629 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3630 (cache_info->type != MemoryCache))
3631 cache_info->type=DiskCache;
3634 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3635 cache_info->offset,(size_t) cache_info->length);
3636 if (cache_info->pixels == (Quantum *) NULL)
3638 cache_info->type=DiskCache;
3639 cache_info->pixels=source_info.pixels;
3644 Create file-backed memory-mapped pixel cache.
3647 (void) ClosePixelCacheOnDisk(cache_info);
3648 cache_info->type=MapCache;
3649 cache_info->mapped=MagickTrue;
3650 cache_info->metacontent=(void *) NULL;
3651 if (cache_info->metacontent_extent != 0)
3652 cache_info->metacontent=(void *) (cache_info->pixels+
3653 number_pixels*cache_info->number_channels);
3654 if ((source_info.storage_class != UndefinedClass) &&
3657 status=ClonePixelCacheRepository(cache_info,&source_info,
3659 RelinquishPixelCachePixels(&source_info);
3661 if (image->debug != MagickFalse)
3663 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3664 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3666 (void) FormatLocaleString(message,MaxTextExtent,
3667 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3668 cache_info->filename,cache_info->cache_filename,
3669 cache_info->file,type,(double) cache_info->columns,(double)
3670 cache_info->rows,(double) cache_info->number_channels,
3672 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3678 RelinquishMagickResource(MapResource,cache_info->length);
3681 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3683 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3684 RelinquishPixelCachePixels(&source_info);
3686 if (image->debug != MagickFalse)
3688 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3689 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3691 (void) FormatLocaleString(message,MaxTextExtent,
3692 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3693 cache_info->cache_filename,cache_info->file,type,(double)
3694 cache_info->columns,(double) cache_info->rows,(double)
3695 cache_info->number_channels,format);
3696 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3706 + P e r s i s t P i x e l C a c h e %
3710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3712 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3713 % persistent pixel cache is one that resides on disk and is not destroyed
3714 % when the program exits.
3716 % The format of the PersistPixelCache() method is:
3718 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3719 % const MagickBooleanType attach,MagickOffsetType *offset,
3720 % ExceptionInfo *exception)
3722 % A description of each parameter follows:
3724 % o image: the image.
3726 % o filename: the persistent pixel cache filename.
3728 % o attach: A value other than zero initializes the persistent pixel cache.
3730 % o initialize: A value other than zero initializes the persistent pixel
3733 % o offset: the offset in the persistent cache to store pixels.
3735 % o exception: return any errors or warnings in this structure.
3738 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3739 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3740 ExceptionInfo *exception)
3755 assert(image != (Image *) NULL);
3756 assert(image->signature == MagickSignature);
3757 if (image->debug != MagickFalse)
3758 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3759 assert(image->cache != (void *) NULL);
3760 assert(filename != (const char *) NULL);
3761 assert(offset != (MagickOffsetType *) NULL);
3762 page_size=GetMagickPageSize();
3763 cache_info=(CacheInfo *) image->cache;
3764 assert(cache_info->signature == MagickSignature);
3765 if (attach != MagickFalse)
3768 Attach existing persistent pixel cache.
3770 if (image->debug != MagickFalse)
3771 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3772 "attach persistent cache");
3773 (void) CopyMagickString(cache_info->cache_filename,filename,
3775 cache_info->type=DiskCache;
3776 cache_info->offset=(*offset);
3777 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3778 return(MagickFalse);
3779 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3782 if ((cache_info->mode != ReadMode) &&
3783 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3784 (cache_info->reference_count == 1))
3786 LockSemaphoreInfo(cache_info->semaphore);
3787 if ((cache_info->mode != ReadMode) &&
3788 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3789 (cache_info->reference_count == 1))
3795 Usurp existing persistent pixel cache.
3797 status=rename_utf8(cache_info->cache_filename,filename);
3800 (void) CopyMagickString(cache_info->cache_filename,filename,
3802 *offset+=cache_info->length+page_size-(cache_info->length %
3804 UnlockSemaphoreInfo(cache_info->semaphore);
3805 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3806 if (image->debug != MagickFalse)
3807 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3808 "Usurp resident persistent cache");
3812 UnlockSemaphoreInfo(cache_info->semaphore);
3815 Clone persistent pixel cache.
3817 clone_image=(*image);
3818 clone_info=(CacheInfo *) clone_image.cache;
3819 image->cache=ClonePixelCache(cache_info);
3820 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3821 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3822 cache_info->type=DiskCache;
3823 cache_info->offset=(*offset);
3824 cache_info=(CacheInfo *) image->cache;
3825 status=OpenPixelCache(image,IOMode,exception);
3826 if (status != MagickFalse)
3827 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3828 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3829 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3838 + 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 %
3842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3844 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3845 % defined by the region rectangle and returns a pointer to the region. This
3846 % region is subsequently transferred from the pixel cache with
3847 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3848 % pixels are transferred, otherwise a NULL is returned.
3850 % The format of the QueueAuthenticPixelCacheNexus() method is:
3852 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3853 % const ssize_t y,const size_t columns,const size_t rows,
3854 % const MagickBooleanType clone,NexusInfo *nexus_info,
3855 % ExceptionInfo *exception)
3857 % A description of each parameter follows:
3859 % o image: the image.
3861 % o x,y,columns,rows: These values define the perimeter of a region of
3864 % o nexus_info: the cache nexus to set.
3866 % o clone: clone the pixel cache.
3868 % o exception: return any errors or warnings in this structure.
3871 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3872 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3873 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3891 Validate pixel cache geometry.
3893 assert(image != (const Image *) NULL);
3894 assert(image->signature == MagickSignature);
3895 assert(image->cache != (Cache) NULL);
3896 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3897 if (cache_info == (Cache) NULL)
3898 return((Quantum *) NULL);
3899 assert(cache_info->signature == MagickSignature);
3900 if ((cache_info->columns == 0) && (cache_info->rows == 0))
3902 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3903 "NoPixelsDefinedInCache","`%s'",image->filename);
3904 return((Quantum *) NULL);
3906 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3907 (y >= (ssize_t) cache_info->rows))
3909 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3910 "PixelsAreNotAuthentic","`%s'",image->filename);
3911 return((Quantum *) NULL);
3913 offset=(MagickOffsetType) y*cache_info->columns+x;
3915 return((Quantum *) NULL);
3916 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3917 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3918 if ((MagickSizeType) offset >= number_pixels)
3919 return((Quantum *) NULL);
3925 region.width=columns;
3927 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3937 + 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 %
3941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3943 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3944 % defined by the region rectangle and returns a pointer to the region. This
3945 % region is subsequently transferred from the pixel cache with
3946 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3947 % pixels are transferred, otherwise a NULL is returned.
3949 % The format of the QueueAuthenticPixelsCache() method is:
3951 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3952 % const ssize_t y,const size_t columns,const size_t rows,
3953 % ExceptionInfo *exception)
3955 % A description of each parameter follows:
3957 % o image: the image.
3959 % o x,y,columns,rows: These values define the perimeter of a region of
3962 % o exception: return any errors or warnings in this structure.
3965 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3966 const ssize_t y,const size_t columns,const size_t rows,
3967 ExceptionInfo *exception)
3973 id = GetOpenMPThreadId();
3978 assert(image != (const Image *) NULL);
3979 assert(image->signature == MagickSignature);
3980 assert(image->cache != (Cache) NULL);
3981 cache_info=(CacheInfo *) image->cache;
3982 assert(cache_info->signature == MagickSignature);
3983 assert(id < (int) cache_info->number_threads);
3984 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3985 cache_info->nexus_info[id],exception);
3990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3994 % Q u e u e A u t h e n t i c P i x e l s %
3998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4000 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4001 % successfully initialized a pointer to a Quantum array representing the
4002 % region is returned, otherwise NULL is returned. The returned pointer may
4003 % point to a temporary working buffer for the pixels or it may point to the
4004 % final location of the pixels in memory.
4006 % Write-only access means that any existing pixel values corresponding to
4007 % the region are ignored. This is useful if the initial image is being
4008 % created from scratch, or if the existing pixel values are to be
4009 % completely replaced without need to refer to their pre-existing values.
4010 % The application is free to read and write the pixel buffer returned by
4011 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4012 % initialize the pixel array values. Initializing pixel array values is the
4013 % application's responsibility.
4015 % Performance is maximized if the selected region is part of one row, or
4016 % one or more full rows, since then there is opportunity to access the
4017 % pixels in-place (without a copy) if the image is in memory, or in a
4018 % memory-mapped file. The returned pointer must *never* be deallocated
4021 % Pixels accessed via the returned pointer represent a simple array of type
4022 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4023 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4024 % obtain the meta-content (of type void) corresponding to the region.
4025 % Once the Quantum (and/or Quantum) array has been updated, the
4026 % changes must be saved back to the underlying image using
4027 % SyncAuthenticPixels() or they may be lost.
4029 % The format of the QueueAuthenticPixels() method is:
4031 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4032 % const ssize_t y,const size_t columns,const size_t rows,
4033 % ExceptionInfo *exception)
4035 % A description of each parameter follows:
4037 % o image: the image.
4039 % o x,y,columns,rows: These values define the perimeter of a region of
4042 % o exception: return any errors or warnings in this structure.
4045 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4046 const ssize_t y,const size_t columns,const size_t rows,
4047 ExceptionInfo *exception)
4053 id = GetOpenMPThreadId();
4058 assert(image != (Image *) NULL);
4059 assert(image->signature == MagickSignature);
4060 assert(image->cache != (Cache) NULL);
4061 cache_info=(CacheInfo *) image->cache;
4062 assert(cache_info->signature == MagickSignature);
4063 if (cache_info->methods.queue_authentic_pixels_handler !=
4064 (QueueAuthenticPixelsHandler) NULL)
4066 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4070 assert(id < (int) cache_info->number_threads);
4071 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4072 cache_info->nexus_info[id],exception);
4077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4081 + 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 %
4085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4087 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4090 % The format of the ReadPixelCacheMetacontent() method is:
4092 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4093 % NexusInfo *nexus_info,ExceptionInfo *exception)
4095 % A description of each parameter follows:
4097 % o cache_info: the pixel cache.
4099 % o nexus_info: the cache nexus to read the metacontent.
4101 % o exception: return any errors or warnings in this structure.
4105 static inline MagickOffsetType ReadPixelCacheRegion(
4106 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4107 const MagickSizeType length,unsigned char *restrict buffer)
4109 register MagickOffsetType
4115 #if !defined(MAGICKCORE_HAVE_PREAD)
4116 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4117 return((MagickOffsetType) -1);
4120 for (i=0; i < (MagickOffsetType) length; i+=count)
4122 #if !defined(MAGICKCORE_HAVE_PREAD)
4123 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4124 (MagickSizeType) SSIZE_MAX));
4126 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4127 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4139 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4140 NexusInfo *nexus_info,ExceptionInfo *exception)
4153 register unsigned char
4159 if (cache_info->metacontent_extent == 0)
4160 return(MagickFalse);
4161 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4163 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4164 nexus_info->region.x;
4165 length=(MagickSizeType) nexus_info->region.width*
4166 cache_info->metacontent_extent;
4167 extent=length*nexus_info->region.height;
4168 rows=nexus_info->region.height;
4170 q=(unsigned char *) nexus_info->metacontent;
4171 switch (cache_info->type)
4176 register unsigned char
4180 Read meta-content from memory.
4182 if ((cache_info->columns == nexus_info->region.width) &&
4183 (extent == (MagickSizeType) ((size_t) extent)))
4188 p=(unsigned char *) cache_info->metacontent+offset*
4189 cache_info->metacontent_extent;
4190 for (y=0; y < (ssize_t) rows; y++)
4192 (void) memcpy(q,p,(size_t) length);
4193 p+=cache_info->metacontent_extent*cache_info->columns;
4194 q+=cache_info->metacontent_extent*nexus_info->region.width;
4201 Read meta content from disk.
4203 LockSemaphoreInfo(cache_info->file_semaphore);
4204 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4206 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4207 cache_info->cache_filename);
4208 UnlockSemaphoreInfo(cache_info->file_semaphore);
4209 return(MagickFalse);
4211 if ((cache_info->columns == nexus_info->region.width) &&
4212 (extent <= MagickMaxBufferExtent))
4217 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4218 for (y=0; y < (ssize_t) rows; y++)
4220 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4221 cache_info->number_channels*sizeof(Quantum)+offset*
4222 cache_info->metacontent_extent,length,(unsigned char *) q);
4223 if (count != (MagickOffsetType) length)
4225 offset+=cache_info->columns;
4226 q+=cache_info->metacontent_extent*nexus_info->region.width;
4228 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4229 (void) ClosePixelCacheOnDisk(cache_info);
4230 UnlockSemaphoreInfo(cache_info->file_semaphore);
4233 case DistributedCache:
4239 Read metacontent from distributed cache.
4241 LockSemaphoreInfo(cache_info->file_semaphore);
4242 region=nexus_info->region;
4244 for (y=0; y < (ssize_t) rows; y++)
4246 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4247 length,(unsigned char *) q);
4248 if (count != (MagickOffsetType) length)
4250 q+=cache_info->metacontent_extent*nexus_info->region.width;
4253 UnlockSemaphoreInfo(cache_info->file_semaphore);
4259 if (y < (ssize_t) rows)
4261 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4262 cache_info->cache_filename);
4263 return(MagickFalse);
4265 if ((cache_info->debug != MagickFalse) &&
4266 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4267 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4268 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4269 nexus_info->region.width,(double) nexus_info->region.height,(double)
4270 nexus_info->region.x,(double) nexus_info->region.y);
4275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4279 + R e a d P i x e l C a c h e P i x e l s %
4283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4285 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4288 % The format of the ReadPixelCachePixels() method is:
4290 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4291 % NexusInfo *nexus_info,ExceptionInfo *exception)
4293 % A description of each parameter follows:
4295 % o cache_info: the pixel cache.
4297 % o nexus_info: the cache nexus to read the pixels.
4299 % o exception: return any errors or warnings in this structure.
4302 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4303 NexusInfo *nexus_info,ExceptionInfo *exception)
4322 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4324 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4325 nexus_info->region.x;
4326 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4328 extent=length*nexus_info->region.height;
4329 rows=nexus_info->region.height;
4331 q=nexus_info->pixels;
4332 switch (cache_info->type)
4341 Read pixels from memory.
4343 if ((cache_info->columns == nexus_info->region.width) &&
4344 (extent == (MagickSizeType) ((size_t) extent)))
4349 p=cache_info->pixels+offset*cache_info->number_channels;
4350 for (y=0; y < (ssize_t) rows; y++)
4352 (void) memcpy(q,p,(size_t) length);
4353 p+=cache_info->number_channels*cache_info->columns;
4354 q+=cache_info->number_channels*nexus_info->region.width;
4361 Read pixels from disk.
4363 LockSemaphoreInfo(cache_info->file_semaphore);
4364 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4366 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4367 cache_info->cache_filename);
4368 UnlockSemaphoreInfo(cache_info->file_semaphore);
4369 return(MagickFalse);
4371 if ((cache_info->columns == nexus_info->region.width) &&
4372 (extent <= MagickMaxBufferExtent))
4377 for (y=0; y < (ssize_t) rows; y++)
4379 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4380 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4381 if (count != (MagickOffsetType) length)
4383 offset+=cache_info->columns;
4384 q+=cache_info->number_channels*nexus_info->region.width;
4386 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4387 (void) ClosePixelCacheOnDisk(cache_info);
4388 UnlockSemaphoreInfo(cache_info->file_semaphore);
4391 case DistributedCache:
4397 Read pixels from distributed cache.
4399 LockSemaphoreInfo(cache_info->file_semaphore);
4400 region=nexus_info->region;
4402 for (y=0; y < (ssize_t) rows; y++)
4404 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4405 length,(unsigned char *) q);
4406 if (count != (MagickOffsetType) length)
4408 q+=cache_info->number_channels*nexus_info->region.width;
4411 UnlockSemaphoreInfo(cache_info->file_semaphore);
4417 if (y < (ssize_t) rows)
4419 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4420 cache_info->cache_filename);
4421 return(MagickFalse);
4423 if ((cache_info->debug != MagickFalse) &&
4424 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4425 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4426 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4427 nexus_info->region.width,(double) nexus_info->region.height,(double)
4428 nexus_info->region.x,(double) nexus_info->region.y);
4433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4437 + R e f e r e n c e P i x e l C a c h e %
4441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4443 % ReferencePixelCache() increments the reference count associated with the
4444 % pixel cache returning a pointer to the cache.
4446 % The format of the ReferencePixelCache method is:
4448 % Cache ReferencePixelCache(Cache cache_info)
4450 % A description of each parameter follows:
4452 % o cache_info: the pixel cache.
4455 MagickPrivate Cache ReferencePixelCache(Cache cache)
4460 assert(cache != (Cache *) NULL);
4461 cache_info=(CacheInfo *) cache;
4462 assert(cache_info->signature == MagickSignature);
4463 LockSemaphoreInfo(cache_info->semaphore);
4464 cache_info->reference_count++;
4465 UnlockSemaphoreInfo(cache_info->semaphore);
4470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474 + S e t P i x e l C a c h e M e t h o d s %
4478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4480 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4482 % The format of the SetPixelCacheMethods() method is:
4484 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4486 % A description of each parameter follows:
4488 % o cache: the pixel cache.
4490 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4493 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4498 GetOneAuthenticPixelFromHandler
4499 get_one_authentic_pixel_from_handler;
4501 GetOneVirtualPixelFromHandler
4502 get_one_virtual_pixel_from_handler;
4505 Set cache pixel methods.
4507 assert(cache != (Cache) NULL);
4508 assert(cache_methods != (CacheMethods *) NULL);
4509 cache_info=(CacheInfo *) cache;
4510 assert(cache_info->signature == MagickSignature);
4511 if (cache_info->debug != MagickFalse)
4512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4513 cache_info->filename);
4514 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4515 cache_info->methods.get_virtual_pixel_handler=
4516 cache_methods->get_virtual_pixel_handler;
4517 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4518 cache_info->methods.destroy_pixel_handler=
4519 cache_methods->destroy_pixel_handler;
4520 if (cache_methods->get_virtual_metacontent_from_handler !=
4521 (GetVirtualMetacontentFromHandler) NULL)
4522 cache_info->methods.get_virtual_metacontent_from_handler=
4523 cache_methods->get_virtual_metacontent_from_handler;
4524 if (cache_methods->get_authentic_pixels_handler !=
4525 (GetAuthenticPixelsHandler) NULL)
4526 cache_info->methods.get_authentic_pixels_handler=
4527 cache_methods->get_authentic_pixels_handler;
4528 if (cache_methods->queue_authentic_pixels_handler !=
4529 (QueueAuthenticPixelsHandler) NULL)
4530 cache_info->methods.queue_authentic_pixels_handler=
4531 cache_methods->queue_authentic_pixels_handler;
4532 if (cache_methods->sync_authentic_pixels_handler !=
4533 (SyncAuthenticPixelsHandler) NULL)
4534 cache_info->methods.sync_authentic_pixels_handler=
4535 cache_methods->sync_authentic_pixels_handler;
4536 if (cache_methods->get_authentic_pixels_from_handler !=
4537 (GetAuthenticPixelsFromHandler) NULL)
4538 cache_info->methods.get_authentic_pixels_from_handler=
4539 cache_methods->get_authentic_pixels_from_handler;
4540 if (cache_methods->get_authentic_metacontent_from_handler !=
4541 (GetAuthenticMetacontentFromHandler) NULL)
4542 cache_info->methods.get_authentic_metacontent_from_handler=
4543 cache_methods->get_authentic_metacontent_from_handler;
4544 get_one_virtual_pixel_from_handler=
4545 cache_info->methods.get_one_virtual_pixel_from_handler;
4546 if (get_one_virtual_pixel_from_handler !=
4547 (GetOneVirtualPixelFromHandler) NULL)
4548 cache_info->methods.get_one_virtual_pixel_from_handler=
4549 cache_methods->get_one_virtual_pixel_from_handler;
4550 get_one_authentic_pixel_from_handler=
4551 cache_methods->get_one_authentic_pixel_from_handler;
4552 if (get_one_authentic_pixel_from_handler !=
4553 (GetOneAuthenticPixelFromHandler) NULL)
4554 cache_info->methods.get_one_authentic_pixel_from_handler=
4555 cache_methods->get_one_authentic_pixel_from_handler;
4559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4563 + S e t P i x e l C a c h e N e x u s P i x e l s %
4567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4569 % SetPixelCacheNexusPixels() defines the region of the cache for the
4570 % specified cache nexus.
4572 % The format of the SetPixelCacheNexusPixels() method is:
4574 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4575 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4576 % ExceptionInfo *exception)
4578 % A description of each parameter follows:
4580 % o cache_info: the pixel cache.
4582 % o mode: ReadMode, WriteMode, or IOMode.
4584 % o region: A pointer to the RectangleInfo structure that defines the
4585 % region of this particular cache nexus.
4587 % o nexus_info: the cache nexus to set.
4589 % o exception: return any errors or warnings in this structure.
4593 static inline MagickBooleanType AcquireCacheNexusPixels(
4594 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4595 ExceptionInfo *exception)
4597 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4598 return(MagickFalse);
4599 nexus_info->mapped=MagickFalse;
4600 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4601 (size_t) nexus_info->length));
4602 if (nexus_info->cache == (Quantum *) NULL)
4604 nexus_info->mapped=MagickTrue;
4605 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4606 nexus_info->length);
4608 if (nexus_info->cache == (Quantum *) NULL)
4610 (void) ThrowMagickException(exception,GetMagickModule(),
4611 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4612 cache_info->filename);
4613 return(MagickFalse);
4618 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4621 if (mode == ReadMode)
4623 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4626 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4629 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4630 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4631 ExceptionInfo *exception)
4640 assert(cache_info != (const CacheInfo *) NULL);
4641 assert(cache_info->signature == MagickSignature);
4642 if (cache_info->type == UndefinedCache)
4643 return((Quantum *) NULL);
4644 nexus_info->region=(*region);
4645 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4651 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4652 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4653 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4654 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4655 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4656 ((nexus_info->region.width == cache_info->columns) ||
4657 ((nexus_info->region.width % cache_info->columns) == 0)))))
4663 Pixels are accessed directly from memory.
4665 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4666 nexus_info->region.x;
4667 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4669 nexus_info->metacontent=(void *) NULL;
4670 if (cache_info->metacontent_extent != 0)
4671 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4672 offset*cache_info->metacontent_extent;
4673 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4674 return(nexus_info->pixels);
4678 Pixels are stored in a cache region until they are synced to the cache.
4680 number_pixels=(MagickSizeType) nexus_info->region.width*
4681 nexus_info->region.height;
4682 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4683 if (cache_info->metacontent_extent != 0)
4684 length+=number_pixels*cache_info->metacontent_extent;
4685 if (nexus_info->cache == (Quantum *) NULL)
4687 nexus_info->length=length;
4688 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4689 if (status == MagickFalse)
4691 nexus_info->length=0;
4692 return((Quantum *) NULL);
4696 if (nexus_info->length != length)
4698 RelinquishCacheNexusPixels(nexus_info);
4699 nexus_info->length=length;
4700 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4701 if (status == MagickFalse)
4703 nexus_info->length=0;
4704 return((Quantum *) NULL);
4707 nexus_info->pixels=nexus_info->cache;
4708 nexus_info->metacontent=(void *) NULL;
4709 if (cache_info->metacontent_extent != 0)
4710 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4711 cache_info->number_channels);
4712 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4713 return(nexus_info->pixels);
4717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4721 % 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 %
4725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4727 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4728 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4729 % access that is outside the boundaries of the image cache.
4731 % The format of the SetPixelCacheVirtualMethod() method is:
4733 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4734 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4736 % A description of each parameter follows:
4738 % o image: the image.
4740 % o virtual_pixel_method: choose the type of virtual pixel.
4742 % o exception: return any errors or warnings in this structure.
4746 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4747 ExceptionInfo *exception)
4761 assert(image != (Image *) NULL);
4762 assert(image->signature == MagickSignature);
4763 if (image->debug != MagickFalse)
4764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4765 assert(image->cache != (Cache) NULL);
4766 cache_info=(CacheInfo *) image->cache;
4767 assert(cache_info->signature == MagickSignature);
4768 image->alpha_trait=BlendPixelTrait;
4770 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4771 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4772 #pragma omp parallel for schedule(static,4) shared(status) \
4773 magick_threads(image,image,1,1)
4775 for (y=0; y < (ssize_t) image->rows; y++)
4783 if (status == MagickFalse)
4785 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4786 if (q == (Quantum *) NULL)
4791 for (x=0; x < (ssize_t) image->columns; x++)
4793 SetPixelAlpha(image,alpha,q);
4794 q+=GetPixelChannels(image);
4796 status=SyncCacheViewAuthenticPixels(image_view,exception);
4798 image_view=DestroyCacheView(image_view);
4802 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4803 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4811 assert(image != (Image *) NULL);
4812 assert(image->signature == MagickSignature);
4813 if (image->debug != MagickFalse)
4814 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4815 assert(image->cache != (Cache) NULL);
4816 cache_info=(CacheInfo *) image->cache;
4817 assert(cache_info->signature == MagickSignature);
4818 method=cache_info->virtual_pixel_method;
4819 cache_info->virtual_pixel_method=virtual_pixel_method;
4820 if ((image->columns != 0) && (image->rows != 0))
4821 switch (virtual_pixel_method)
4823 case BackgroundVirtualPixelMethod:
4825 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4826 (image->alpha_trait != BlendPixelTrait))
4827 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4828 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4829 (IsGrayColorspace(image->colorspace) != MagickFalse))
4830 (void) TransformImageColorspace(image,RGBColorspace,exception);
4833 case TransparentVirtualPixelMethod:
4835 if (image->alpha_trait != BlendPixelTrait)
4836 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4850 + 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 %
4854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4856 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4857 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4858 % is synced, otherwise MagickFalse.
4860 % The format of the SyncAuthenticPixelCacheNexus() method is:
4862 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4863 % NexusInfo *nexus_info,ExceptionInfo *exception)
4865 % A description of each parameter follows:
4867 % o image: the image.
4869 % o nexus_info: the cache nexus to sync.
4871 % o exception: return any errors or warnings in this structure.
4874 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4875 NexusInfo *nexus_info,ExceptionInfo *exception)
4884 Transfer pixels to the cache.
4886 assert(image != (Image *) NULL);
4887 assert(image->signature == MagickSignature);
4888 if (image->cache == (Cache) NULL)
4889 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4890 cache_info=(CacheInfo *) image->cache;
4891 assert(cache_info->signature == MagickSignature);
4892 if (cache_info->type == UndefinedCache)
4893 return(MagickFalse);
4894 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4896 assert(cache_info->signature == MagickSignature);
4897 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4898 if ((cache_info->metacontent_extent != 0) &&
4899 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4900 return(MagickFalse);
4905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4909 + S y n c A u t h e n t i c P i x e l C a c h e %
4913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4915 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4916 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4917 % otherwise MagickFalse.
4919 % The format of the SyncAuthenticPixelsCache() method is:
4921 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4922 % ExceptionInfo *exception)
4924 % A description of each parameter follows:
4926 % o image: the image.
4928 % o exception: return any errors or warnings in this structure.
4931 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4932 ExceptionInfo *exception)
4938 id = GetOpenMPThreadId();
4943 assert(image != (Image *) NULL);
4944 assert(image->signature == MagickSignature);
4945 assert(image->cache != (Cache) NULL);
4946 cache_info=(CacheInfo *) image->cache;
4947 assert(cache_info->signature == MagickSignature);
4948 assert(id < (int) cache_info->number_threads);
4949 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4959 % S y n c A u t h e n t i c P i x e l s %
4963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4965 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4966 % The method returns MagickTrue if the pixel region is flushed, otherwise
4969 % The format of the SyncAuthenticPixels() method is:
4971 % MagickBooleanType SyncAuthenticPixels(Image *image,
4972 % ExceptionInfo *exception)
4974 % A description of each parameter follows:
4976 % o image: the image.
4978 % o exception: return any errors or warnings in this structure.
4981 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4982 ExceptionInfo *exception)
4988 id = GetOpenMPThreadId();
4993 assert(image != (Image *) NULL);
4994 assert(image->signature == MagickSignature);
4995 assert(image->cache != (Cache) NULL);
4996 cache_info=(CacheInfo *) image->cache;
4997 assert(cache_info->signature == MagickSignature);
4998 if (cache_info->methods.sync_authentic_pixels_handler !=
4999 (SyncAuthenticPixelsHandler) NULL)
5001 status=cache_info->methods.sync_authentic_pixels_handler(image,
5005 assert(id < (int) cache_info->number_threads);
5006 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5016 + S y n c I m a g e P i x e l C a c h e %
5020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5022 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5023 % The method returns MagickTrue if the pixel region is flushed, otherwise
5026 % The format of the SyncImagePixelCache() method is:
5028 % MagickBooleanType SyncImagePixelCache(Image *image,
5029 % ExceptionInfo *exception)
5031 % A description of each parameter follows:
5033 % o image: the image.
5035 % o exception: return any errors or warnings in this structure.
5038 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5039 ExceptionInfo *exception)
5044 assert(image != (Image *) NULL);
5045 assert(exception != (ExceptionInfo *) NULL);
5046 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5047 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5055 + 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 %
5059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5061 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5062 % of the pixel cache.
5064 % The format of the WritePixelCacheMetacontent() method is:
5066 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5067 % NexusInfo *nexus_info,ExceptionInfo *exception)
5069 % A description of each parameter follows:
5071 % o cache_info: the pixel cache.
5073 % o nexus_info: the cache nexus to write the meta-content.
5075 % o exception: return any errors or warnings in this structure.
5078 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5079 NexusInfo *nexus_info,ExceptionInfo *exception)
5089 register const unsigned char
5098 if (cache_info->metacontent_extent == 0)
5099 return(MagickFalse);
5100 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5102 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5103 nexus_info->region.x;
5104 length=(MagickSizeType) nexus_info->region.width*
5105 cache_info->metacontent_extent;
5106 extent=(MagickSizeType) length*nexus_info->region.height;
5107 rows=nexus_info->region.height;
5109 p=(unsigned char *) nexus_info->metacontent;
5110 switch (cache_info->type)
5115 register unsigned char
5119 Write associated pixels to memory.
5121 if ((cache_info->columns == nexus_info->region.width) &&
5122 (extent == (MagickSizeType) ((size_t) extent)))
5127 q=(unsigned char *) cache_info->metacontent+offset*
5128 cache_info->metacontent_extent;
5129 for (y=0; y < (ssize_t) rows; y++)
5131 (void) memcpy(q,p,(size_t) length);
5132 p+=nexus_info->region.width*cache_info->metacontent_extent;
5133 q+=cache_info->columns*cache_info->metacontent_extent;
5140 Write associated pixels to disk.
5142 LockSemaphoreInfo(cache_info->file_semaphore);
5143 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5145 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5146 cache_info->cache_filename);
5147 UnlockSemaphoreInfo(cache_info->file_semaphore);
5148 return(MagickFalse);
5150 if ((cache_info->columns == nexus_info->region.width) &&
5151 (extent <= MagickMaxBufferExtent))
5156 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5157 for (y=0; y < (ssize_t) rows; y++)
5159 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5160 cache_info->number_channels*sizeof(Quantum)+offset*
5161 cache_info->metacontent_extent,length,(const unsigned char *) p);
5162 if (count != (MagickOffsetType) length)
5164 p+=cache_info->metacontent_extent*nexus_info->region.width;
5165 offset+=cache_info->columns;
5167 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5168 (void) ClosePixelCacheOnDisk(cache_info);
5169 UnlockSemaphoreInfo(cache_info->file_semaphore);
5172 case DistributedCache:
5178 Write metacontent to distributed cache.
5180 LockSemaphoreInfo(cache_info->file_semaphore);
5181 region=nexus_info->region;
5183 for (y=0; y < (ssize_t) rows; y++)
5185 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5186 length,(const unsigned char *) p);
5187 if (count != (MagickOffsetType) length)
5189 p+=cache_info->metacontent_extent*nexus_info->region.width;
5192 UnlockSemaphoreInfo(cache_info->file_semaphore);
5198 if (y < (ssize_t) rows)
5200 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5201 cache_info->cache_filename);
5202 return(MagickFalse);
5204 if ((cache_info->debug != MagickFalse) &&
5205 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5206 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5207 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5208 nexus_info->region.width,(double) nexus_info->region.height,(double)
5209 nexus_info->region.x,(double) nexus_info->region.y);
5214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5218 + W r i t e C a c h e P i x e l s %
5222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5224 % WritePixelCachePixels() writes image pixels to the specified region of the
5227 % The format of the WritePixelCachePixels() method is:
5229 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5230 % NexusInfo *nexus_info,ExceptionInfo *exception)
5232 % A description of each parameter follows:
5234 % o cache_info: the pixel cache.
5236 % o nexus_info: the cache nexus to write the pixels.
5238 % o exception: return any errors or warnings in this structure.
5241 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5242 NexusInfo *nexus_info,ExceptionInfo *exception)
5252 register const Quantum
5261 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5263 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5264 nexus_info->region.x;
5265 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5267 extent=length*nexus_info->region.height;
5268 rows=nexus_info->region.height;
5270 p=nexus_info->pixels;
5271 switch (cache_info->type)
5280 Write pixels to memory.
5282 if ((cache_info->columns == nexus_info->region.width) &&
5283 (extent == (MagickSizeType) ((size_t) extent)))
5288 q=cache_info->pixels+offset*cache_info->number_channels;
5289 for (y=0; y < (ssize_t) rows; y++)
5291 (void) memcpy(q,p,(size_t) length);
5292 p+=cache_info->number_channels*nexus_info->region.width;
5293 q+=cache_info->columns*cache_info->number_channels;
5300 Write pixels to disk.
5302 LockSemaphoreInfo(cache_info->file_semaphore);
5303 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5305 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5306 cache_info->cache_filename);
5307 UnlockSemaphoreInfo(cache_info->file_semaphore);
5308 return(MagickFalse);
5310 if ((cache_info->columns == nexus_info->region.width) &&
5311 (extent <= MagickMaxBufferExtent))
5316 for (y=0; y < (ssize_t) rows; y++)
5318 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5319 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5321 if (count != (MagickOffsetType) length)
5323 p+=cache_info->number_channels*nexus_info->region.width;
5324 offset+=cache_info->columns;
5326 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5327 (void) ClosePixelCacheOnDisk(cache_info);
5328 UnlockSemaphoreInfo(cache_info->file_semaphore);
5331 case DistributedCache:
5337 Write pixels to distributed cache.
5339 LockSemaphoreInfo(cache_info->file_semaphore);
5340 region=nexus_info->region;
5342 for (y=0; y < (ssize_t) rows; y++)
5344 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5345 length,(const unsigned char *) p);
5346 if (count != (MagickOffsetType) length)
5348 p+=cache_info->number_channels*nexus_info->region.width;
5351 UnlockSemaphoreInfo(cache_info->file_semaphore);
5357 if (y < (ssize_t) rows)
5359 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5360 cache_info->cache_filename);
5361 return(MagickFalse);
5363 if ((cache_info->debug != MagickFalse) &&
5364 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5365 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5366 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5367 nexus_info->region.width,(double) nexus_info->region.height,(double)
5368 nexus_info->region.x,(double) nexus_info->region.y);