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 P i x e l s %
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
434 % ClonePixelCachePixels() clones the source pixel cache to the destination
437 % The format of the ClonePixelCachePixels() method is:
439 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
440 % CacheInfo *source_info,ExceptionInfo *exception)
442 % A description of each parameter follows:
444 % o cache_info: the pixel cache.
446 % o source_info: the source pixel cache.
448 % o exception: return any errors or warnings in this structure.
452 static inline MagickSizeType MagickMin(const MagickSizeType x,
453 const MagickSizeType y)
460 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
461 CacheInfo *cache_info,ExceptionInfo *exception)
483 assert(cache_info != (CacheInfo *) NULL);
484 assert(clone_info != (CacheInfo *) NULL);
485 assert(exception != (ExceptionInfo *) NULL);
486 if (cache_info->type == PingCache)
488 cache_nexus=AcquirePixelCacheNexus(1);
489 if (cache_nexus == (NexusInfo **) NULL)
490 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
491 clone_nexus=AcquirePixelCacheNexus(1);
492 if (clone_nexus == (NexusInfo **) NULL)
493 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
494 region.width=cache_info->columns;
498 (void) SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[0],
500 region.width=clone_info->columns;
501 (void) SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,clone_nexus[0],
503 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
504 optimize=(cache_info->number_channels == clone_info->number_channels) &&
505 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
506 MagickTrue : MagickFalse;
507 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
508 clone_info->columns*clone_info->number_channels);
510 for (y=0; y < (ssize_t) cache_info->rows; y++)
512 register const Quantum
521 if (y == (ssize_t) clone_info->rows)
523 status=ReadPixelCachePixels(cache_info,cache_nexus[0],exception);
524 if (status == MagickFalse)
526 p=cache_nexus[0]->pixels;
527 q=clone_nexus[0]->pixels;
528 if (optimize != MagickFalse)
529 (void) memcpy(q,p,length*sizeof(Quantum));
531 for (x=0; x < (ssize_t) cache_info->columns; x++)
537 Respect pixel channel map.
539 if (x == (ssize_t) clone_info->columns)
541 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
549 channel=clone_info->channel_map[i].channel;
550 traits=cache_info->channel_map[channel].traits;
551 if (traits != UndefinedPixelTrait)
552 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
556 p+=cache_info->number_channels;
558 status=WritePixelCachePixels(clone_info,clone_nexus[0],exception);
559 if (status == MagickFalse)
561 cache_nexus[0]->region.y++;
562 clone_nexus[0]->region.y++;
564 if ((cache_info->metacontent_extent != 0) &&
565 (clone_info->metacontent_extent != 0))
570 length=(size_t) MagickMin(cache_info->columns*
571 cache_info->metacontent_extent,clone_info->columns*
572 clone_info->metacontent_extent);
573 for (y=0; y < (ssize_t) cache_info->rows; y++)
575 register const unsigned char
578 register unsigned char
581 if (y == (ssize_t) clone_info->rows)
583 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[0],exception);
584 if (status == MagickFalse)
586 p=cache_nexus[0]->metacontent;
587 q=clone_nexus[0]->metacontent;
588 (void) memcpy(q,p,length*sizeof(*cache_nexus[0]->metacontent));
589 status=WritePixelCacheMetacontent(clone_info,clone_nexus[0],exception);
590 if (status == MagickFalse)
592 cache_nexus[0]->region.y++;
593 clone_nexus[0]->region.y++;
596 cache_nexus=DestroyPixelCacheNexus(cache_nexus,1);
597 clone_nexus=DestroyPixelCacheNexus(clone_nexus,1);
598 if (cache_info->debug != MagickFalse)
601 message[MaxTextExtent];
603 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
604 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
605 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
606 (void) LogMagickEvent(CacheEvent,GetMagickModule(),message);
612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616 + C l o n e P i x e l C a c h e M e t h o d s %
620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
625 % The format of the ClonePixelCacheMethods() method is:
627 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
629 % A description of each parameter follows:
631 % o clone: Specifies a pointer to a Cache structure.
633 % o cache: the pixel cache.
636 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
642 assert(clone != (Cache) NULL);
643 source_info=(CacheInfo *) clone;
644 assert(source_info->signature == MagickSignature);
645 if (source_info->debug != MagickFalse)
646 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
647 source_info->filename);
648 assert(cache != (Cache) NULL);
649 cache_info=(CacheInfo *) cache;
650 assert(cache_info->signature == MagickSignature);
651 source_info->methods=cache_info->methods;
655 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 + D e s t r o y I m a g e P i x e l C a c h e %
663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
667 % The format of the DestroyImagePixelCache() method is:
669 % void DestroyImagePixelCache(Image *image)
671 % A description of each parameter follows:
673 % o image: the image.
676 static void DestroyImagePixelCache(Image *image)
678 assert(image != (Image *) NULL);
679 assert(image->signature == MagickSignature);
680 if (image->debug != MagickFalse)
681 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
682 if (image->cache == (void *) NULL)
684 image->cache=DestroyPixelCache(image->cache);
688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692 + D e s t r o y I m a g e P i x e l s %
696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
698 % DestroyImagePixels() deallocates memory associated with the pixel cache.
700 % The format of the DestroyImagePixels() method is:
702 % void DestroyImagePixels(Image *image)
704 % A description of each parameter follows:
706 % o image: the image.
709 MagickExport void DestroyImagePixels(Image *image)
714 assert(image != (const Image *) NULL);
715 assert(image->signature == MagickSignature);
716 if (image->debug != MagickFalse)
717 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
718 assert(image->cache != (Cache) NULL);
719 cache_info=(CacheInfo *) image->cache;
720 assert(cache_info->signature == MagickSignature);
721 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
723 cache_info->methods.destroy_pixel_handler(image);
726 image->cache=DestroyPixelCache(image->cache);
730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
734 + D e s t r o y P i x e l C a c h e %
738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
740 % DestroyPixelCache() deallocates memory associated with the pixel cache.
742 % The format of the DestroyPixelCache() method is:
744 % Cache DestroyPixelCache(Cache cache)
746 % A description of each parameter follows:
748 % o cache: the pixel cache.
752 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
758 if (cache_info->file != -1)
760 status=close(cache_info->file);
761 cache_info->file=(-1);
762 RelinquishMagickResource(FileResource,1);
764 return(status == -1 ? MagickFalse : MagickTrue);
767 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
769 switch (cache_info->type)
773 if (cache_info->mapped == MagickFalse)
774 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
777 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
778 (size_t) cache_info->length);
779 RelinquishMagickResource(MemoryResource,cache_info->length);
784 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
786 if (cache_info->mode != ReadMode)
787 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
788 *cache_info->cache_filename='\0';
789 RelinquishMagickResource(MapResource,cache_info->length);
793 if (cache_info->file != -1)
794 (void) ClosePixelCacheOnDisk(cache_info);
795 if (cache_info->mode != ReadMode)
796 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
797 *cache_info->cache_filename='\0';
798 RelinquishMagickResource(DiskResource,cache_info->length);
801 case DistributedCache:
803 *cache_info->cache_filename='\0';
804 (void) RelinquishDistributePixelCache(cache_info->server_info);
810 cache_info->type=UndefinedCache;
811 cache_info->mapped=MagickFalse;
812 cache_info->metacontent=(void *) NULL;
815 MagickPrivate Cache DestroyPixelCache(Cache cache)
820 assert(cache != (Cache) NULL);
821 cache_info=(CacheInfo *) cache;
822 assert(cache_info->signature == MagickSignature);
823 if (cache_info->debug != MagickFalse)
824 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
825 cache_info->filename);
826 LockSemaphoreInfo(cache_info->semaphore);
827 cache_info->reference_count--;
828 if (cache_info->reference_count != 0)
830 UnlockSemaphoreInfo(cache_info->semaphore);
831 return((Cache) NULL);
833 UnlockSemaphoreInfo(cache_info->semaphore);
834 if (cache_info->debug != MagickFalse)
837 message[MaxTextExtent];
839 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
840 cache_info->filename);
841 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
843 RelinquishPixelCachePixels(cache_info);
844 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
845 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
846 if (cache_info->nexus_info != (NexusInfo **) NULL)
847 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
848 cache_info->number_threads);
849 if (cache_info->random_info != (RandomInfo *) NULL)
850 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
851 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
852 DestroySemaphoreInfo(&cache_info->file_semaphore);
853 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
854 DestroySemaphoreInfo(&cache_info->semaphore);
855 cache_info->signature=(~MagickSignature);
856 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
866 + D e s t r o y P i x e l C a c h e N e x u s %
870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
872 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
874 % The format of the DestroyPixelCacheNexus() method is:
876 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
877 % const size_t number_threads)
879 % A description of each parameter follows:
881 % o nexus_info: the nexus to destroy.
883 % o number_threads: the number of nexus threads.
887 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
889 if (nexus_info->mapped == MagickFalse)
890 (void) RelinquishAlignedMemory(nexus_info->cache);
892 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
893 nexus_info->cache=(Quantum *) NULL;
894 nexus_info->pixels=(Quantum *) NULL;
895 nexus_info->metacontent=(void *) NULL;
896 nexus_info->length=0;
897 nexus_info->mapped=MagickFalse;
900 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
901 const size_t number_threads)
906 assert(nexus_info != (NexusInfo **) NULL);
907 for (i=0; i < (ssize_t) number_threads; i++)
909 if (nexus_info[i]->cache != (Quantum *) NULL)
910 RelinquishCacheNexusPixels(nexus_info[i]);
911 nexus_info[i]->signature=(~MagickSignature);
913 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
914 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923 % G e t A u t h e n t i c M e t a c o n t e n t %
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
930 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
931 % returned if the associated pixels are not available.
933 % The format of the GetAuthenticMetacontent() method is:
935 % void *GetAuthenticMetacontent(const Image *image)
937 % A description of each parameter follows:
939 % o image: the image.
942 MagickExport void *GetAuthenticMetacontent(const Image *image)
948 id = GetOpenMPThreadId();
953 assert(image != (const Image *) NULL);
954 assert(image->signature == MagickSignature);
955 assert(image->cache != (Cache) NULL);
956 cache_info=(CacheInfo *) image->cache;
957 assert(cache_info->signature == MagickSignature);
958 if (cache_info->methods.get_authentic_metacontent_from_handler !=
959 (GetAuthenticMetacontentFromHandler) NULL)
961 metacontent=cache_info->methods.
962 get_authentic_metacontent_from_handler(image);
965 assert(id < (int) cache_info->number_threads);
966 metacontent=GetPixelCacheNexusMetacontent(cache_info,
967 cache_info->nexus_info[id]);
972 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976 + 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 %
980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
983 % with the last call to QueueAuthenticPixelsCache() or
984 % GetAuthenticPixelsCache().
986 % The format of the GetAuthenticMetacontentFromCache() method is:
988 % void *GetAuthenticMetacontentFromCache(const Image *image)
990 % A description of each parameter follows:
992 % o image: the image.
995 static void *GetAuthenticMetacontentFromCache(const Image *image)
1001 id = GetOpenMPThreadId();
1006 assert(image != (const Image *) NULL);
1007 assert(image->signature == MagickSignature);
1008 assert(image->cache != (Cache) NULL);
1009 cache_info=(CacheInfo *) image->cache;
1010 assert(cache_info->signature == MagickSignature);
1011 assert(id < (int) cache_info->number_threads);
1012 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1013 cache_info->nexus_info[id]);
1014 return(metacontent);
1018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022 + 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 %
1026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1029 % disk pixel cache as defined by the geometry parameters. A pointer to the
1030 % pixels is returned if the pixels are transferred, otherwise a NULL is
1033 % The format of the GetAuthenticPixelCacheNexus() method is:
1035 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1036 % const ssize_t y,const size_t columns,const size_t rows,
1037 % NexusInfo *nexus_info,ExceptionInfo *exception)
1039 % A description of each parameter follows:
1041 % o image: the image.
1043 % o x,y,columns,rows: These values define the perimeter of a region of
1046 % o nexus_info: the cache nexus to return.
1048 % o exception: return any errors or warnings in this structure.
1052 static inline MagickBooleanType IsPixelAuthentic(
1053 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1061 if (cache_info->type == PingCache)
1063 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1064 nexus_info->region.x;
1065 status=nexus_info->pixels == (cache_info->pixels+offset*
1066 cache_info->number_channels) ? MagickTrue : MagickFalse;
1070 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1071 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1072 NexusInfo *nexus_info,ExceptionInfo *exception)
1081 Transfer pixels from the cache.
1083 assert(image != (Image *) NULL);
1084 assert(image->signature == MagickSignature);
1085 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1087 if (q == (Quantum *) NULL)
1088 return((Quantum *) NULL);
1089 cache_info=(CacheInfo *) image->cache;
1090 assert(cache_info->signature == MagickSignature);
1091 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1093 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1094 return((Quantum *) NULL);
1095 if (cache_info->metacontent_extent != 0)
1096 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1097 return((Quantum *) NULL);
1102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1106 + 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 %
1110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1112 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1113 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1115 % The format of the GetAuthenticPixelsFromCache() method is:
1117 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1119 % A description of each parameter follows:
1121 % o image: the image.
1124 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1130 id = GetOpenMPThreadId();
1132 assert(image != (const Image *) NULL);
1133 assert(image->signature == MagickSignature);
1134 assert(image->cache != (Cache) NULL);
1135 cache_info=(CacheInfo *) image->cache;
1136 assert(cache_info->signature == MagickSignature);
1137 assert(id < (int) cache_info->number_threads);
1138 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1146 % G e t A u t h e n t i c P i x e l Q u e u e %
1150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 % GetAuthenticPixelQueue() returns the authentic pixels associated
1153 % corresponding with the last call to QueueAuthenticPixels() or
1154 % GetAuthenticPixels().
1156 % The format of the GetAuthenticPixelQueue() method is:
1158 % Quantum *GetAuthenticPixelQueue(const Image image)
1160 % A description of each parameter follows:
1162 % o image: the image.
1165 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1171 id = GetOpenMPThreadId();
1173 assert(image != (const Image *) NULL);
1174 assert(image->signature == MagickSignature);
1175 assert(image->cache != (Cache) NULL);
1176 cache_info=(CacheInfo *) image->cache;
1177 assert(cache_info->signature == MagickSignature);
1178 if (cache_info->methods.get_authentic_pixels_from_handler !=
1179 (GetAuthenticPixelsFromHandler) NULL)
1180 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1181 assert(id < (int) cache_info->number_threads);
1182 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1190 % G e t A u t h e n t i c P i x e l s %
1193 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1195 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1196 % region is successfully accessed, a pointer to a Quantum array
1197 % representing the region is returned, otherwise NULL is returned.
1199 % The returned pointer may point to a temporary working copy of the pixels
1200 % or it may point to the original pixels in memory. Performance is maximized
1201 % if the selected region is part of one row, or one or more full rows, since
1202 % then there is opportunity to access the pixels in-place (without a copy)
1203 % if the image is in memory, or in a memory-mapped file. The returned pointer
1204 % must *never* be deallocated by the user.
1206 % Pixels accessed via the returned pointer represent a simple array of type
1207 % Quantum. If the image has corresponding metacontent,call
1208 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1209 % meta-content corresponding to the region. Once the Quantum array has
1210 % been updated, the changes must be saved back to the underlying image using
1211 % SyncAuthenticPixels() or they may be lost.
1213 % The format of the GetAuthenticPixels() method is:
1215 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1216 % const ssize_t y,const size_t columns,const size_t rows,
1217 % ExceptionInfo *exception)
1219 % A description of each parameter follows:
1221 % o image: the image.
1223 % o x,y,columns,rows: These values define the perimeter of a region of
1226 % o exception: return any errors or warnings in this structure.
1229 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1230 const ssize_t y,const size_t columns,const size_t rows,
1231 ExceptionInfo *exception)
1237 id = GetOpenMPThreadId();
1242 assert(image != (Image *) NULL);
1243 assert(image->signature == MagickSignature);
1244 assert(image->cache != (Cache) NULL);
1245 cache_info=(CacheInfo *) image->cache;
1246 assert(cache_info->signature == MagickSignature);
1247 if (cache_info->methods.get_authentic_pixels_handler !=
1248 (GetAuthenticPixelsHandler) NULL)
1250 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1254 assert(id < (int) cache_info->number_threads);
1255 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1256 cache_info->nexus_info[id],exception);
1261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1265 + G e t A u t h e n t i c P i x e l s C a c h e %
1269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1271 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1272 % as defined by the geometry parameters. A pointer to the pixels is returned
1273 % if the pixels are transferred, otherwise a NULL is returned.
1275 % The format of the GetAuthenticPixelsCache() method is:
1277 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1278 % const ssize_t y,const size_t columns,const size_t rows,
1279 % ExceptionInfo *exception)
1281 % A description of each parameter follows:
1283 % o image: the image.
1285 % o x,y,columns,rows: These values define the perimeter of a region of
1288 % o exception: return any errors or warnings in this structure.
1291 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1292 const ssize_t y,const size_t columns,const size_t rows,
1293 ExceptionInfo *exception)
1299 id = GetOpenMPThreadId();
1304 assert(image != (const Image *) NULL);
1305 assert(image->signature == MagickSignature);
1306 assert(image->cache != (Cache) NULL);
1307 cache_info=(CacheInfo *) image->cache;
1308 if (cache_info == (Cache) NULL)
1309 return((Quantum *) NULL);
1310 assert(cache_info->signature == MagickSignature);
1311 assert(id < (int) cache_info->number_threads);
1312 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1313 cache_info->nexus_info[id],exception);
1318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 + G e t I m a g e E x t e n t %
1326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1328 % GetImageExtent() returns the extent of the pixels associated corresponding
1329 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1331 % The format of the GetImageExtent() method is:
1333 % MagickSizeType GetImageExtent(const Image *image)
1335 % A description of each parameter follows:
1337 % o image: the image.
1340 MagickExport MagickSizeType GetImageExtent(const Image *image)
1346 id = GetOpenMPThreadId();
1348 assert(image != (Image *) NULL);
1349 assert(image->signature == MagickSignature);
1350 if (image->debug != MagickFalse)
1351 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1352 assert(image->cache != (Cache) NULL);
1353 cache_info=(CacheInfo *) image->cache;
1354 assert(cache_info->signature == MagickSignature);
1355 assert(id < (int) cache_info->number_threads);
1356 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364 + G e t I m a g e P i x e l C a c h e %
1368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370 % GetImagePixelCache() ensures that there is only a single reference to the
1371 % pixel cache to be modified, updating the provided cache pointer to point to
1372 % a clone of the original pixel cache if necessary.
1374 % The format of the GetImagePixelCache method is:
1376 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1377 % ExceptionInfo *exception)
1379 % A description of each parameter follows:
1381 % o image: the image.
1383 % o clone: any value other than MagickFalse clones the cache pixels.
1385 % o exception: return any errors or warnings in this structure.
1389 static inline MagickBooleanType ValidatePixelCacheMorphology(
1390 const Image *restrict image)
1393 *restrict cache_info;
1395 const PixelChannelMap
1400 Does the image match the pixel cache morphology?
1402 cache_info=(CacheInfo *) image->cache;
1403 p=image->channel_map;
1404 q=cache_info->channel_map;
1405 if ((image->storage_class != cache_info->storage_class) ||
1406 (image->colorspace != cache_info->colorspace) ||
1407 (image->alpha_trait != cache_info->alpha_trait) ||
1408 (image->mask != cache_info->mask) ||
1409 (image->columns != cache_info->columns) ||
1410 (image->rows != cache_info->rows) ||
1411 (image->number_channels != cache_info->number_channels) ||
1412 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1413 (image->metacontent_extent != cache_info->metacontent_extent) ||
1414 (cache_info->nexus_info == (NexusInfo **) NULL))
1415 return(MagickFalse);
1419 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1420 ExceptionInfo *exception)
1429 static MagickSizeType
1435 cache_timestamp = 0;
1438 LockSemaphoreInfo(image->semaphore);
1439 if (cpu_throttle == 0)
1445 Set CPU throttle in milleseconds.
1447 cpu_throttle=MagickResourceInfinity;
1448 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1449 if (limit == (char *) NULL)
1450 limit=GetPolicyValue("throttle");
1451 if (limit != (char *) NULL)
1453 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1454 limit=DestroyString(limit);
1457 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1458 MagickDelay(cpu_throttle);
1459 if (time_limit == 0)
1462 Set the expire time in seconds.
1464 time_limit=GetMagickResourceLimit(TimeResource);
1465 cache_timestamp=time((time_t *) NULL);
1467 if ((time_limit != MagickResourceInfinity) &&
1468 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1469 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1470 assert(image->cache != (Cache) NULL);
1471 cache_info=(CacheInfo *) image->cache;
1472 destroy=MagickFalse;
1473 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1475 LockSemaphoreInfo(cache_info->semaphore);
1476 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1487 clone_image=(*image);
1488 clone_image.semaphore=AllocateSemaphoreInfo();
1489 clone_image.reference_count=1;
1490 clone_image.cache=ClonePixelCache(cache_info);
1491 clone_info=(CacheInfo *) clone_image.cache;
1492 status=OpenPixelCache(&clone_image,IOMode,exception);
1493 if (status != MagickFalse)
1495 if (clone != MagickFalse)
1496 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1497 if (status != MagickFalse)
1499 if (cache_info->reference_count == 1)
1500 cache_info->nexus_info=(NexusInfo **) NULL;
1502 image->cache=clone_image.cache;
1505 DestroySemaphoreInfo(&clone_image.semaphore);
1507 UnlockSemaphoreInfo(cache_info->semaphore);
1509 if (destroy != MagickFalse)
1510 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1511 if (status != MagickFalse)
1514 Ensure the image matches the pixel cache morphology.
1516 image->taint=MagickTrue;
1517 image->type=UndefinedType;
1518 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1520 status=OpenPixelCache(image,IOMode,exception);
1521 cache_info=(CacheInfo *) image->cache;
1522 if (cache_info->type == DiskCache)
1523 (void) ClosePixelCacheOnDisk(cache_info);
1526 UnlockSemaphoreInfo(image->semaphore);
1527 if (status == MagickFalse)
1528 return((Cache) NULL);
1529 return(image->cache);
1533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1537 + G e t I m a g e P i x e l C a c h e T y p e %
1541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1544 % DiskCache, MemoryCache, MapCache, or PingCache.
1546 % The format of the GetImagePixelCacheType() method is:
1548 % CacheType GetImagePixelCacheType(const Image *image)
1550 % A description of each parameter follows:
1552 % o image: the image.
1555 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1560 assert(image != (Image *) NULL);
1561 assert(image->signature == MagickSignature);
1562 assert(image->cache != (Cache) NULL);
1563 cache_info=(CacheInfo *) image->cache;
1564 assert(cache_info->signature == MagickSignature);
1565 return(cache_info->type);
1569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573 % G e t O n e A u t h e n t i c P i x e l %
1577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1580 % location. The image background color is returned if an error occurs.
1582 % The format of the GetOneAuthenticPixel() method is:
1584 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1585 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1587 % A description of each parameter follows:
1589 % o image: the image.
1591 % o x,y: These values define the location of the pixel to return.
1593 % o pixel: return a pixel at the specified (x,y) location.
1595 % o exception: return any errors or warnings in this structure.
1598 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1599 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1610 assert(image != (Image *) NULL);
1611 assert(image->signature == MagickSignature);
1612 assert(image->cache != (Cache) NULL);
1613 cache_info=(CacheInfo *) image->cache;
1614 assert(cache_info->signature == MagickSignature);
1615 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1616 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1617 (GetOneAuthenticPixelFromHandler) NULL)
1618 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1620 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1621 if (q == (Quantum *) NULL)
1623 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1624 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1625 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1626 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1627 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1628 return(MagickFalse);
1630 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1635 channel=GetPixelChannelChannel(image,i);
1636 pixel[channel]=q[i];
1642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1646 + 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 %
1650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1652 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1653 % location. The image background color is returned if an error occurs.
1655 % The format of the GetOneAuthenticPixelFromCache() method is:
1657 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1658 % const ssize_t x,const ssize_t y,Quantum *pixel,
1659 % ExceptionInfo *exception)
1661 % A description of each parameter follows:
1663 % o image: the image.
1665 % o x,y: These values define the location of the pixel to return.
1667 % o pixel: return a pixel at the specified (x,y) location.
1669 % o exception: return any errors or warnings in this structure.
1672 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1673 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1679 id = GetOpenMPThreadId();
1687 assert(image != (const Image *) NULL);
1688 assert(image->signature == MagickSignature);
1689 assert(image->cache != (Cache) NULL);
1690 cache_info=(CacheInfo *) image->cache;
1691 assert(cache_info->signature == MagickSignature);
1692 assert(id < (int) cache_info->number_threads);
1693 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1694 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1696 if (q == (Quantum *) NULL)
1698 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1699 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1700 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1701 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1702 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1703 return(MagickFalse);
1705 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1710 channel=GetPixelChannelChannel(image,i);
1711 pixel[channel]=q[i];
1717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1721 % G e t O n e V i r t u a l P i x e l %
1725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1728 % (x,y) location. The image background color is returned if an error occurs.
1729 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1731 % The format of the GetOneVirtualPixel() method is:
1733 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1734 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1736 % A description of each parameter follows:
1738 % o image: the image.
1740 % o x,y: These values define the location of the pixel to return.
1742 % o pixel: return a pixel at the specified (x,y) location.
1744 % o exception: return any errors or warnings in this structure.
1747 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1748 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1754 id = GetOpenMPThreadId();
1762 assert(image != (const Image *) NULL);
1763 assert(image->signature == MagickSignature);
1764 assert(image->cache != (Cache) NULL);
1765 cache_info=(CacheInfo *) image->cache;
1766 assert(cache_info->signature == MagickSignature);
1767 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1768 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1769 (GetOneVirtualPixelFromHandler) NULL)
1770 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1771 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1772 assert(id < (int) cache_info->number_threads);
1773 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1774 1UL,1UL,cache_info->nexus_info[id],exception);
1775 if (p == (const Quantum *) NULL)
1777 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1778 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1779 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1780 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1781 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1782 return(MagickFalse);
1784 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1789 channel=GetPixelChannelChannel(image,i);
1790 pixel[channel]=p[i];
1796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1800 + 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 %
1804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1806 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1807 % specified (x,y) location. The image background color is returned if an
1810 % The format of the GetOneVirtualPixelFromCache() method is:
1812 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1813 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1814 % Quantum *pixel,ExceptionInfo *exception)
1816 % A description of each parameter follows:
1818 % o image: the image.
1820 % o virtual_pixel_method: the virtual pixel method.
1822 % o x,y: These values define the location of the pixel to return.
1824 % o pixel: return a pixel at the specified (x,y) location.
1826 % o exception: return any errors or warnings in this structure.
1829 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1830 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1831 Quantum *pixel,ExceptionInfo *exception)
1837 id = GetOpenMPThreadId();
1845 assert(image != (const Image *) NULL);
1846 assert(image->signature == MagickSignature);
1847 assert(image->cache != (Cache) NULL);
1848 cache_info=(CacheInfo *) image->cache;
1849 assert(cache_info->signature == MagickSignature);
1850 assert(id < (int) cache_info->number_threads);
1851 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1852 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1853 cache_info->nexus_info[id],exception);
1854 if (p == (const Quantum *) NULL)
1856 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1857 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1858 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1859 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1860 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1861 return(MagickFalse);
1863 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1868 channel=GetPixelChannelChannel(image,i);
1869 pixel[channel]=p[i];
1875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1879 % G e t O n e V i r t u a l P i x e l I n f o %
1883 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1885 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1886 % location. The image background color is returned if an error occurs. If
1887 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1889 % The format of the GetOneVirtualPixelInfo() method is:
1891 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1892 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1893 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1895 % A description of each parameter follows:
1897 % o image: the image.
1899 % o virtual_pixel_method: the virtual pixel method.
1901 % o x,y: these values define the location of the pixel to return.
1903 % o pixel: return a pixel at the specified (x,y) location.
1905 % o exception: return any errors or warnings in this structure.
1908 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1909 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1910 PixelInfo *pixel,ExceptionInfo *exception)
1916 id = GetOpenMPThreadId();
1918 register const Quantum
1921 assert(image != (const Image *) NULL);
1922 assert(image->signature == MagickSignature);
1923 assert(image->cache != (Cache) NULL);
1924 cache_info=(CacheInfo *) image->cache;
1925 assert(cache_info->signature == MagickSignature);
1926 assert(id < (int) cache_info->number_threads);
1927 GetPixelInfo(image,pixel);
1928 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1929 cache_info->nexus_info[id],exception);
1930 if (p == (const Quantum *) NULL)
1931 return(MagickFalse);
1932 GetPixelInfoPixel(image,p,pixel);
1937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1941 + G e t P i x e l C a c h e C o l o r s p a c e %
1945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1947 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1949 % The format of the GetPixelCacheColorspace() method is:
1951 % Colorspace GetPixelCacheColorspace(Cache cache)
1953 % A description of each parameter follows:
1955 % o cache: the pixel cache.
1958 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1963 assert(cache != (Cache) NULL);
1964 cache_info=(CacheInfo *) cache;
1965 assert(cache_info->signature == MagickSignature);
1966 if (cache_info->debug != MagickFalse)
1967 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1968 cache_info->filename);
1969 return(cache_info->colorspace);
1973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977 + G e t P i x e l C a c h e M e t h o d s %
1981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983 % GetPixelCacheMethods() initializes the CacheMethods structure.
1985 % The format of the GetPixelCacheMethods() method is:
1987 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1989 % A description of each parameter follows:
1991 % o cache_methods: Specifies a pointer to a CacheMethods structure.
1994 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
1996 assert(cache_methods != (CacheMethods *) NULL);
1997 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
1998 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
1999 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2000 cache_methods->get_virtual_metacontent_from_handler=
2001 GetVirtualMetacontentFromCache;
2002 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2003 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2004 cache_methods->get_authentic_metacontent_from_handler=
2005 GetAuthenticMetacontentFromCache;
2006 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2007 cache_methods->get_one_authentic_pixel_from_handler=
2008 GetOneAuthenticPixelFromCache;
2009 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2010 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2011 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019 + G e t P i x e l C a c h e N e x u s E x t e n t %
2023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2025 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2026 % corresponding with the last call to SetPixelCacheNexusPixels() or
2027 % GetPixelCacheNexusPixels().
2029 % The format of the GetPixelCacheNexusExtent() method is:
2031 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2032 % NexusInfo *nexus_info)
2034 % A description of each parameter follows:
2036 % o nexus_info: the nexus info.
2039 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2040 NexusInfo *nexus_info)
2048 assert(cache != NULL);
2049 cache_info=(CacheInfo *) cache;
2050 assert(cache_info->signature == MagickSignature);
2051 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2053 return((MagickSizeType) cache_info->columns*cache_info->rows);
2058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2062 + 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 %
2066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2068 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2071 % The format of the GetPixelCacheNexusMetacontent() method is:
2073 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2074 % NexusInfo *nexus_info)
2076 % A description of each parameter follows:
2078 % o cache: the pixel cache.
2080 % o nexus_info: the cache nexus to return the meta-content.
2083 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2084 NexusInfo *nexus_info)
2089 assert(cache != NULL);
2090 cache_info=(CacheInfo *) cache;
2091 assert(cache_info->signature == MagickSignature);
2092 if (cache_info->storage_class == UndefinedClass)
2093 return((void *) NULL);
2094 return(nexus_info->metacontent);
2098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102 + G e t P i x e l C a c h e N e x u s P i x e l s %
2106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2108 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2111 % The format of the GetPixelCacheNexusPixels() method is:
2113 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2114 % NexusInfo *nexus_info)
2116 % A description of each parameter follows:
2118 % o cache: the pixel cache.
2120 % o nexus_info: the cache nexus to return the pixels.
2123 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2124 NexusInfo *nexus_info)
2129 assert(cache != NULL);
2130 cache_info=(CacheInfo *) cache;
2131 assert(cache_info->signature == MagickSignature);
2132 if (cache_info->storage_class == UndefinedClass)
2133 return((Quantum *) NULL);
2134 return(nexus_info->pixels);
2138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2142 + G e t P i x e l C a c h e P i x e l s %
2146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2148 % GetPixelCachePixels() returns the pixels associated with the specified image.
2150 % The format of the GetPixelCachePixels() method is:
2152 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2153 % ExceptionInfo *exception)
2155 % A description of each parameter follows:
2157 % o image: the image.
2159 % o length: the pixel cache length.
2161 % o exception: return any errors or warnings in this structure.
2164 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2165 ExceptionInfo *exception)
2170 assert(image != (const Image *) NULL);
2171 assert(image->signature == MagickSignature);
2172 assert(image->cache != (Cache) NULL);
2173 assert(length != (MagickSizeType *) NULL);
2174 assert(exception != (ExceptionInfo *) NULL);
2175 assert(exception->signature == MagickSignature);
2176 cache_info=(CacheInfo *) image->cache;
2177 assert(cache_info->signature == MagickSignature);
2179 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2180 return((void *) NULL);
2181 *length=cache_info->length;
2182 return((void *) cache_info->pixels);
2186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2190 + 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 %
2194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2196 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2198 % The format of the GetPixelCacheStorageClass() method is:
2200 % ClassType GetPixelCacheStorageClass(Cache cache)
2202 % A description of each parameter follows:
2204 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2206 % o cache: the pixel cache.
2209 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2214 assert(cache != (Cache) NULL);
2215 cache_info=(CacheInfo *) cache;
2216 assert(cache_info->signature == MagickSignature);
2217 if (cache_info->debug != MagickFalse)
2218 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2219 cache_info->filename);
2220 return(cache_info->storage_class);
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2228 + G e t P i x e l C a c h e T i l e S i z e %
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2234 % GetPixelCacheTileSize() returns the pixel cache tile size.
2236 % The format of the GetPixelCacheTileSize() method is:
2238 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2241 % A description of each parameter follows:
2243 % o image: the image.
2245 % o width: the optimize cache tile width in pixels.
2247 % o height: the optimize cache tile height in pixels.
2250 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2256 assert(image != (Image *) NULL);
2257 assert(image->signature == MagickSignature);
2258 if (image->debug != MagickFalse)
2259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2260 cache_info=(CacheInfo *) image->cache;
2261 assert(cache_info->signature == MagickSignature);
2262 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2263 if (GetImagePixelCacheType(image) == DiskCache)
2264 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273 + 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 %
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2280 % pixel cache. A virtual pixel is any pixel access that is outside the
2281 % boundaries of the image cache.
2283 % The format of the GetPixelCacheVirtualMethod() method is:
2285 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2287 % A description of each parameter follows:
2289 % o image: the image.
2292 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2297 assert(image != (Image *) NULL);
2298 assert(image->signature == MagickSignature);
2299 assert(image->cache != (Cache) NULL);
2300 cache_info=(CacheInfo *) image->cache;
2301 assert(cache_info->signature == MagickSignature);
2302 return(cache_info->virtual_pixel_method);
2306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2310 + 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 %
2314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2316 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2317 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2319 % The format of the GetVirtualMetacontentFromCache() method is:
2321 % void *GetVirtualMetacontentFromCache(const Image *image)
2323 % A description of each parameter follows:
2325 % o image: the image.
2328 static const void *GetVirtualMetacontentFromCache(const Image *image)
2334 id = GetOpenMPThreadId();
2339 assert(image != (const Image *) NULL);
2340 assert(image->signature == MagickSignature);
2341 assert(image->cache != (Cache) NULL);
2342 cache_info=(CacheInfo *) image->cache;
2343 assert(cache_info->signature == MagickSignature);
2344 assert(id < (int) cache_info->number_threads);
2345 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2346 cache_info->nexus_info[id]);
2347 return(metacontent);
2351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2355 + 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 %
2359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2361 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2364 % The format of the GetVirtualMetacontentFromNexus() method is:
2366 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2367 % NexusInfo *nexus_info)
2369 % A description of each parameter follows:
2371 % o cache: the pixel cache.
2373 % o nexus_info: the cache nexus to return the meta-content.
2376 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2377 NexusInfo *nexus_info)
2382 assert(cache != (Cache) NULL);
2383 cache_info=(CacheInfo *) cache;
2384 assert(cache_info->signature == MagickSignature);
2385 if (cache_info->storage_class == UndefinedClass)
2386 return((void *) NULL);
2387 return(nexus_info->metacontent);
2391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2395 % G e t V i r t u a l M e t a c o n t e n t %
2399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2401 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2402 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2403 % returned if the meta-content are not available.
2405 % The format of the GetVirtualMetacontent() method is:
2407 % const void *GetVirtualMetacontent(const Image *image)
2409 % A description of each parameter follows:
2411 % o image: the image.
2414 MagickExport const void *GetVirtualMetacontent(const Image *image)
2420 id = GetOpenMPThreadId();
2425 assert(image != (const Image *) NULL);
2426 assert(image->signature == MagickSignature);
2427 assert(image->cache != (Cache) NULL);
2428 cache_info=(CacheInfo *) image->cache;
2429 assert(cache_info->signature == MagickSignature);
2430 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2431 if (metacontent != (void *) NULL)
2432 return(metacontent);
2433 assert(id < (int) cache_info->number_threads);
2434 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2435 cache_info->nexus_info[id]);
2436 return(metacontent);
2440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2444 + 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 %
2448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2450 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2451 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2452 % is returned if the pixels are transferred, otherwise a NULL is returned.
2454 % The format of the GetVirtualPixelsFromNexus() method is:
2456 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2457 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2458 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2459 % ExceptionInfo *exception)
2461 % A description of each parameter follows:
2463 % o image: the image.
2465 % o virtual_pixel_method: the virtual pixel method.
2467 % o x,y,columns,rows: These values define the perimeter of a region of
2470 % o nexus_info: the cache nexus to acquire.
2472 % o exception: return any errors or warnings in this structure.
2479 0, 48, 12, 60, 3, 51, 15, 63,
2480 32, 16, 44, 28, 35, 19, 47, 31,
2481 8, 56, 4, 52, 11, 59, 7, 55,
2482 40, 24, 36, 20, 43, 27, 39, 23,
2483 2, 50, 14, 62, 1, 49, 13, 61,
2484 34, 18, 46, 30, 33, 17, 45, 29,
2485 10, 58, 6, 54, 9, 57, 5, 53,
2486 42, 26, 38, 22, 41, 25, 37, 21
2489 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2494 index=x+DitherMatrix[x & 0x07]-32L;
2497 if (index >= (ssize_t) columns)
2498 return((ssize_t) columns-1L);
2502 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2507 index=y+DitherMatrix[y & 0x07]-32L;
2510 if (index >= (ssize_t) rows)
2511 return((ssize_t) rows-1L);
2515 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2519 if (x >= (ssize_t) columns)
2520 return((ssize_t) (columns-1));
2524 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2528 if (y >= (ssize_t) rows)
2529 return((ssize_t) (rows-1));
2533 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2535 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2538 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2540 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2543 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2544 const size_t extent)
2550 Compute the remainder of dividing offset by extent. It returns not only
2551 the quotient (tile the offset falls in) but also the positive remainer
2552 within that tile such that 0 <= remainder < extent. This method is
2553 essentially a ldiv() using a floored modulo division rather than the
2554 normal default truncated modulo division.
2556 modulo.quotient=offset/(ssize_t) extent;
2559 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2563 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2564 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2565 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2566 ExceptionInfo *exception)
2583 virtual_pixel[CompositePixelChannel];
2588 register const Quantum
2601 register unsigned char
2608 *virtual_metacontent;
2613 assert(image != (const Image *) NULL);
2614 assert(image->signature == MagickSignature);
2615 assert(image->cache != (Cache) NULL);
2616 cache_info=(CacheInfo *) image->cache;
2617 assert(cache_info->signature == MagickSignature);
2618 if (cache_info->type == UndefinedCache)
2619 return((const Quantum *) NULL);
2622 region.width=columns;
2624 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2626 if (pixels == (Quantum *) NULL)
2627 return((const Quantum *) NULL);
2629 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2630 nexus_info->region.x;
2631 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2632 nexus_info->region.width-1L;
2633 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2634 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2635 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2636 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2642 Pixel request is inside cache extents.
2644 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2646 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2647 if (status == MagickFalse)
2648 return((const Quantum *) NULL);
2649 if (cache_info->metacontent_extent != 0)
2651 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2652 if (status == MagickFalse)
2653 return((const Quantum *) NULL);
2658 Pixel request is outside cache extents.
2660 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2661 virtual_nexus=AcquirePixelCacheNexus(1);
2662 if (virtual_nexus == (NexusInfo **) NULL)
2664 if (virtual_nexus != (NexusInfo **) NULL)
2665 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2666 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2667 "UnableToGetCacheNexus","`%s'",image->filename);
2668 return((const Quantum *) NULL);
2670 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2671 sizeof(*virtual_pixel));
2672 virtual_metacontent=(void *) NULL;
2673 switch (virtual_pixel_method)
2675 case BackgroundVirtualPixelMethod:
2676 case BlackVirtualPixelMethod:
2677 case GrayVirtualPixelMethod:
2678 case TransparentVirtualPixelMethod:
2679 case MaskVirtualPixelMethod:
2680 case WhiteVirtualPixelMethod:
2681 case EdgeVirtualPixelMethod:
2682 case CheckerTileVirtualPixelMethod:
2683 case HorizontalTileVirtualPixelMethod:
2684 case VerticalTileVirtualPixelMethod:
2686 if (cache_info->metacontent_extent != 0)
2689 Acquire a metacontent buffer.
2691 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2692 cache_info->metacontent_extent);
2693 if (virtual_metacontent == (void *) NULL)
2695 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2696 (void) ThrowMagickException(exception,GetMagickModule(),
2697 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2698 return((const Quantum *) NULL);
2700 (void) ResetMagickMemory(virtual_metacontent,0,
2701 cache_info->metacontent_extent);
2703 switch (virtual_pixel_method)
2705 case BlackVirtualPixelMethod:
2707 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2708 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2709 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2712 case GrayVirtualPixelMethod:
2714 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2715 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2717 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2720 case TransparentVirtualPixelMethod:
2722 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2723 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2724 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2727 case MaskVirtualPixelMethod:
2728 case WhiteVirtualPixelMethod:
2730 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2731 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2732 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2737 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2739 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2741 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2743 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2745 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2755 for (v=0; v < (ssize_t) rows; v++)
2757 for (u=0; u < (ssize_t) columns; u+=length)
2759 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
2760 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
2761 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
2769 Transfer a single pixel.
2771 length=(MagickSizeType) 1;
2772 switch (virtual_pixel_method)
2776 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2777 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
2778 1UL,1UL,*virtual_nexus,exception);
2779 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2782 case RandomVirtualPixelMethod:
2784 if (cache_info->random_info == (RandomInfo *) NULL)
2785 cache_info->random_info=AcquireRandomInfo();
2786 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2787 RandomX(cache_info->random_info,cache_info->columns),
2788 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2789 *virtual_nexus,exception);
2790 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2793 case DitherVirtualPixelMethod:
2795 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2796 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
2797 1UL,1UL,*virtual_nexus,exception);
2798 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2801 case TileVirtualPixelMethod:
2803 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2804 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2805 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2806 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2808 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2811 case MirrorVirtualPixelMethod:
2813 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2814 if ((x_modulo.quotient & 0x01) == 1L)
2815 x_modulo.remainder=(ssize_t) cache_info->columns-
2816 x_modulo.remainder-1L;
2817 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2818 if ((y_modulo.quotient & 0x01) == 1L)
2819 y_modulo.remainder=(ssize_t) cache_info->rows-
2820 y_modulo.remainder-1L;
2821 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2822 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2824 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2827 case HorizontalTileEdgeVirtualPixelMethod:
2829 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2830 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2831 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
2832 *virtual_nexus,exception);
2833 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2836 case VerticalTileEdgeVirtualPixelMethod:
2838 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2839 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2840 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
2841 *virtual_nexus,exception);
2842 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2845 case BackgroundVirtualPixelMethod:
2846 case BlackVirtualPixelMethod:
2847 case GrayVirtualPixelMethod:
2848 case TransparentVirtualPixelMethod:
2849 case MaskVirtualPixelMethod:
2850 case WhiteVirtualPixelMethod:
2853 r=virtual_metacontent;
2856 case EdgeVirtualPixelMethod:
2857 case CheckerTileVirtualPixelMethod:
2859 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2860 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2861 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2864 r=virtual_metacontent;
2867 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2868 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2870 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2873 case HorizontalTileVirtualPixelMethod:
2875 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
2878 r=virtual_metacontent;
2881 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2882 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2883 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2884 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2886 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2889 case VerticalTileVirtualPixelMethod:
2891 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
2894 r=virtual_metacontent;
2897 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2898 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2899 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2900 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2902 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2906 if (p == (const Quantum *) NULL)
2908 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2910 q+=cache_info->number_channels;
2911 if ((s != (void *) NULL) && (r != (const void *) NULL))
2913 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2914 s+=cache_info->metacontent_extent;
2919 Transfer a run of pixels.
2921 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
2922 length,1UL,*virtual_nexus,exception);
2923 if (p == (const Quantum *) NULL)
2925 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2926 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2927 q+=length*cache_info->number_channels;
2928 if ((r != (void *) NULL) && (s != (const void *) NULL))
2930 (void) memcpy(s,r,(size_t) length);
2931 s+=length*cache_info->metacontent_extent;
2938 if (virtual_metacontent != (void *) NULL)
2939 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2940 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2949 + G e t V i r t u a l P i x e l C a c h e %
2953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2955 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2956 % cache as defined by the geometry parameters. A pointer to the pixels
2957 % is returned if the pixels are transferred, otherwise a NULL is returned.
2959 % The format of the GetVirtualPixelCache() method is:
2961 % const Quantum *GetVirtualPixelCache(const Image *image,
2962 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2963 % const ssize_t y,const size_t columns,const size_t rows,
2964 % ExceptionInfo *exception)
2966 % A description of each parameter follows:
2968 % o image: the image.
2970 % o virtual_pixel_method: the virtual pixel method.
2972 % o x,y,columns,rows: These values define the perimeter of a region of
2975 % o exception: return any errors or warnings in this structure.
2978 static const Quantum *GetVirtualPixelCache(const Image *image,
2979 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2980 const size_t columns,const size_t rows,ExceptionInfo *exception)
2986 id = GetOpenMPThreadId();
2991 assert(image != (const Image *) NULL);
2992 assert(image->signature == MagickSignature);
2993 assert(image->cache != (Cache) NULL);
2994 cache_info=(CacheInfo *) image->cache;
2995 assert(cache_info->signature == MagickSignature);
2996 assert(id < (int) cache_info->number_threads);
2997 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2998 cache_info->nexus_info[id],exception);
3003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007 % G e t V i r t u a l P i x e l Q u e u e %
3011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3013 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3014 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3016 % The format of the GetVirtualPixelQueue() method is:
3018 % const Quantum *GetVirtualPixelQueue(const Image image)
3020 % A description of each parameter follows:
3022 % o image: the image.
3025 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3031 id = GetOpenMPThreadId();
3033 assert(image != (const Image *) NULL);
3034 assert(image->signature == MagickSignature);
3035 assert(image->cache != (Cache) NULL);
3036 cache_info=(CacheInfo *) image->cache;
3037 assert(cache_info->signature == MagickSignature);
3038 if (cache_info->methods.get_virtual_pixels_handler !=
3039 (GetVirtualPixelsHandler) NULL)
3040 return(cache_info->methods.get_virtual_pixels_handler(image));
3041 assert(id < (int) cache_info->number_threads);
3042 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3050 % G e t V i r t u a l P i x e l s %
3054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3056 % GetVirtualPixels() returns an immutable pixel region. If the
3057 % region is successfully accessed, a pointer to it is returned, otherwise
3058 % NULL is returned. The returned pointer may point to a temporary working
3059 % copy of the pixels or it may point to the original pixels in memory.
3060 % Performance is maximized if the selected region is part of one row, or one
3061 % or more full rows, since there is opportunity to access the pixels in-place
3062 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3063 % returned pointer must *never* be deallocated by the user.
3065 % Pixels accessed via the returned pointer represent a simple array of type
3066 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3067 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3068 % access the meta-content (of type void) corresponding to the the
3071 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3073 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3074 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3075 % GetCacheViewAuthenticPixels() instead.
3077 % The format of the GetVirtualPixels() method is:
3079 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3080 % const ssize_t y,const size_t columns,const size_t rows,
3081 % ExceptionInfo *exception)
3083 % A description of each parameter follows:
3085 % o image: the image.
3087 % o x,y,columns,rows: These values define the perimeter of a region of
3090 % o exception: return any errors or warnings in this structure.
3093 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3094 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3095 ExceptionInfo *exception)
3101 id = GetOpenMPThreadId();
3106 assert(image != (const Image *) NULL);
3107 assert(image->signature == MagickSignature);
3108 assert(image->cache != (Cache) NULL);
3109 cache_info=(CacheInfo *) image->cache;
3110 assert(cache_info->signature == MagickSignature);
3111 if (cache_info->methods.get_virtual_pixel_handler !=
3112 (GetVirtualPixelHandler) NULL)
3113 return(cache_info->methods.get_virtual_pixel_handler(image,
3114 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3115 assert(id < (int) cache_info->number_threads);
3116 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3117 columns,rows,cache_info->nexus_info[id],exception);
3122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3126 + 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 %
3130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3132 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3133 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3135 % The format of the GetVirtualPixelsCache() method is:
3137 % Quantum *GetVirtualPixelsCache(const Image *image)
3139 % A description of each parameter follows:
3141 % o image: the image.
3144 static const Quantum *GetVirtualPixelsCache(const Image *image)
3150 id = GetOpenMPThreadId();
3152 assert(image != (const Image *) NULL);
3153 assert(image->signature == MagickSignature);
3154 assert(image->cache != (Cache) NULL);
3155 cache_info=(CacheInfo *) image->cache;
3156 assert(cache_info->signature == MagickSignature);
3157 assert(id < (int) cache_info->number_threads);
3158 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3166 + G e t V i r t u a l P i x e l s N e x u s %
3170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3172 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3175 % The format of the GetVirtualPixelsNexus() method is:
3177 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3178 % NexusInfo *nexus_info)
3180 % A description of each parameter follows:
3182 % o cache: the pixel cache.
3184 % o nexus_info: the cache nexus to return the colormap pixels.
3187 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3188 NexusInfo *nexus_info)
3193 assert(cache != (Cache) NULL);
3194 cache_info=(CacheInfo *) cache;
3195 assert(cache_info->signature == MagickSignature);
3196 if (cache_info->storage_class == UndefinedClass)
3197 return((Quantum *) NULL);
3198 return((const Quantum *) nexus_info->pixels);
3202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3206 + O p e n P i x e l C a c h e %
3210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3212 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3213 % dimensions, allocating space for the image pixels and optionally the
3214 % metacontent, and memory mapping the cache if it is disk based. The cache
3215 % nexus array is initialized as well.
3217 % The format of the OpenPixelCache() method is:
3219 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3220 % ExceptionInfo *exception)
3222 % A description of each parameter follows:
3224 % o image: the image.
3226 % o mode: ReadMode, WriteMode, or IOMode.
3228 % o exception: return any errors or warnings in this structure.
3232 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3234 cache_info->mapped=MagickFalse;
3235 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3236 (size_t) cache_info->length));
3237 if (cache_info->pixels == (Quantum *) NULL)
3239 cache_info->mapped=MagickTrue;
3240 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3241 cache_info->length);
3245 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3252 Open pixel cache on disk.
3254 if (cache_info->file != -1)
3255 return(MagickTrue); /* cache already open */
3256 if (*cache_info->cache_filename == '\0')
3257 file=AcquireUniqueFileResource(cache_info->cache_filename);
3263 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3268 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3269 O_BINARY | O_EXCL,S_MODE);
3271 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3277 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3280 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3285 return(MagickFalse);
3286 (void) AcquireMagickResource(FileResource,1);
3287 cache_info->file=file;
3288 cache_info->mode=mode;
3292 static inline MagickOffsetType WritePixelCacheRegion(
3293 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3294 const MagickSizeType length,const unsigned char *restrict buffer)
3296 register MagickOffsetType
3302 #if !defined(MAGICKCORE_HAVE_PWRITE)
3303 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3304 return((MagickOffsetType) -1);
3307 for (i=0; i < (MagickOffsetType) length; i+=count)
3309 #if !defined(MAGICKCORE_HAVE_PWRITE)
3310 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3311 (MagickSizeType) SSIZE_MAX));
3313 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3314 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3326 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3336 cache_info=(CacheInfo *) image->cache;
3337 if (image->debug != MagickFalse)
3340 format[MaxTextExtent],
3341 message[MaxTextExtent];
3343 (void) FormatMagickSize(length,MagickFalse,format);
3344 (void) FormatLocaleString(message,MaxTextExtent,
3345 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3346 cache_info->cache_filename,cache_info->file,format);
3347 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3349 if (length != (MagickSizeType) ((MagickOffsetType) length))
3350 return(MagickFalse);
3351 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3353 return(MagickFalse);
3354 if ((MagickSizeType) offset >= length)
3356 extent=(MagickOffsetType) length-1;
3357 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3358 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3359 if (cache_info->synchronize != MagickFalse)
3364 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3366 return(MagickFalse);
3369 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3372 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3373 ExceptionInfo *exception)
3380 format[MaxTextExtent],
3381 message[MaxTextExtent];
3397 assert(image != (const Image *) NULL);
3398 assert(image->signature == MagickSignature);
3399 assert(image->cache != (Cache) NULL);
3400 if (image->debug != MagickFalse)
3401 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3402 if ((image->columns == 0) || (image->rows == 0))
3403 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3404 cache_info=(CacheInfo *) image->cache;
3405 assert(cache_info->signature == MagickSignature);
3406 source_info=(*cache_info);
3407 source_info.file=(-1);
3408 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3409 image->filename,(double) GetImageIndexInList(image));
3410 cache_info->storage_class=image->storage_class;
3411 cache_info->colorspace=image->colorspace;
3412 cache_info->alpha_trait=image->alpha_trait;
3413 cache_info->mask=image->mask;
3414 cache_info->rows=image->rows;
3415 cache_info->columns=image->columns;
3416 InitializePixelChannelMap(image);
3417 cache_info->number_channels=GetPixelChannels(image);
3418 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3419 sizeof(*image->channel_map));
3420 cache_info->metacontent_extent=image->metacontent_extent;
3421 cache_info->mode=mode;
3422 if (image->ping != MagickFalse)
3424 cache_info->type=PingCache;
3425 cache_info->pixels=(Quantum *) NULL;
3426 cache_info->metacontent=(void *) NULL;
3427 cache_info->length=0;
3430 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3431 packet_size=cache_info->number_channels*sizeof(Quantum);
3432 if (image->metacontent_extent != 0)
3433 packet_size+=cache_info->metacontent_extent;
3434 length=number_pixels*packet_size;
3435 columns=(size_t) (length/cache_info->rows/packet_size);
3436 if (cache_info->columns != columns)
3437 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3439 cache_info->length=length;
3440 status=AcquireMagickResource(AreaResource,cache_info->length);
3441 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3442 cache_info->metacontent_extent);
3443 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3445 status=AcquireMagickResource(MemoryResource,cache_info->length);
3446 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3447 (cache_info->type == MemoryCache))
3449 AllocatePixelCachePixels(cache_info);
3450 if (cache_info->pixels == (Quantum *) NULL)
3451 cache_info->pixels=source_info.pixels;
3455 Create memory pixel cache.
3458 cache_info->type=MemoryCache;
3459 cache_info->metacontent=(void *) NULL;
3460 if (cache_info->metacontent_extent != 0)
3461 cache_info->metacontent=(void *) (cache_info->pixels+
3462 number_pixels*cache_info->number_channels);
3463 if ((source_info.storage_class != UndefinedClass) &&
3466 status=ClonePixelCachePixels(cache_info,&source_info,
3468 RelinquishPixelCachePixels(&source_info);
3470 if (image->debug != MagickFalse)
3472 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3473 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3475 (void) FormatLocaleString(message,MaxTextExtent,
3476 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3477 cache_info->filename,cache_info->mapped != MagickFalse ?
3478 "Anonymous" : "Heap",type,(double) cache_info->columns,
3479 (double) cache_info->rows,(double)
3480 cache_info->number_channels,format);
3481 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3487 RelinquishMagickResource(MemoryResource,cache_info->length);
3490 Create pixel cache on disk.
3492 status=AcquireMagickResource(DiskResource,cache_info->length);
3493 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3498 if (cache_info->type == DistributedCache)
3499 RelinquishMagickResource(DiskResource,cache_info->length);
3500 server_info=AcquireDistributeCacheInfo(exception);
3501 if (server_info != (DistributeCacheInfo *) NULL)
3503 status=OpenDistributePixelCache(server_info,image);
3504 if (status == MagickFalse)
3505 server_info=DestroyDistributeCacheInfo(server_info);
3509 Create a distributed pixel cache.
3511 cache_info->type=DistributedCache;
3512 cache_info->server_info=server_info;
3513 (void) FormatLocaleString(cache_info->cache_filename,
3514 MaxTextExtent,"%s:%d",
3515 GetDistributeCacheHostname(cache_info->server_info),
3516 GetDistributeCachePort(cache_info->server_info));
3517 if ((source_info.storage_class != UndefinedClass) &&
3520 status=ClonePixelCachePixels(cache_info,&source_info,
3522 RelinquishPixelCachePixels(&source_info);
3524 if (image->debug != MagickFalse)
3526 (void) FormatMagickSize(cache_info->length,MagickFalse,
3528 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3530 (void) FormatLocaleString(message,MaxTextExtent,
3531 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3532 cache_info->filename,cache_info->cache_filename,
3533 GetDistributeCacheFile(cache_info->server_info),type,
3534 (double) cache_info->columns,(double) cache_info->rows,
3535 (double) cache_info->number_channels,format);
3536 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3542 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3543 "CacheResourcesExhausted","`%s'",image->filename);
3544 return(MagickFalse);
3546 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3548 (void) ClosePixelCacheOnDisk(cache_info);
3549 *cache_info->cache_filename='\0';
3551 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3553 RelinquishMagickResource(DiskResource,cache_info->length);
3554 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3556 return(MagickFalse);
3558 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3559 cache_info->length);
3560 if (status == MagickFalse)
3562 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3564 return(MagickFalse);
3566 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3567 cache_info->metacontent_extent);
3568 if (length != (MagickSizeType) ((size_t) length))
3569 cache_info->type=DiskCache;
3572 status=AcquireMagickResource(MapResource,cache_info->length);
3573 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3574 (cache_info->type != MemoryCache))
3575 cache_info->type=DiskCache;
3578 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3579 cache_info->offset,(size_t) cache_info->length);
3580 if (cache_info->pixels == (Quantum *) NULL)
3582 cache_info->type=DiskCache;
3583 cache_info->pixels=source_info.pixels;
3588 Create file-backed memory-mapped pixel cache.
3591 (void) ClosePixelCacheOnDisk(cache_info);
3592 cache_info->type=MapCache;
3593 cache_info->mapped=MagickTrue;
3594 cache_info->metacontent=(void *) NULL;
3595 if (cache_info->metacontent_extent != 0)
3596 cache_info->metacontent=(void *) (cache_info->pixels+
3597 number_pixels*cache_info->number_channels);
3598 if ((source_info.storage_class != UndefinedClass) &&
3601 status=ClonePixelCachePixels(cache_info,&source_info,
3603 RelinquishPixelCachePixels(&source_info);
3605 if (image->debug != MagickFalse)
3607 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3608 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3610 (void) FormatLocaleString(message,MaxTextExtent,
3611 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3612 cache_info->filename,cache_info->cache_filename,
3613 cache_info->file,type,(double) cache_info->columns,(double)
3614 cache_info->rows,(double) cache_info->number_channels,
3616 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3622 RelinquishMagickResource(MapResource,cache_info->length);
3625 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3627 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3628 RelinquishPixelCachePixels(&source_info);
3630 if (image->debug != MagickFalse)
3632 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3633 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3635 (void) FormatLocaleString(message,MaxTextExtent,
3636 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3637 cache_info->cache_filename,cache_info->file,type,(double)
3638 cache_info->columns,(double) cache_info->rows,(double)
3639 cache_info->number_channels,format);
3640 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3650 + P e r s i s t P i x e l C a c h e %
3654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3656 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3657 % persistent pixel cache is one that resides on disk and is not destroyed
3658 % when the program exits.
3660 % The format of the PersistPixelCache() method is:
3662 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3663 % const MagickBooleanType attach,MagickOffsetType *offset,
3664 % ExceptionInfo *exception)
3666 % A description of each parameter follows:
3668 % o image: the image.
3670 % o filename: the persistent pixel cache filename.
3672 % o attach: A value other than zero initializes the persistent pixel cache.
3674 % o initialize: A value other than zero initializes the persistent pixel
3677 % o offset: the offset in the persistent cache to store pixels.
3679 % o exception: return any errors or warnings in this structure.
3682 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3683 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3684 ExceptionInfo *exception)
3699 assert(image != (Image *) NULL);
3700 assert(image->signature == MagickSignature);
3701 if (image->debug != MagickFalse)
3702 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3703 assert(image->cache != (void *) NULL);
3704 assert(filename != (const char *) NULL);
3705 assert(offset != (MagickOffsetType *) NULL);
3706 page_size=GetMagickPageSize();
3707 cache_info=(CacheInfo *) image->cache;
3708 assert(cache_info->signature == MagickSignature);
3709 if (attach != MagickFalse)
3712 Attach existing persistent pixel cache.
3714 if (image->debug != MagickFalse)
3715 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3716 "attach persistent cache");
3717 (void) CopyMagickString(cache_info->cache_filename,filename,
3719 cache_info->type=DiskCache;
3720 cache_info->offset=(*offset);
3721 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3722 return(MagickFalse);
3723 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3726 if ((cache_info->mode != ReadMode) &&
3727 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3728 (cache_info->reference_count == 1))
3730 LockSemaphoreInfo(cache_info->semaphore);
3731 if ((cache_info->mode != ReadMode) &&
3732 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3733 (cache_info->reference_count == 1))
3739 Usurp existing persistent pixel cache.
3741 status=rename_utf8(cache_info->cache_filename,filename);
3744 (void) CopyMagickString(cache_info->cache_filename,filename,
3746 *offset+=cache_info->length+page_size-(cache_info->length %
3748 UnlockSemaphoreInfo(cache_info->semaphore);
3749 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3750 if (image->debug != MagickFalse)
3751 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3752 "Usurp resident persistent cache");
3756 UnlockSemaphoreInfo(cache_info->semaphore);
3759 Clone persistent pixel cache.
3761 clone_image=(*image);
3762 clone_info=(CacheInfo *) clone_image.cache;
3763 image->cache=ClonePixelCache(cache_info);
3764 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3765 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3766 cache_info->type=DiskCache;
3767 cache_info->offset=(*offset);
3768 cache_info=(CacheInfo *) image->cache;
3769 status=OpenPixelCache(image,IOMode,exception);
3770 if (status != MagickFalse)
3771 status=ClonePixelCachePixels(cache_info,clone_info,exception);
3772 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3773 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3782 + 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 %
3786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3788 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3789 % defined by the region rectangle and returns a pointer to the region. This
3790 % region is subsequently transferred from the pixel cache with
3791 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3792 % pixels are transferred, otherwise a NULL is returned.
3794 % The format of the QueueAuthenticPixelCacheNexus() method is:
3796 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3797 % const ssize_t y,const size_t columns,const size_t rows,
3798 % const MagickBooleanType clone,NexusInfo *nexus_info,
3799 % ExceptionInfo *exception)
3801 % A description of each parameter follows:
3803 % o image: the image.
3805 % o x,y,columns,rows: These values define the perimeter of a region of
3808 % o nexus_info: the cache nexus to set.
3810 % o clone: clone the pixel cache.
3812 % o exception: return any errors or warnings in this structure.
3815 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3816 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3817 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3835 Validate pixel cache geometry.
3837 assert(image != (const Image *) NULL);
3838 assert(image->signature == MagickSignature);
3839 assert(image->cache != (Cache) NULL);
3840 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3841 if (cache_info == (Cache) NULL)
3842 return((Quantum *) NULL);
3843 assert(cache_info->signature == MagickSignature);
3844 if ((cache_info->columns == 0) && (cache_info->rows == 0))
3846 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3847 "NoPixelsDefinedInCache","`%s'",image->filename);
3848 return((Quantum *) NULL);
3850 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3851 (y >= (ssize_t) cache_info->rows))
3853 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3854 "PixelsAreNotAuthentic","`%s'",image->filename);
3855 return((Quantum *) NULL);
3857 offset=(MagickOffsetType) y*cache_info->columns+x;
3859 return((Quantum *) NULL);
3860 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3861 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3862 if ((MagickSizeType) offset >= number_pixels)
3863 return((Quantum *) NULL);
3869 region.width=columns;
3871 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3881 + 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 %
3885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3887 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3888 % defined by the region rectangle and returns a pointer to the region. This
3889 % region is subsequently transferred from the pixel cache with
3890 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3891 % pixels are transferred, otherwise a NULL is returned.
3893 % The format of the QueueAuthenticPixelsCache() method is:
3895 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3896 % const ssize_t y,const size_t columns,const size_t rows,
3897 % ExceptionInfo *exception)
3899 % A description of each parameter follows:
3901 % o image: the image.
3903 % o x,y,columns,rows: These values define the perimeter of a region of
3906 % o exception: return any errors or warnings in this structure.
3909 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3910 const ssize_t y,const size_t columns,const size_t rows,
3911 ExceptionInfo *exception)
3917 id = GetOpenMPThreadId();
3922 assert(image != (const Image *) NULL);
3923 assert(image->signature == MagickSignature);
3924 assert(image->cache != (Cache) NULL);
3925 cache_info=(CacheInfo *) image->cache;
3926 assert(cache_info->signature == MagickSignature);
3927 assert(id < (int) cache_info->number_threads);
3928 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3929 cache_info->nexus_info[id],exception);
3934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3938 % Q u e u e A u t h e n t i c P i x e l s %
3942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3944 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3945 % successfully initialized a pointer to a Quantum array representing the
3946 % region is returned, otherwise NULL is returned. The returned pointer may
3947 % point to a temporary working buffer for the pixels or it may point to the
3948 % final location of the pixels in memory.
3950 % Write-only access means that any existing pixel values corresponding to
3951 % the region are ignored. This is useful if the initial image is being
3952 % created from scratch, or if the existing pixel values are to be
3953 % completely replaced without need to refer to their pre-existing values.
3954 % The application is free to read and write the pixel buffer returned by
3955 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3956 % initialize the pixel array values. Initializing pixel array values is the
3957 % application's responsibility.
3959 % Performance is maximized if the selected region is part of one row, or
3960 % one or more full rows, since then there is opportunity to access the
3961 % pixels in-place (without a copy) if the image is in memory, or in a
3962 % memory-mapped file. The returned pointer must *never* be deallocated
3965 % Pixels accessed via the returned pointer represent a simple array of type
3966 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3967 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3968 % obtain the meta-content (of type void) corresponding to the region.
3969 % Once the Quantum (and/or Quantum) array has been updated, the
3970 % changes must be saved back to the underlying image using
3971 % SyncAuthenticPixels() or they may be lost.
3973 % The format of the QueueAuthenticPixels() method is:
3975 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3976 % const ssize_t y,const size_t columns,const size_t rows,
3977 % ExceptionInfo *exception)
3979 % A description of each parameter follows:
3981 % o image: the image.
3983 % o x,y,columns,rows: These values define the perimeter of a region of
3986 % o exception: return any errors or warnings in this structure.
3989 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3990 const ssize_t y,const size_t columns,const size_t rows,
3991 ExceptionInfo *exception)
3997 id = GetOpenMPThreadId();
4002 assert(image != (Image *) NULL);
4003 assert(image->signature == MagickSignature);
4004 assert(image->cache != (Cache) NULL);
4005 cache_info=(CacheInfo *) image->cache;
4006 assert(cache_info->signature == MagickSignature);
4007 if (cache_info->methods.queue_authentic_pixels_handler !=
4008 (QueueAuthenticPixelsHandler) NULL)
4010 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4014 assert(id < (int) cache_info->number_threads);
4015 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4016 cache_info->nexus_info[id],exception);
4021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4025 + 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 %
4029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4031 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4034 % The format of the ReadPixelCacheMetacontent() method is:
4036 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4037 % NexusInfo *nexus_info,ExceptionInfo *exception)
4039 % A description of each parameter follows:
4041 % o cache_info: the pixel cache.
4043 % o nexus_info: the cache nexus to read the metacontent.
4045 % o exception: return any errors or warnings in this structure.
4049 static inline MagickOffsetType ReadPixelCacheRegion(
4050 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4051 const MagickSizeType length,unsigned char *restrict buffer)
4053 register MagickOffsetType
4059 #if !defined(MAGICKCORE_HAVE_PREAD)
4060 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4061 return((MagickOffsetType) -1);
4064 for (i=0; i < (MagickOffsetType) length; i+=count)
4066 #if !defined(MAGICKCORE_HAVE_PREAD)
4067 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4068 (MagickSizeType) SSIZE_MAX));
4070 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4071 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4083 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4084 NexusInfo *nexus_info,ExceptionInfo *exception)
4100 register unsigned char
4103 if (cache_info->metacontent_extent == 0)
4104 return(MagickFalse);
4105 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4107 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4108 nexus_info->region.x;
4109 length=(MagickSizeType) nexus_info->region.width*
4110 cache_info->metacontent_extent;
4111 extent=length*nexus_info->region.height;
4112 region=nexus_info->region;
4114 q=(unsigned char *) nexus_info->metacontent;
4115 switch (cache_info->type)
4120 register unsigned char
4124 Read meta-content from memory.
4126 if ((cache_info->columns == nexus_info->region.width) &&
4127 (extent == (MagickSizeType) ((size_t) extent)))
4132 p=(unsigned char *) cache_info->metacontent+offset*
4133 cache_info->metacontent_extent;
4134 for (y=0; y < (ssize_t) region.height; y++)
4136 (void) memcpy(q,p,(size_t) length);
4137 p+=cache_info->metacontent_extent*cache_info->columns;
4138 q+=cache_info->metacontent_extent*nexus_info->region.width;
4145 Read meta content from disk.
4147 LockSemaphoreInfo(cache_info->file_semaphore);
4148 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4150 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4151 cache_info->cache_filename);
4152 UnlockSemaphoreInfo(cache_info->file_semaphore);
4153 return(MagickFalse);
4155 if ((cache_info->columns == nexus_info->region.width) &&
4156 (extent <= MagickMaxBufferExtent))
4161 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4162 for (y=0; y < (ssize_t) region.height; y++)
4164 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4165 cache_info->number_channels*sizeof(Quantum)+offset*
4166 cache_info->metacontent_extent,length,(unsigned char *) q);
4167 if (count != (MagickOffsetType) length)
4169 offset+=cache_info->columns;
4170 q+=cache_info->metacontent_extent*nexus_info->region.width;
4172 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4173 (void) ClosePixelCacheOnDisk(cache_info);
4174 UnlockSemaphoreInfo(cache_info->file_semaphore);
4177 case DistributedCache:
4180 Read metacontent from distributed cache.
4182 LockSemaphoreInfo(cache_info->file_semaphore);
4184 for (y=0; y < (ssize_t) region.height; y++)
4186 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4187 length,(unsigned char *) q);
4188 if (count != (MagickOffsetType) length)
4190 q+=cache_info->metacontent_extent*nexus_info->region.width;
4193 UnlockSemaphoreInfo(cache_info->file_semaphore);
4199 if (y < (ssize_t) region.height)
4201 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4202 cache_info->cache_filename);
4203 return(MagickFalse);
4205 if ((cache_info->debug != MagickFalse) &&
4206 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4207 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4208 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4209 nexus_info->region.width,(double) nexus_info->region.height,(double)
4210 nexus_info->region.x,(double) nexus_info->region.y);
4215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4219 + R e a d P i x e l C a c h e P i x e l s %
4223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4225 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4228 % The format of the ReadPixelCachePixels() method is:
4230 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4231 % NexusInfo *nexus_info,ExceptionInfo *exception)
4233 % A description of each parameter follows:
4235 % o cache_info: the pixel cache.
4237 % o nexus_info: the cache nexus to read the pixels.
4239 % o exception: return any errors or warnings in this structure.
4242 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4243 NexusInfo *nexus_info,ExceptionInfo *exception)
4262 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4264 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4265 nexus_info->region.x;
4266 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4268 extent=length*nexus_info->region.height;
4269 region=nexus_info->region;
4271 q=nexus_info->pixels;
4272 switch (cache_info->type)
4281 Read pixels from memory.
4283 if ((cache_info->columns == nexus_info->region.width) &&
4284 (extent == (MagickSizeType) ((size_t) extent)))
4289 p=cache_info->pixels+offset*cache_info->number_channels;
4290 for (y=0; y < (ssize_t) region.height; y++)
4292 (void) memcpy(q,p,(size_t) length);
4293 p+=cache_info->number_channels*cache_info->columns;
4294 q+=cache_info->number_channels*nexus_info->region.width;
4301 Read pixels from disk.
4303 LockSemaphoreInfo(cache_info->file_semaphore);
4304 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4306 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4307 cache_info->cache_filename);
4308 UnlockSemaphoreInfo(cache_info->file_semaphore);
4309 return(MagickFalse);
4311 if ((cache_info->columns == nexus_info->region.width) &&
4312 (extent <= MagickMaxBufferExtent))
4317 for (y=0; y < (ssize_t) region.height; y++)
4319 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4320 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4321 if (count != (MagickOffsetType) length)
4323 offset+=cache_info->columns;
4324 q+=cache_info->number_channels*nexus_info->region.width;
4326 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4327 (void) ClosePixelCacheOnDisk(cache_info);
4328 UnlockSemaphoreInfo(cache_info->file_semaphore);
4331 case DistributedCache:
4334 Read pixels from distributed cache.
4336 LockSemaphoreInfo(cache_info->file_semaphore);
4338 for (y=0; y < (ssize_t) region.height; y++)
4340 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4341 length,(unsigned char *) q);
4342 if (count != (MagickOffsetType) length)
4344 q+=cache_info->number_channels*nexus_info->region.width;
4347 UnlockSemaphoreInfo(cache_info->file_semaphore);
4353 if (y < (ssize_t) region.height)
4355 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4356 cache_info->cache_filename);
4357 return(MagickFalse);
4359 if ((cache_info->debug != MagickFalse) &&
4360 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4361 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4362 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4363 nexus_info->region.width,(double) nexus_info->region.height,(double)
4364 nexus_info->region.x,(double) nexus_info->region.y);
4369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4373 + R e f e r e n c e P i x e l C a c h e %
4377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4379 % ReferencePixelCache() increments the reference count associated with the
4380 % pixel cache returning a pointer to the cache.
4382 % The format of the ReferencePixelCache method is:
4384 % Cache ReferencePixelCache(Cache cache_info)
4386 % A description of each parameter follows:
4388 % o cache_info: the pixel cache.
4391 MagickPrivate Cache ReferencePixelCache(Cache cache)
4396 assert(cache != (Cache *) NULL);
4397 cache_info=(CacheInfo *) cache;
4398 assert(cache_info->signature == MagickSignature);
4399 LockSemaphoreInfo(cache_info->semaphore);
4400 cache_info->reference_count++;
4401 UnlockSemaphoreInfo(cache_info->semaphore);
4406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4410 + S e t P i x e l C a c h e M e t h o d s %
4414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4416 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4418 % The format of the SetPixelCacheMethods() method is:
4420 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4422 % A description of each parameter follows:
4424 % o cache: the pixel cache.
4426 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4429 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4434 GetOneAuthenticPixelFromHandler
4435 get_one_authentic_pixel_from_handler;
4437 GetOneVirtualPixelFromHandler
4438 get_one_virtual_pixel_from_handler;
4441 Set cache pixel methods.
4443 assert(cache != (Cache) NULL);
4444 assert(cache_methods != (CacheMethods *) NULL);
4445 cache_info=(CacheInfo *) cache;
4446 assert(cache_info->signature == MagickSignature);
4447 if (cache_info->debug != MagickFalse)
4448 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4449 cache_info->filename);
4450 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4451 cache_info->methods.get_virtual_pixel_handler=
4452 cache_methods->get_virtual_pixel_handler;
4453 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4454 cache_info->methods.destroy_pixel_handler=
4455 cache_methods->destroy_pixel_handler;
4456 if (cache_methods->get_virtual_metacontent_from_handler !=
4457 (GetVirtualMetacontentFromHandler) NULL)
4458 cache_info->methods.get_virtual_metacontent_from_handler=
4459 cache_methods->get_virtual_metacontent_from_handler;
4460 if (cache_methods->get_authentic_pixels_handler !=
4461 (GetAuthenticPixelsHandler) NULL)
4462 cache_info->methods.get_authentic_pixels_handler=
4463 cache_methods->get_authentic_pixels_handler;
4464 if (cache_methods->queue_authentic_pixels_handler !=
4465 (QueueAuthenticPixelsHandler) NULL)
4466 cache_info->methods.queue_authentic_pixels_handler=
4467 cache_methods->queue_authentic_pixels_handler;
4468 if (cache_methods->sync_authentic_pixels_handler !=
4469 (SyncAuthenticPixelsHandler) NULL)
4470 cache_info->methods.sync_authentic_pixels_handler=
4471 cache_methods->sync_authentic_pixels_handler;
4472 if (cache_methods->get_authentic_pixels_from_handler !=
4473 (GetAuthenticPixelsFromHandler) NULL)
4474 cache_info->methods.get_authentic_pixels_from_handler=
4475 cache_methods->get_authentic_pixels_from_handler;
4476 if (cache_methods->get_authentic_metacontent_from_handler !=
4477 (GetAuthenticMetacontentFromHandler) NULL)
4478 cache_info->methods.get_authentic_metacontent_from_handler=
4479 cache_methods->get_authentic_metacontent_from_handler;
4480 get_one_virtual_pixel_from_handler=
4481 cache_info->methods.get_one_virtual_pixel_from_handler;
4482 if (get_one_virtual_pixel_from_handler !=
4483 (GetOneVirtualPixelFromHandler) NULL)
4484 cache_info->methods.get_one_virtual_pixel_from_handler=
4485 cache_methods->get_one_virtual_pixel_from_handler;
4486 get_one_authentic_pixel_from_handler=
4487 cache_methods->get_one_authentic_pixel_from_handler;
4488 if (get_one_authentic_pixel_from_handler !=
4489 (GetOneAuthenticPixelFromHandler) NULL)
4490 cache_info->methods.get_one_authentic_pixel_from_handler=
4491 cache_methods->get_one_authentic_pixel_from_handler;
4495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4499 + S e t P i x e l C a c h e N e x u s P i x e l s %
4503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4505 % SetPixelCacheNexusPixels() defines the region of the cache for the
4506 % specified cache nexus.
4508 % The format of the SetPixelCacheNexusPixels() method is:
4510 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4511 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4512 % ExceptionInfo *exception)
4514 % A description of each parameter follows:
4516 % o cache_info: the pixel cache.
4518 % o mode: ReadMode, WriteMode, or IOMode.
4520 % o region: A pointer to the RectangleInfo structure that defines the
4521 % region of this particular cache nexus.
4523 % o nexus_info: the cache nexus to set.
4525 % o exception: return any errors or warnings in this structure.
4529 static inline MagickBooleanType AcquireCacheNexusPixels(
4530 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4531 ExceptionInfo *exception)
4533 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4534 return(MagickFalse);
4535 nexus_info->mapped=MagickFalse;
4536 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4537 (size_t) nexus_info->length));
4538 if (nexus_info->cache == (Quantum *) NULL)
4540 nexus_info->mapped=MagickTrue;
4541 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4542 nexus_info->length);
4544 if (nexus_info->cache == (Quantum *) NULL)
4546 (void) ThrowMagickException(exception,GetMagickModule(),
4547 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4548 cache_info->filename);
4549 return(MagickFalse);
4554 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4557 if (mode == ReadMode)
4559 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4562 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4565 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4566 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4567 ExceptionInfo *exception)
4576 assert(cache_info != (const CacheInfo *) NULL);
4577 assert(cache_info->signature == MagickSignature);
4578 if (cache_info->type == UndefinedCache)
4579 return((Quantum *) NULL);
4580 nexus_info->region=(*region);
4581 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4587 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4588 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4589 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4590 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4591 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4592 ((nexus_info->region.width == cache_info->columns) ||
4593 ((nexus_info->region.width % cache_info->columns) == 0)))))
4599 Pixels are accessed directly from memory.
4601 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4602 nexus_info->region.x;
4603 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4605 nexus_info->metacontent=(void *) NULL;
4606 if (cache_info->metacontent_extent != 0)
4607 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4608 offset*cache_info->metacontent_extent;
4609 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4610 return(nexus_info->pixels);
4614 Pixels are stored in a cache region until they are synced to the cache.
4616 number_pixels=(MagickSizeType) nexus_info->region.width*
4617 nexus_info->region.height;
4618 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4619 if (cache_info->metacontent_extent != 0)
4620 length+=number_pixels*cache_info->metacontent_extent;
4621 if (nexus_info->cache == (Quantum *) NULL)
4623 nexus_info->length=length;
4624 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4625 if (status == MagickFalse)
4627 nexus_info->length=0;
4628 return((Quantum *) NULL);
4632 if (nexus_info->length != length)
4634 RelinquishCacheNexusPixels(nexus_info);
4635 nexus_info->length=length;
4636 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4637 if (status == MagickFalse)
4639 nexus_info->length=0;
4640 return((Quantum *) NULL);
4643 nexus_info->pixels=nexus_info->cache;
4644 nexus_info->metacontent=(void *) NULL;
4645 if (cache_info->metacontent_extent != 0)
4646 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4647 cache_info->number_channels);
4648 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4649 return(nexus_info->pixels);
4653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4657 % 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 %
4661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4663 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4664 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4665 % access that is outside the boundaries of the image cache.
4667 % The format of the SetPixelCacheVirtualMethod() method is:
4669 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4670 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4672 % A description of each parameter follows:
4674 % o image: the image.
4676 % o virtual_pixel_method: choose the type of virtual pixel.
4678 % o exception: return any errors or warnings in this structure.
4682 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4683 ExceptionInfo *exception)
4697 assert(image != (Image *) NULL);
4698 assert(image->signature == MagickSignature);
4699 if (image->debug != MagickFalse)
4700 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4701 assert(image->cache != (Cache) NULL);
4702 cache_info=(CacheInfo *) image->cache;
4703 assert(cache_info->signature == MagickSignature);
4704 image->alpha_trait=BlendPixelTrait;
4706 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4707 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4708 #pragma omp parallel for schedule(static,4) shared(status) \
4709 magick_threads(image,image,1,1)
4711 for (y=0; y < (ssize_t) image->rows; y++)
4719 if (status == MagickFalse)
4721 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4722 if (q == (Quantum *) NULL)
4727 for (x=0; x < (ssize_t) image->columns; x++)
4729 SetPixelAlpha(image,alpha,q);
4730 q+=GetPixelChannels(image);
4732 status=SyncCacheViewAuthenticPixels(image_view,exception);
4734 image_view=DestroyCacheView(image_view);
4738 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4739 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4747 assert(image != (Image *) NULL);
4748 assert(image->signature == MagickSignature);
4749 if (image->debug != MagickFalse)
4750 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4751 assert(image->cache != (Cache) NULL);
4752 cache_info=(CacheInfo *) image->cache;
4753 assert(cache_info->signature == MagickSignature);
4754 method=cache_info->virtual_pixel_method;
4755 cache_info->virtual_pixel_method=virtual_pixel_method;
4756 if ((image->columns != 0) && (image->rows != 0))
4757 switch (virtual_pixel_method)
4759 case BackgroundVirtualPixelMethod:
4761 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4762 (image->alpha_trait != BlendPixelTrait))
4763 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4764 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4765 (IsGrayColorspace(image->colorspace) != MagickFalse))
4766 (void) TransformImageColorspace(image,RGBColorspace,exception);
4769 case TransparentVirtualPixelMethod:
4771 if (image->alpha_trait != BlendPixelTrait)
4772 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4782 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4786 + 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 %
4790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4792 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4793 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4794 % is synced, otherwise MagickFalse.
4796 % The format of the SyncAuthenticPixelCacheNexus() method is:
4798 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4799 % NexusInfo *nexus_info,ExceptionInfo *exception)
4801 % A description of each parameter follows:
4803 % o image: the image.
4805 % o nexus_info: the cache nexus to sync.
4807 % o exception: return any errors or warnings in this structure.
4810 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4811 NexusInfo *nexus_info,ExceptionInfo *exception)
4820 Transfer pixels to the cache.
4822 assert(image != (Image *) NULL);
4823 assert(image->signature == MagickSignature);
4824 if (image->cache == (Cache) NULL)
4825 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4826 cache_info=(CacheInfo *) image->cache;
4827 assert(cache_info->signature == MagickSignature);
4828 if (cache_info->type == UndefinedCache)
4829 return(MagickFalse);
4830 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4832 assert(cache_info->signature == MagickSignature);
4833 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4834 if ((cache_info->metacontent_extent != 0) &&
4835 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4836 return(MagickFalse);
4841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4845 + S y n c A u t h e n t i c P i x e l C a c h e %
4849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4851 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4852 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4853 % otherwise MagickFalse.
4855 % The format of the SyncAuthenticPixelsCache() method is:
4857 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4858 % ExceptionInfo *exception)
4860 % A description of each parameter follows:
4862 % o image: the image.
4864 % o exception: return any errors or warnings in this structure.
4867 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4868 ExceptionInfo *exception)
4874 id = GetOpenMPThreadId();
4879 assert(image != (Image *) NULL);
4880 assert(image->signature == MagickSignature);
4881 assert(image->cache != (Cache) NULL);
4882 cache_info=(CacheInfo *) image->cache;
4883 assert(cache_info->signature == MagickSignature);
4884 assert(id < (int) cache_info->number_threads);
4885 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4895 % S y n c A u t h e n t i c P i x e l s %
4899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4901 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4902 % The method returns MagickTrue if the pixel region is flushed, otherwise
4905 % The format of the SyncAuthenticPixels() method is:
4907 % MagickBooleanType SyncAuthenticPixels(Image *image,
4908 % ExceptionInfo *exception)
4910 % A description of each parameter follows:
4912 % o image: the image.
4914 % o exception: return any errors or warnings in this structure.
4917 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4918 ExceptionInfo *exception)
4924 id = GetOpenMPThreadId();
4929 assert(image != (Image *) NULL);
4930 assert(image->signature == MagickSignature);
4931 assert(image->cache != (Cache) NULL);
4932 cache_info=(CacheInfo *) image->cache;
4933 assert(cache_info->signature == MagickSignature);
4934 if (cache_info->methods.sync_authentic_pixels_handler !=
4935 (SyncAuthenticPixelsHandler) NULL)
4937 status=cache_info->methods.sync_authentic_pixels_handler(image,
4941 assert(id < (int) cache_info->number_threads);
4942 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4952 + S y n c I m a g e P i x e l C a c h e %
4956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4958 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4959 % The method returns MagickTrue if the pixel region is flushed, otherwise
4962 % The format of the SyncImagePixelCache() method is:
4964 % MagickBooleanType SyncImagePixelCache(Image *image,
4965 % ExceptionInfo *exception)
4967 % A description of each parameter follows:
4969 % o image: the image.
4971 % o exception: return any errors or warnings in this structure.
4974 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4975 ExceptionInfo *exception)
4980 assert(image != (Image *) NULL);
4981 assert(exception != (ExceptionInfo *) NULL);
4982 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4983 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991 + 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 %
4995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4997 % WritePixelCacheMetacontent() writes the meta-content to the specified region
4998 % of the pixel cache.
5000 % The format of the WritePixelCacheMetacontent() method is:
5002 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5003 % NexusInfo *nexus_info,ExceptionInfo *exception)
5005 % A description of each parameter follows:
5007 % o cache_info: the pixel cache.
5009 % o nexus_info: the cache nexus to write the meta-content.
5011 % o exception: return any errors or warnings in this structure.
5014 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5015 NexusInfo *nexus_info,ExceptionInfo *exception)
5028 register const unsigned char
5034 if (cache_info->metacontent_extent == 0)
5035 return(MagickFalse);
5036 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5038 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5039 nexus_info->region.x;
5040 length=(MagickSizeType) nexus_info->region.width*
5041 cache_info->metacontent_extent;
5042 extent=(MagickSizeType) length*nexus_info->region.height;
5043 region=nexus_info->region;
5045 p=(unsigned char *) nexus_info->metacontent;
5046 switch (cache_info->type)
5051 register unsigned char
5055 Write associated pixels to memory.
5057 if ((cache_info->columns == nexus_info->region.width) &&
5058 (extent == (MagickSizeType) ((size_t) extent)))
5063 q=(unsigned char *) cache_info->metacontent+offset*
5064 cache_info->metacontent_extent;
5065 for (y=0; y < (ssize_t) region.height; y++)
5067 (void) memcpy(q,p,(size_t) length);
5068 p+=nexus_info->region.width*cache_info->metacontent_extent;
5069 q+=cache_info->columns*cache_info->metacontent_extent;
5076 Write associated pixels to disk.
5078 LockSemaphoreInfo(cache_info->file_semaphore);
5079 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5081 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5082 cache_info->cache_filename);
5083 UnlockSemaphoreInfo(cache_info->file_semaphore);
5084 return(MagickFalse);
5086 if ((cache_info->columns == nexus_info->region.width) &&
5087 (extent <= MagickMaxBufferExtent))
5092 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5093 for (y=0; y < (ssize_t) region.height; y++)
5095 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5096 cache_info->number_channels*sizeof(Quantum)+offset*
5097 cache_info->metacontent_extent,length,(const unsigned char *) p);
5098 if (count != (MagickOffsetType) length)
5100 p+=cache_info->metacontent_extent*nexus_info->region.width;
5101 offset+=cache_info->columns;
5103 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5104 (void) ClosePixelCacheOnDisk(cache_info);
5105 UnlockSemaphoreInfo(cache_info->file_semaphore);
5108 case DistributedCache:
5111 Write metacontent to distributed cache.
5113 LockSemaphoreInfo(cache_info->file_semaphore);
5115 for (y=0; y < (ssize_t) region.height; y++)
5117 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5118 length,(const unsigned char *) p);
5119 if (count != (MagickOffsetType) length)
5121 p+=cache_info->metacontent_extent*nexus_info->region.width;
5124 UnlockSemaphoreInfo(cache_info->file_semaphore);
5130 if (y < (ssize_t) region.height)
5132 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5133 cache_info->cache_filename);
5134 return(MagickFalse);
5136 if ((cache_info->debug != MagickFalse) &&
5137 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5138 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5139 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5140 nexus_info->region.width,(double) nexus_info->region.height,(double)
5141 nexus_info->region.x,(double) nexus_info->region.y);
5146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5150 + W r i t e C a c h e P i x e l s %
5154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5156 % WritePixelCachePixels() writes image pixels to the specified region of the
5159 % The format of the WritePixelCachePixels() method is:
5161 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5162 % NexusInfo *nexus_info,ExceptionInfo *exception)
5164 % A description of each parameter follows:
5166 % o cache_info: the pixel cache.
5168 % o nexus_info: the cache nexus to write the pixels.
5170 % o exception: return any errors or warnings in this structure.
5173 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5174 NexusInfo *nexus_info,ExceptionInfo *exception)
5187 register const Quantum
5193 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5195 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5196 nexus_info->region.x;
5197 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5199 extent=length*nexus_info->region.height;
5200 region=nexus_info->region;
5202 p=nexus_info->pixels;
5203 switch (cache_info->type)
5212 Write pixels to memory.
5214 if ((cache_info->columns == nexus_info->region.width) &&
5215 (extent == (MagickSizeType) ((size_t) extent)))
5220 q=cache_info->pixels+offset*cache_info->number_channels;
5221 for (y=0; y < (ssize_t) region.height; y++)
5223 (void) memcpy(q,p,(size_t) length);
5224 p+=cache_info->number_channels*nexus_info->region.width;
5225 q+=cache_info->columns*cache_info->number_channels;
5232 Write pixels to disk.
5234 LockSemaphoreInfo(cache_info->file_semaphore);
5235 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5237 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5238 cache_info->cache_filename);
5239 UnlockSemaphoreInfo(cache_info->file_semaphore);
5240 return(MagickFalse);
5242 if ((cache_info->columns == nexus_info->region.width) &&
5243 (extent <= MagickMaxBufferExtent))
5248 for (y=0; y < (ssize_t) region.height; y++)
5250 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5251 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5253 if (count != (MagickOffsetType) length)
5255 p+=cache_info->number_channels*nexus_info->region.width;
5256 offset+=cache_info->columns;
5258 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5259 (void) ClosePixelCacheOnDisk(cache_info);
5260 UnlockSemaphoreInfo(cache_info->file_semaphore);
5263 case DistributedCache:
5266 Write pixels to distributed cache.
5268 LockSemaphoreInfo(cache_info->file_semaphore);
5270 for (y=0; y < (ssize_t) region.height; y++)
5272 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5273 length,(const unsigned char *) p);
5274 if (count != (MagickOffsetType) length)
5276 p+=cache_info->number_channels*nexus_info->region.width;
5279 UnlockSemaphoreInfo(cache_info->file_semaphore);
5285 if (y < (ssize_t) region.height)
5287 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5288 cache_info->cache_filename);
5289 return(MagickFalse);
5291 if ((cache_info->debug != MagickFalse) &&
5292 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5293 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5294 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5295 nexus_info->region.width,(double) nexus_info->region.height,(double)
5296 nexus_info->region.x,(double) nexus_info->region.y);