2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
120 Forward declarations.
122 #if defined(__cplusplus) || defined(c_plusplus)
127 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
131 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
132 const ssize_t,const size_t,const size_t,ExceptionInfo *),
133 *GetVirtualPixelsCache(const Image *);
136 *GetVirtualMetacontentFromCache(const Image *);
138 static MagickBooleanType
139 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
141 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
142 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
143 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
144 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
146 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
147 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
148 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
151 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
152 const size_t,ExceptionInfo *),
153 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
154 const size_t,ExceptionInfo *),
155 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
156 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
158 #if defined(__cplusplus) || defined(c_plusplus)
165 static volatile MagickBooleanType
166 instantiate_cache = MagickFalse;
169 *cache_semaphore = (SemaphoreInfo *) NULL;
172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 + A c q u i r e P i x e l C a c h e %
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 % AcquirePixelCache() acquires a pixel cache.
184 % The format of the AcquirePixelCache() method is:
186 % Cache AcquirePixelCache(const size_t number_threads)
188 % A description of each parameter follows:
190 % o number_threads: the number of nexus threads.
193 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
201 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
202 if (cache_info == (CacheInfo *) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
205 cache_info->type=UndefinedCache;
206 cache_info->mode=IOMode;
207 cache_info->colorspace=sRGBColorspace;
208 cache_info->file=(-1);
209 cache_info->id=GetMagickThreadId();
210 cache_info->number_threads=number_threads;
211 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
212 cache_info->number_threads=GetOpenMPMaximumThreads();
213 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
214 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
215 if (cache_info->number_threads == 0)
216 cache_info->number_threads=1;
217 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
218 if (cache_info->nexus_info == (NexusInfo **) NULL)
219 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
220 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
221 if (synchronize != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(synchronize);
224 synchronize=DestroyString(synchronize);
226 cache_info->semaphore=AllocateSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AllocateSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickSignature;
231 return((Cache ) cache_info);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % A c q u i r e P i x e l C a c h e N e x u s %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
247 % The format of the AcquirePixelCacheNexus method is:
249 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 % A description of each parameter follows:
253 % o number_threads: the number of nexus threads.
256 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
264 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
265 number_threads,sizeof(*nexus_info)));
266 if (nexus_info == (NexusInfo **) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
269 sizeof(**nexus_info));
270 if (nexus_info[0] == (NexusInfo *) NULL)
271 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
272 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
273 for (i=0; i < (ssize_t) number_threads; i++)
275 nexus_info[i]=(&nexus_info[0][i]);
276 nexus_info[i]->signature=MagickSignature;
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 + A c q u i r e P i x e l C a c h e P i x e l s %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % AcquirePixelCachePixels() returns the pixels associated with the specified
295 % The format of the AcquirePixelCachePixels() method is:
297 % const void *AcquirePixelCachePixels(const Image *image,
298 % MagickSizeType *length,ExceptionInfo *exception)
300 % A description of each parameter follows:
302 % o image: the image.
304 % o length: the pixel cache length.
306 % o exception: return any errors or warnings in this structure.
309 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
310 MagickSizeType *length,ExceptionInfo *exception)
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickSignature);
323 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
324 return((const void *) NULL);
325 *length=cache_info->length;
326 return((const void *) cache_info->pixels);
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 + C a c h e C o m p o n e n t G e n e s i s %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % CacheComponentGenesis() instantiates the cache component.
342 % The format of the CacheComponentGenesis method is:
344 % MagickBooleanType CacheComponentGenesis(void)
347 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
349 AcquireSemaphoreInfo(&cache_semaphore);
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 + C a c h e C o m p o n e n t T e r m i n u s %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 % CacheComponentTerminus() destroys the cache component.
366 % The format of the CacheComponentTerminus() method is:
368 % CacheComponentTerminus(void)
371 MagickPrivate void CacheComponentTerminus(void)
373 if (cache_semaphore == (SemaphoreInfo *) NULL)
374 AcquireSemaphoreInfo(&cache_semaphore);
375 LockSemaphoreInfo(cache_semaphore);
376 instantiate_cache=MagickFalse;
377 UnlockSemaphoreInfo(cache_semaphore);
378 DestroySemaphoreInfo(&cache_semaphore);
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 + C l o n e P i x e l C a c h e %
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 % ClonePixelCache() clones a pixel cache.
394 % The format of the ClonePixelCache() method is:
396 % Cache ClonePixelCache(const Cache cache)
398 % A description of each parameter follows:
400 % o cache: the pixel cache.
403 MagickPrivate Cache ClonePixelCache(const Cache cache)
411 assert(cache != NULL);
412 cache_info=(const CacheInfo *) cache;
413 assert(cache_info->signature == MagickSignature);
414 if (cache_info->debug != MagickFalse)
415 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
416 cache_info->filename);
417 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
418 if (clone_info == (Cache) NULL)
419 return((Cache) NULL);
420 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
421 return((Cache ) clone_info);
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 + C l o n e P i x e l C a c h e M e t h o d s %
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
438 % The format of the ClonePixelCacheMethods() method is:
440 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
442 % A description of each parameter follows:
444 % o clone: Specifies a pointer to a Cache structure.
446 % o cache: the pixel cache.
449 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
455 assert(clone != (Cache) NULL);
456 source_info=(CacheInfo *) clone;
457 assert(source_info->signature == MagickSignature);
458 if (source_info->debug != MagickFalse)
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
460 source_info->filename);
461 assert(cache != (Cache) NULL);
462 cache_info=(CacheInfo *) cache;
463 assert(cache_info->signature == MagickSignature);
464 source_info->methods=cache_info->methods;
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 + C l o n e P i x e l C a c h e R e p o s i t o r y %
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
477 % ClonePixelCacheRepository() clones the source pixel cache to the destination
480 % The format of the ClonePixelCacheRepository() method is:
482 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
483 % CacheInfo *source_info,ExceptionInfo *exception)
485 % A description of each parameter follows:
487 % o cache_info: the pixel cache.
489 % o source_info: the source pixel cache.
491 % o exception: return any errors or warnings in this structure.
495 static inline MagickSizeType MagickMin(const MagickSizeType x,
496 const MagickSizeType y)
503 static MagickBooleanType ClonePixelCacheRepository(CacheInfo *clone_info,
504 CacheInfo *cache_info,ExceptionInfo *exception)
506 #define MaxCacheThreads 2
507 #define cache_threads(source,destination,chunk) \
508 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
509 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? 1 : \
526 assert(cache_info != (CacheInfo *) NULL);
527 assert(clone_info != (CacheInfo *) NULL);
528 assert(exception != (ExceptionInfo *) NULL);
529 if (cache_info->type == PingCache)
531 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
532 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
533 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
534 (cache_info->columns == clone_info->columns) &&
535 (cache_info->rows == clone_info->rows) &&
536 (cache_info->number_channels == clone_info->number_channels) &&
537 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0))
540 Identical pixel cache morphology.
542 (void) memcpy(clone_info->pixels,cache_info->pixels,cache_info->columns*
543 cache_info->number_channels*cache_info->rows*
544 sizeof(*cache_info->pixels));
545 if ((cache_info->metacontent_extent != 0) &&
546 (clone_info->metacontent_extent != 0) &&
547 (cache_info->metacontent_extent == clone_info->metacontent_extent))
548 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
549 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
550 sizeof(*cache_info->metacontent));
554 Mismatched pixel cache morphology.
556 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
557 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
558 if ((cache_nexus == (NexusInfo **) NULL) ||
559 (clone_nexus == (NexusInfo **) NULL))
560 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
561 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
562 optimize=(cache_info->number_channels == clone_info->number_channels) &&
563 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
564 MagickTrue : MagickFalse;
565 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
566 clone_info->columns*clone_info->number_channels);
568 #if defined(MAGICKCORE_OPENMP_SUPPORT)
569 #pragma omp parallel for schedule(static,4) shared(status) \
570 cache_threads(cache_info,clone_info,cache_info->rows)
572 for (y=0; y < (ssize_t) cache_info->rows; y++)
575 id = GetOpenMPThreadId();
580 register const Quantum
589 if (status == MagickFalse)
591 if (y >= (ssize_t) clone_info->rows)
593 region.width=cache_info->columns;
597 (void) SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
599 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
600 if (status == MagickFalse)
602 p=cache_nexus[id]->pixels;
603 region.width=clone_info->columns;
605 (void) SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
606 clone_nexus[id],exception);
607 q=clone_nexus[id]->pixels;
608 if (optimize != MagickFalse)
609 (void) memcpy(q,p,length*sizeof(Quantum));
611 for (x=0; x < (ssize_t) cache_info->columns; x++)
617 Respect pixel channel map.
619 if (x == (ssize_t) clone_info->columns)
621 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
629 channel=clone_info->channel_map[i].channel;
630 traits=cache_info->channel_map[channel].traits;
631 if (traits != UndefinedPixelTrait)
632 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
636 p+=cache_info->number_channels;
638 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
640 if ((cache_info->metacontent_extent != 0) &&
641 (clone_info->metacontent_extent != 0))
646 length=(size_t) MagickMin(cache_info->metacontent_extent,
647 clone_info->metacontent_extent);
648 for (y=0; y < (ssize_t) cache_info->rows; y++)
651 id = GetOpenMPThreadId();
656 register const unsigned char
659 register unsigned char
662 if (status == MagickFalse)
664 if (y >= (ssize_t) clone_info->rows)
666 region.width=cache_info->columns;
670 (void) SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
671 cache_nexus[id],exception);
672 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
673 if (status == MagickFalse)
675 p=cache_nexus[id]->metacontent;
676 region.width=clone_info->columns;
678 (void) SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
679 clone_nexus[id],exception);
680 q=clone_nexus[id]->metacontent;
681 (void) memcpy(q,p,length*sizeof(*cache_nexus[0]->metacontent));
682 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
685 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
686 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
687 if (cache_info->debug != MagickFalse)
690 message[MaxTextExtent];
692 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
693 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
694 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
695 (void) LogMagickEvent(CacheEvent,GetMagickModule(),message);
701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
705 + D e s t r o y I m a g e P i x e l C a c h e %
709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
711 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
713 % The format of the DestroyImagePixelCache() method is:
715 % void DestroyImagePixelCache(Image *image)
717 % A description of each parameter follows:
719 % o image: the image.
722 static void DestroyImagePixelCache(Image *image)
724 assert(image != (Image *) NULL);
725 assert(image->signature == MagickSignature);
726 if (image->debug != MagickFalse)
727 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
728 if (image->cache == (void *) NULL)
730 image->cache=DestroyPixelCache(image->cache);
734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738 + D e s t r o y I m a g e P i x e l s %
742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
744 % DestroyImagePixels() deallocates memory associated with the pixel cache.
746 % The format of the DestroyImagePixels() method is:
748 % void DestroyImagePixels(Image *image)
750 % A description of each parameter follows:
752 % o image: the image.
755 MagickExport void DestroyImagePixels(Image *image)
760 assert(image != (const Image *) NULL);
761 assert(image->signature == MagickSignature);
762 if (image->debug != MagickFalse)
763 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
764 assert(image->cache != (Cache) NULL);
765 cache_info=(CacheInfo *) image->cache;
766 assert(cache_info->signature == MagickSignature);
767 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
769 cache_info->methods.destroy_pixel_handler(image);
772 image->cache=DestroyPixelCache(image->cache);
776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780 + D e s t r o y P i x e l C a c h e %
784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
786 % DestroyPixelCache() deallocates memory associated with the pixel cache.
788 % The format of the DestroyPixelCache() method is:
790 % Cache DestroyPixelCache(Cache cache)
792 % A description of each parameter follows:
794 % o cache: the pixel cache.
798 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
804 if (cache_info->file != -1)
806 status=close(cache_info->file);
807 cache_info->file=(-1);
808 RelinquishMagickResource(FileResource,1);
810 return(status == -1 ? MagickFalse : MagickTrue);
813 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
815 switch (cache_info->type)
819 if (cache_info->mapped == MagickFalse)
820 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
823 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
824 (size_t) cache_info->length);
825 RelinquishMagickResource(MemoryResource,cache_info->length);
830 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
832 if (cache_info->mode != ReadMode)
833 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
834 *cache_info->cache_filename='\0';
835 RelinquishMagickResource(MapResource,cache_info->length);
839 if (cache_info->file != -1)
840 (void) ClosePixelCacheOnDisk(cache_info);
841 if (cache_info->mode != ReadMode)
842 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
843 *cache_info->cache_filename='\0';
844 RelinquishMagickResource(DiskResource,cache_info->length);
847 case DistributedCache:
849 *cache_info->cache_filename='\0';
850 (void) RelinquishDistributePixelCache(cache_info->server_info);
856 cache_info->type=UndefinedCache;
857 cache_info->mapped=MagickFalse;
858 cache_info->metacontent=(void *) NULL;
861 MagickPrivate Cache DestroyPixelCache(Cache cache)
866 assert(cache != (Cache) NULL);
867 cache_info=(CacheInfo *) cache;
868 assert(cache_info->signature == MagickSignature);
869 if (cache_info->debug != MagickFalse)
870 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
871 cache_info->filename);
872 LockSemaphoreInfo(cache_info->semaphore);
873 cache_info->reference_count--;
874 if (cache_info->reference_count != 0)
876 UnlockSemaphoreInfo(cache_info->semaphore);
877 return((Cache) NULL);
879 UnlockSemaphoreInfo(cache_info->semaphore);
880 if (cache_info->debug != MagickFalse)
883 message[MaxTextExtent];
885 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
886 cache_info->filename);
887 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
889 RelinquishPixelCachePixels(cache_info);
890 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
891 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
892 if (cache_info->nexus_info != (NexusInfo **) NULL)
893 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
894 cache_info->number_threads);
895 if (cache_info->random_info != (RandomInfo *) NULL)
896 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
897 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
898 DestroySemaphoreInfo(&cache_info->file_semaphore);
899 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
900 DestroySemaphoreInfo(&cache_info->semaphore);
901 cache_info->signature=(~MagickSignature);
902 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
912 + D e s t r o y P i x e l C a c h e N e x u s %
916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
920 % The format of the DestroyPixelCacheNexus() method is:
922 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
923 % const size_t number_threads)
925 % A description of each parameter follows:
927 % o nexus_info: the nexus to destroy.
929 % o number_threads: the number of nexus threads.
933 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
935 if (nexus_info->mapped == MagickFalse)
936 (void) RelinquishAlignedMemory(nexus_info->cache);
938 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
939 nexus_info->cache=(Quantum *) NULL;
940 nexus_info->pixels=(Quantum *) NULL;
941 nexus_info->metacontent=(void *) NULL;
942 nexus_info->length=0;
943 nexus_info->mapped=MagickFalse;
946 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
947 const size_t number_threads)
952 assert(nexus_info != (NexusInfo **) NULL);
953 for (i=0; i < (ssize_t) number_threads; i++)
955 if (nexus_info[i]->cache != (Quantum *) NULL)
956 RelinquishCacheNexusPixels(nexus_info[i]);
957 nexus_info[i]->signature=(~MagickSignature);
959 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
960 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
969 % G e t A u t h e n t i c M e t a c o n t e n t %
973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
976 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
977 % returned if the associated pixels are not available.
979 % The format of the GetAuthenticMetacontent() method is:
981 % void *GetAuthenticMetacontent(const Image *image)
983 % A description of each parameter follows:
985 % o image: the image.
988 MagickExport void *GetAuthenticMetacontent(const Image *image)
994 id = GetOpenMPThreadId();
999 assert(image != (const Image *) NULL);
1000 assert(image->signature == MagickSignature);
1001 assert(image->cache != (Cache) NULL);
1002 cache_info=(CacheInfo *) image->cache;
1003 assert(cache_info->signature == MagickSignature);
1004 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1005 (GetAuthenticMetacontentFromHandler) NULL)
1007 metacontent=cache_info->methods.
1008 get_authentic_metacontent_from_handler(image);
1009 return(metacontent);
1011 assert(id < (int) cache_info->number_threads);
1012 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1013 cache_info->nexus_info[id]);
1014 return(metacontent);
1018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022 + 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 %
1026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1029 % with the last call to QueueAuthenticPixelsCache() or
1030 % GetAuthenticPixelsCache().
1032 % The format of the GetAuthenticMetacontentFromCache() method is:
1034 % void *GetAuthenticMetacontentFromCache(const Image *image)
1036 % A description of each parameter follows:
1038 % o image: the image.
1041 static void *GetAuthenticMetacontentFromCache(const Image *image)
1047 id = GetOpenMPThreadId();
1052 assert(image != (const Image *) NULL);
1053 assert(image->signature == MagickSignature);
1054 assert(image->cache != (Cache) NULL);
1055 cache_info=(CacheInfo *) image->cache;
1056 assert(cache_info->signature == MagickSignature);
1057 assert(id < (int) cache_info->number_threads);
1058 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1059 cache_info->nexus_info[id]);
1060 return(metacontent);
1064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1068 + 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 %
1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1074 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1075 % disk pixel cache as defined by the geometry parameters. A pointer to the
1076 % pixels is returned if the pixels are transferred, otherwise a NULL is
1079 % The format of the GetAuthenticPixelCacheNexus() method is:
1081 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1082 % const ssize_t y,const size_t columns,const size_t rows,
1083 % NexusInfo *nexus_info,ExceptionInfo *exception)
1085 % A description of each parameter follows:
1087 % o image: the image.
1089 % o x,y,columns,rows: These values define the perimeter of a region of
1092 % o nexus_info: the cache nexus to return.
1094 % o exception: return any errors or warnings in this structure.
1098 static inline MagickBooleanType IsPixelAuthentic(
1099 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1107 if (cache_info->type == PingCache)
1109 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1110 nexus_info->region.x;
1111 status=nexus_info->pixels == (cache_info->pixels+offset*
1112 cache_info->number_channels) ? MagickTrue : MagickFalse;
1116 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1117 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1118 NexusInfo *nexus_info,ExceptionInfo *exception)
1127 Transfer pixels from the cache.
1129 assert(image != (Image *) NULL);
1130 assert(image->signature == MagickSignature);
1131 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1133 if (q == (Quantum *) NULL)
1134 return((Quantum *) NULL);
1135 cache_info=(CacheInfo *) image->cache;
1136 assert(cache_info->signature == MagickSignature);
1137 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1139 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1140 return((Quantum *) NULL);
1141 if (cache_info->metacontent_extent != 0)
1142 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1143 return((Quantum *) NULL);
1148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 + 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 %
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1159 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1161 % The format of the GetAuthenticPixelsFromCache() method is:
1163 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1165 % A description of each parameter follows:
1167 % o image: the image.
1170 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1176 id = GetOpenMPThreadId();
1178 assert(image != (const Image *) NULL);
1179 assert(image->signature == MagickSignature);
1180 assert(image->cache != (Cache) NULL);
1181 cache_info=(CacheInfo *) image->cache;
1182 assert(cache_info->signature == MagickSignature);
1183 assert(id < (int) cache_info->number_threads);
1184 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 % G e t A u t h e n t i c P i x e l Q u e u e %
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198 % GetAuthenticPixelQueue() returns the authentic pixels associated
1199 % corresponding with the last call to QueueAuthenticPixels() or
1200 % GetAuthenticPixels().
1202 % The format of the GetAuthenticPixelQueue() method is:
1204 % Quantum *GetAuthenticPixelQueue(const Image image)
1206 % A description of each parameter follows:
1208 % o image: the image.
1211 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1217 id = GetOpenMPThreadId();
1219 assert(image != (const Image *) NULL);
1220 assert(image->signature == MagickSignature);
1221 assert(image->cache != (Cache) NULL);
1222 cache_info=(CacheInfo *) image->cache;
1223 assert(cache_info->signature == MagickSignature);
1224 if (cache_info->methods.get_authentic_pixels_from_handler !=
1225 (GetAuthenticPixelsFromHandler) NULL)
1226 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1227 assert(id < (int) cache_info->number_threads);
1228 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1236 % G e t A u t h e n t i c P i x e l s %
1239 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1241 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1242 % region is successfully accessed, a pointer to a Quantum array
1243 % representing the region is returned, otherwise NULL is returned.
1245 % The returned pointer may point to a temporary working copy of the pixels
1246 % or it may point to the original pixels in memory. Performance is maximized
1247 % if the selected region is part of one row, or one or more full rows, since
1248 % then there is opportunity to access the pixels in-place (without a copy)
1249 % if the image is in memory, or in a memory-mapped file. The returned pointer
1250 % must *never* be deallocated by the user.
1252 % Pixels accessed via the returned pointer represent a simple array of type
1253 % Quantum. If the image has corresponding metacontent,call
1254 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1255 % meta-content corresponding to the region. Once the Quantum array has
1256 % been updated, the changes must be saved back to the underlying image using
1257 % SyncAuthenticPixels() or they may be lost.
1259 % The format of the GetAuthenticPixels() method is:
1261 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1262 % const ssize_t y,const size_t columns,const size_t rows,
1263 % ExceptionInfo *exception)
1265 % A description of each parameter follows:
1267 % o image: the image.
1269 % o x,y,columns,rows: These values define the perimeter of a region of
1272 % o exception: return any errors or warnings in this structure.
1275 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1276 const ssize_t y,const size_t columns,const size_t rows,
1277 ExceptionInfo *exception)
1283 id = GetOpenMPThreadId();
1288 assert(image != (Image *) NULL);
1289 assert(image->signature == MagickSignature);
1290 assert(image->cache != (Cache) NULL);
1291 cache_info=(CacheInfo *) image->cache;
1292 assert(cache_info->signature == MagickSignature);
1293 if (cache_info->methods.get_authentic_pixels_handler !=
1294 (GetAuthenticPixelsHandler) NULL)
1296 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1300 assert(id < (int) cache_info->number_threads);
1301 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1302 cache_info->nexus_info[id],exception);
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311 + G e t A u t h e n t i c P i x e l s C a c h e %
1315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1317 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1318 % as defined by the geometry parameters. A pointer to the pixels is returned
1319 % if the pixels are transferred, otherwise a NULL is returned.
1321 % The format of the GetAuthenticPixelsCache() method is:
1323 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1324 % const ssize_t y,const size_t columns,const size_t rows,
1325 % ExceptionInfo *exception)
1327 % A description of each parameter follows:
1329 % o image: the image.
1331 % o x,y,columns,rows: These values define the perimeter of a region of
1334 % o exception: return any errors or warnings in this structure.
1337 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1338 const ssize_t y,const size_t columns,const size_t rows,
1339 ExceptionInfo *exception)
1345 id = GetOpenMPThreadId();
1350 assert(image != (const Image *) NULL);
1351 assert(image->signature == MagickSignature);
1352 assert(image->cache != (Cache) NULL);
1353 cache_info=(CacheInfo *) image->cache;
1354 if (cache_info == (Cache) NULL)
1355 return((Quantum *) NULL);
1356 assert(cache_info->signature == MagickSignature);
1357 assert(id < (int) cache_info->number_threads);
1358 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1359 cache_info->nexus_info[id],exception);
1364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368 + G e t I m a g e E x t e n t %
1372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1374 % GetImageExtent() returns the extent of the pixels associated corresponding
1375 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1377 % The format of the GetImageExtent() method is:
1379 % MagickSizeType GetImageExtent(const Image *image)
1381 % A description of each parameter follows:
1383 % o image: the image.
1386 MagickExport MagickSizeType GetImageExtent(const Image *image)
1392 id = GetOpenMPThreadId();
1394 assert(image != (Image *) NULL);
1395 assert(image->signature == MagickSignature);
1396 if (image->debug != MagickFalse)
1397 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1398 assert(image->cache != (Cache) NULL);
1399 cache_info=(CacheInfo *) image->cache;
1400 assert(cache_info->signature == MagickSignature);
1401 assert(id < (int) cache_info->number_threads);
1402 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410 + G e t I m a g e P i x e l C a c h e %
1414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416 % GetImagePixelCache() ensures that there is only a single reference to the
1417 % pixel cache to be modified, updating the provided cache pointer to point to
1418 % a clone of the original pixel cache if necessary.
1420 % The format of the GetImagePixelCache method is:
1422 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1423 % ExceptionInfo *exception)
1425 % A description of each parameter follows:
1427 % o image: the image.
1429 % o clone: any value other than MagickFalse clones the cache pixels.
1431 % o exception: return any errors or warnings in this structure.
1435 static inline MagickBooleanType ValidatePixelCacheMorphology(
1436 const Image *restrict image)
1439 *restrict cache_info;
1441 const PixelChannelMap
1446 Does the image match the pixel cache morphology?
1448 cache_info=(CacheInfo *) image->cache;
1449 p=image->channel_map;
1450 q=cache_info->channel_map;
1451 if ((image->storage_class != cache_info->storage_class) ||
1452 (image->colorspace != cache_info->colorspace) ||
1453 (image->alpha_trait != cache_info->alpha_trait) ||
1454 (image->mask != cache_info->mask) ||
1455 (image->columns != cache_info->columns) ||
1456 (image->rows != cache_info->rows) ||
1457 (image->number_channels != cache_info->number_channels) ||
1458 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1459 (image->metacontent_extent != cache_info->metacontent_extent) ||
1460 (cache_info->nexus_info == (NexusInfo **) NULL))
1461 return(MagickFalse);
1465 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1466 ExceptionInfo *exception)
1475 static MagickSizeType
1481 cache_timestamp = 0;
1484 LockSemaphoreInfo(image->semaphore);
1485 if (cpu_throttle == 0)
1491 Set CPU throttle in milleseconds.
1493 cpu_throttle=MagickResourceInfinity;
1494 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1495 if (limit == (char *) NULL)
1496 limit=GetPolicyValue("throttle");
1497 if (limit != (char *) NULL)
1499 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1500 limit=DestroyString(limit);
1503 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1504 MagickDelay(cpu_throttle);
1505 if (time_limit == 0)
1508 Set the expire time in seconds.
1510 time_limit=GetMagickResourceLimit(TimeResource);
1511 cache_timestamp=time((time_t *) NULL);
1513 if ((time_limit != MagickResourceInfinity) &&
1514 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1515 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1516 assert(image->cache != (Cache) NULL);
1517 cache_info=(CacheInfo *) image->cache;
1518 destroy=MagickFalse;
1519 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1521 LockSemaphoreInfo(cache_info->semaphore);
1522 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1533 clone_image=(*image);
1534 clone_image.semaphore=AllocateSemaphoreInfo();
1535 clone_image.reference_count=1;
1536 clone_image.cache=ClonePixelCache(cache_info);
1537 clone_info=(CacheInfo *) clone_image.cache;
1538 status=OpenPixelCache(&clone_image,IOMode,exception);
1539 if (status != MagickFalse)
1541 if (clone != MagickFalse)
1542 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
1543 if (status != MagickFalse)
1545 if (cache_info->reference_count == 1)
1546 cache_info->nexus_info=(NexusInfo **) NULL;
1548 image->cache=clone_image.cache;
1551 DestroySemaphoreInfo(&clone_image.semaphore);
1553 UnlockSemaphoreInfo(cache_info->semaphore);
1555 if (destroy != MagickFalse)
1556 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1557 if (status != MagickFalse)
1560 Ensure the image matches the pixel cache morphology.
1562 image->taint=MagickTrue;
1563 image->type=UndefinedType;
1564 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1566 status=OpenPixelCache(image,IOMode,exception);
1567 cache_info=(CacheInfo *) image->cache;
1568 if (cache_info->type == DiskCache)
1569 (void) ClosePixelCacheOnDisk(cache_info);
1572 UnlockSemaphoreInfo(image->semaphore);
1573 if (status == MagickFalse)
1574 return((Cache) NULL);
1575 return(image->cache);
1579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583 + G e t I m a g e P i x e l C a c h e T y p e %
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1590 % DiskCache, MemoryCache, MapCache, or PingCache.
1592 % The format of the GetImagePixelCacheType() method is:
1594 % CacheType GetImagePixelCacheType(const Image *image)
1596 % A description of each parameter follows:
1598 % o image: the image.
1601 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1606 assert(image != (Image *) NULL);
1607 assert(image->signature == MagickSignature);
1608 assert(image->cache != (Cache) NULL);
1609 cache_info=(CacheInfo *) image->cache;
1610 assert(cache_info->signature == MagickSignature);
1611 return(cache_info->type);
1615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619 % G e t O n e A u t h e n t i c P i x e l %
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1626 % location. The image background color is returned if an error occurs.
1628 % The format of the GetOneAuthenticPixel() method is:
1630 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1631 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1633 % A description of each parameter follows:
1635 % o image: the image.
1637 % o x,y: These values define the location of the pixel to return.
1639 % o pixel: return a pixel at the specified (x,y) location.
1641 % o exception: return any errors or warnings in this structure.
1644 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1645 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1656 assert(image != (Image *) NULL);
1657 assert(image->signature == MagickSignature);
1658 assert(image->cache != (Cache) NULL);
1659 cache_info=(CacheInfo *) image->cache;
1660 assert(cache_info->signature == MagickSignature);
1661 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1662 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1663 (GetOneAuthenticPixelFromHandler) NULL)
1664 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1666 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1667 if (q == (Quantum *) NULL)
1669 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1670 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1671 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1672 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1673 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1674 return(MagickFalse);
1676 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1681 channel=GetPixelChannelChannel(image,i);
1682 pixel[channel]=q[i];
1688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1692 + 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 %
1696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1698 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1699 % location. The image background color is returned if an error occurs.
1701 % The format of the GetOneAuthenticPixelFromCache() method is:
1703 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1704 % const ssize_t x,const ssize_t y,Quantum *pixel,
1705 % ExceptionInfo *exception)
1707 % A description of each parameter follows:
1709 % o image: the image.
1711 % o x,y: These values define the location of the pixel to return.
1713 % o pixel: return a pixel at the specified (x,y) location.
1715 % o exception: return any errors or warnings in this structure.
1718 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1719 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1725 id = GetOpenMPThreadId();
1733 assert(image != (const Image *) NULL);
1734 assert(image->signature == MagickSignature);
1735 assert(image->cache != (Cache) NULL);
1736 cache_info=(CacheInfo *) image->cache;
1737 assert(cache_info->signature == MagickSignature);
1738 assert(id < (int) cache_info->number_threads);
1739 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1740 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1742 if (q == (Quantum *) NULL)
1744 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1745 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1746 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1747 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1748 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1749 return(MagickFalse);
1751 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1756 channel=GetPixelChannelChannel(image,i);
1757 pixel[channel]=q[i];
1763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1767 % G e t O n e V i r t u a l P i x e l %
1771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1774 % (x,y) location. The image background color is returned if an error occurs.
1775 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1777 % The format of the GetOneVirtualPixel() method is:
1779 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1780 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1782 % A description of each parameter follows:
1784 % o image: the image.
1786 % o x,y: These values define the location of the pixel to return.
1788 % o pixel: return a pixel at the specified (x,y) location.
1790 % o exception: return any errors or warnings in this structure.
1793 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1794 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1800 id = GetOpenMPThreadId();
1808 assert(image != (const Image *) NULL);
1809 assert(image->signature == MagickSignature);
1810 assert(image->cache != (Cache) NULL);
1811 cache_info=(CacheInfo *) image->cache;
1812 assert(cache_info->signature == MagickSignature);
1813 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1814 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1815 (GetOneVirtualPixelFromHandler) NULL)
1816 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1817 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1818 assert(id < (int) cache_info->number_threads);
1819 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1820 1UL,1UL,cache_info->nexus_info[id],exception);
1821 if (p == (const Quantum *) NULL)
1823 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1824 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1825 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1826 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1827 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1828 return(MagickFalse);
1830 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1835 channel=GetPixelChannelChannel(image,i);
1836 pixel[channel]=p[i];
1842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1846 + 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 %
1850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1852 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1853 % specified (x,y) location. The image background color is returned if an
1856 % The format of the GetOneVirtualPixelFromCache() method is:
1858 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1859 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1860 % Quantum *pixel,ExceptionInfo *exception)
1862 % A description of each parameter follows:
1864 % o image: the image.
1866 % o virtual_pixel_method: the virtual pixel method.
1868 % o x,y: These values define the location of the pixel to return.
1870 % o pixel: return a pixel at the specified (x,y) location.
1872 % o exception: return any errors or warnings in this structure.
1875 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1876 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1877 Quantum *pixel,ExceptionInfo *exception)
1883 id = GetOpenMPThreadId();
1891 assert(image != (const Image *) NULL);
1892 assert(image->signature == MagickSignature);
1893 assert(image->cache != (Cache) NULL);
1894 cache_info=(CacheInfo *) image->cache;
1895 assert(cache_info->signature == MagickSignature);
1896 assert(id < (int) cache_info->number_threads);
1897 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1898 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1899 cache_info->nexus_info[id],exception);
1900 if (p == (const Quantum *) NULL)
1902 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1903 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1904 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1905 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1906 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1907 return(MagickFalse);
1909 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1914 channel=GetPixelChannelChannel(image,i);
1915 pixel[channel]=p[i];
1921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1925 % G e t O n e V i r t u a l P i x e l I n f o %
1929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1931 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1932 % location. The image background color is returned if an error occurs. If
1933 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1935 % The format of the GetOneVirtualPixelInfo() method is:
1937 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1938 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1939 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1941 % A description of each parameter follows:
1943 % o image: the image.
1945 % o virtual_pixel_method: the virtual pixel method.
1947 % o x,y: these values define the location of the pixel to return.
1949 % o pixel: return a pixel at the specified (x,y) location.
1951 % o exception: return any errors or warnings in this structure.
1954 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1955 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1956 PixelInfo *pixel,ExceptionInfo *exception)
1962 id = GetOpenMPThreadId();
1964 register const Quantum
1967 assert(image != (const Image *) NULL);
1968 assert(image->signature == MagickSignature);
1969 assert(image->cache != (Cache) NULL);
1970 cache_info=(CacheInfo *) image->cache;
1971 assert(cache_info->signature == MagickSignature);
1972 assert(id < (int) cache_info->number_threads);
1973 GetPixelInfo(image,pixel);
1974 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1975 cache_info->nexus_info[id],exception);
1976 if (p == (const Quantum *) NULL)
1977 return(MagickFalse);
1978 GetPixelInfoPixel(image,p,pixel);
1983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987 + G e t P i x e l C a c h e C o l o r s p a c e %
1991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1993 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1995 % The format of the GetPixelCacheColorspace() method is:
1997 % Colorspace GetPixelCacheColorspace(Cache cache)
1999 % A description of each parameter follows:
2001 % o cache: the pixel cache.
2004 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2009 assert(cache != (Cache) NULL);
2010 cache_info=(CacheInfo *) cache;
2011 assert(cache_info->signature == MagickSignature);
2012 if (cache_info->debug != MagickFalse)
2013 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2014 cache_info->filename);
2015 return(cache_info->colorspace);
2019 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2023 + G e t P i x e l C a c h e M e t h o d s %
2027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2029 % GetPixelCacheMethods() initializes the CacheMethods structure.
2031 % The format of the GetPixelCacheMethods() method is:
2033 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2035 % A description of each parameter follows:
2037 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2040 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2042 assert(cache_methods != (CacheMethods *) NULL);
2043 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2044 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2045 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2046 cache_methods->get_virtual_metacontent_from_handler=
2047 GetVirtualMetacontentFromCache;
2048 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2049 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2050 cache_methods->get_authentic_metacontent_from_handler=
2051 GetAuthenticMetacontentFromCache;
2052 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2053 cache_methods->get_one_authentic_pixel_from_handler=
2054 GetOneAuthenticPixelFromCache;
2055 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2056 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2057 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2065 + G e t P i x e l C a c h e N e x u s E x t e n t %
2069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2072 % corresponding with the last call to SetPixelCacheNexusPixels() or
2073 % GetPixelCacheNexusPixels().
2075 % The format of the GetPixelCacheNexusExtent() method is:
2077 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2078 % NexusInfo *nexus_info)
2080 % A description of each parameter follows:
2082 % o nexus_info: the nexus info.
2085 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2086 NexusInfo *nexus_info)
2094 assert(cache != NULL);
2095 cache_info=(CacheInfo *) cache;
2096 assert(cache_info->signature == MagickSignature);
2097 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2099 return((MagickSizeType) cache_info->columns*cache_info->rows);
2104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2108 + 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 %
2112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2114 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2117 % The format of the GetPixelCacheNexusMetacontent() method is:
2119 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2120 % NexusInfo *nexus_info)
2122 % A description of each parameter follows:
2124 % o cache: the pixel cache.
2126 % o nexus_info: the cache nexus to return the meta-content.
2129 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2130 NexusInfo *nexus_info)
2135 assert(cache != NULL);
2136 cache_info=(CacheInfo *) cache;
2137 assert(cache_info->signature == MagickSignature);
2138 if (cache_info->storage_class == UndefinedClass)
2139 return((void *) NULL);
2140 return(nexus_info->metacontent);
2144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2148 + G e t P i x e l C a c h e N e x u s P i x e l s %
2152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2154 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2157 % The format of the GetPixelCacheNexusPixels() method is:
2159 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2160 % NexusInfo *nexus_info)
2162 % A description of each parameter follows:
2164 % o cache: the pixel cache.
2166 % o nexus_info: the cache nexus to return the pixels.
2169 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2170 NexusInfo *nexus_info)
2175 assert(cache != NULL);
2176 cache_info=(CacheInfo *) cache;
2177 assert(cache_info->signature == MagickSignature);
2178 if (cache_info->storage_class == UndefinedClass)
2179 return((Quantum *) NULL);
2180 return(nexus_info->pixels);
2184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2188 + G e t P i x e l C a c h e P i x e l s %
2192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2194 % GetPixelCachePixels() returns the pixels associated with the specified image.
2196 % The format of the GetPixelCachePixels() method is:
2198 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2199 % ExceptionInfo *exception)
2201 % A description of each parameter follows:
2203 % o image: the image.
2205 % o length: the pixel cache length.
2207 % o exception: return any errors or warnings in this structure.
2210 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2211 ExceptionInfo *exception)
2216 assert(image != (const Image *) NULL);
2217 assert(image->signature == MagickSignature);
2218 assert(image->cache != (Cache) NULL);
2219 assert(length != (MagickSizeType *) NULL);
2220 assert(exception != (ExceptionInfo *) NULL);
2221 assert(exception->signature == MagickSignature);
2222 cache_info=(CacheInfo *) image->cache;
2223 assert(cache_info->signature == MagickSignature);
2225 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2226 return((void *) NULL);
2227 *length=cache_info->length;
2228 return((void *) cache_info->pixels);
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2236 + 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 %
2240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2244 % The format of the GetPixelCacheStorageClass() method is:
2246 % ClassType GetPixelCacheStorageClass(Cache cache)
2248 % A description of each parameter follows:
2250 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2252 % o cache: the pixel cache.
2255 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2260 assert(cache != (Cache) NULL);
2261 cache_info=(CacheInfo *) cache;
2262 assert(cache_info->signature == MagickSignature);
2263 if (cache_info->debug != MagickFalse)
2264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2265 cache_info->filename);
2266 return(cache_info->storage_class);
2270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2274 + G e t P i x e l C a c h e T i l e S i z e %
2278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2280 % GetPixelCacheTileSize() returns the pixel cache tile size.
2282 % The format of the GetPixelCacheTileSize() method is:
2284 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2287 % A description of each parameter follows:
2289 % o image: the image.
2291 % o width: the optimize cache tile width in pixels.
2293 % o height: the optimize cache tile height in pixels.
2296 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2302 assert(image != (Image *) NULL);
2303 assert(image->signature == MagickSignature);
2304 if (image->debug != MagickFalse)
2305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2306 cache_info=(CacheInfo *) image->cache;
2307 assert(cache_info->signature == MagickSignature);
2308 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2309 if (GetImagePixelCacheType(image) == DiskCache)
2310 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319 + 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 %
2323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2325 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2326 % pixel cache. A virtual pixel is any pixel access that is outside the
2327 % boundaries of the image cache.
2329 % The format of the GetPixelCacheVirtualMethod() method is:
2331 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2333 % A description of each parameter follows:
2335 % o image: the image.
2338 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2343 assert(image != (Image *) NULL);
2344 assert(image->signature == MagickSignature);
2345 assert(image->cache != (Cache) NULL);
2346 cache_info=(CacheInfo *) image->cache;
2347 assert(cache_info->signature == MagickSignature);
2348 return(cache_info->virtual_pixel_method);
2352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2356 + 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 %
2360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2362 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2363 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2365 % The format of the GetVirtualMetacontentFromCache() method is:
2367 % void *GetVirtualMetacontentFromCache(const Image *image)
2369 % A description of each parameter follows:
2371 % o image: the image.
2374 static const void *GetVirtualMetacontentFromCache(const Image *image)
2380 id = GetOpenMPThreadId();
2385 assert(image != (const Image *) NULL);
2386 assert(image->signature == MagickSignature);
2387 assert(image->cache != (Cache) NULL);
2388 cache_info=(CacheInfo *) image->cache;
2389 assert(cache_info->signature == MagickSignature);
2390 assert(id < (int) cache_info->number_threads);
2391 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2392 cache_info->nexus_info[id]);
2393 return(metacontent);
2397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2401 + 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 %
2405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2407 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2410 % The format of the GetVirtualMetacontentFromNexus() method is:
2412 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2413 % NexusInfo *nexus_info)
2415 % A description of each parameter follows:
2417 % o cache: the pixel cache.
2419 % o nexus_info: the cache nexus to return the meta-content.
2422 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2423 NexusInfo *nexus_info)
2428 assert(cache != (Cache) NULL);
2429 cache_info=(CacheInfo *) cache;
2430 assert(cache_info->signature == MagickSignature);
2431 if (cache_info->storage_class == UndefinedClass)
2432 return((void *) NULL);
2433 return(nexus_info->metacontent);
2437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2441 % G e t V i r t u a l M e t a c o n t e n t %
2445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2447 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2448 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2449 % returned if the meta-content are not available.
2451 % The format of the GetVirtualMetacontent() method is:
2453 % const void *GetVirtualMetacontent(const Image *image)
2455 % A description of each parameter follows:
2457 % o image: the image.
2460 MagickExport const void *GetVirtualMetacontent(const Image *image)
2466 id = GetOpenMPThreadId();
2471 assert(image != (const Image *) NULL);
2472 assert(image->signature == MagickSignature);
2473 assert(image->cache != (Cache) NULL);
2474 cache_info=(CacheInfo *) image->cache;
2475 assert(cache_info->signature == MagickSignature);
2476 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2477 if (metacontent != (void *) NULL)
2478 return(metacontent);
2479 assert(id < (int) cache_info->number_threads);
2480 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2481 cache_info->nexus_info[id]);
2482 return(metacontent);
2486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2490 + 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 %
2494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2496 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2497 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2498 % is returned if the pixels are transferred, otherwise a NULL is returned.
2500 % The format of the GetVirtualPixelsFromNexus() method is:
2502 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2503 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2504 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2505 % ExceptionInfo *exception)
2507 % A description of each parameter follows:
2509 % o image: the image.
2511 % o virtual_pixel_method: the virtual pixel method.
2513 % o x,y,columns,rows: These values define the perimeter of a region of
2516 % o nexus_info: the cache nexus to acquire.
2518 % o exception: return any errors or warnings in this structure.
2525 0, 48, 12, 60, 3, 51, 15, 63,
2526 32, 16, 44, 28, 35, 19, 47, 31,
2527 8, 56, 4, 52, 11, 59, 7, 55,
2528 40, 24, 36, 20, 43, 27, 39, 23,
2529 2, 50, 14, 62, 1, 49, 13, 61,
2530 34, 18, 46, 30, 33, 17, 45, 29,
2531 10, 58, 6, 54, 9, 57, 5, 53,
2532 42, 26, 38, 22, 41, 25, 37, 21
2535 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2540 index=x+DitherMatrix[x & 0x07]-32L;
2543 if (index >= (ssize_t) columns)
2544 return((ssize_t) columns-1L);
2548 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2553 index=y+DitherMatrix[y & 0x07]-32L;
2556 if (index >= (ssize_t) rows)
2557 return((ssize_t) rows-1L);
2561 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2565 if (x >= (ssize_t) columns)
2566 return((ssize_t) (columns-1));
2570 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2574 if (y >= (ssize_t) rows)
2575 return((ssize_t) (rows-1));
2579 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2581 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2584 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2586 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2589 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2590 const size_t extent)
2596 Compute the remainder of dividing offset by extent. It returns not only
2597 the quotient (tile the offset falls in) but also the positive remainer
2598 within that tile such that 0 <= remainder < extent. This method is
2599 essentially a ldiv() using a floored modulo division rather than the
2600 normal default truncated modulo division.
2602 modulo.quotient=offset/(ssize_t) extent;
2605 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2609 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2610 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2611 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2612 ExceptionInfo *exception)
2629 virtual_pixel[CompositePixelChannel];
2634 register const Quantum
2647 register unsigned char
2654 *virtual_metacontent;
2659 assert(image != (const Image *) NULL);
2660 assert(image->signature == MagickSignature);
2661 assert(image->cache != (Cache) NULL);
2662 cache_info=(CacheInfo *) image->cache;
2663 assert(cache_info->signature == MagickSignature);
2664 if (cache_info->type == UndefinedCache)
2665 return((const Quantum *) NULL);
2668 region.width=columns;
2670 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2672 if (pixels == (Quantum *) NULL)
2673 return((const Quantum *) NULL);
2675 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2676 nexus_info->region.x;
2677 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2678 nexus_info->region.width-1L;
2679 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2680 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2681 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2682 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2688 Pixel request is inside cache extents.
2690 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2692 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2693 if (status == MagickFalse)
2694 return((const Quantum *) NULL);
2695 if (cache_info->metacontent_extent != 0)
2697 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2698 if (status == MagickFalse)
2699 return((const Quantum *) NULL);
2704 Pixel request is outside cache extents.
2706 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2707 virtual_nexus=AcquirePixelCacheNexus(1);
2708 if (virtual_nexus == (NexusInfo **) NULL)
2710 if (virtual_nexus != (NexusInfo **) NULL)
2711 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2712 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2713 "UnableToGetCacheNexus","`%s'",image->filename);
2714 return((const Quantum *) NULL);
2716 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2717 sizeof(*virtual_pixel));
2718 virtual_metacontent=(void *) NULL;
2719 switch (virtual_pixel_method)
2721 case BackgroundVirtualPixelMethod:
2722 case BlackVirtualPixelMethod:
2723 case GrayVirtualPixelMethod:
2724 case TransparentVirtualPixelMethod:
2725 case MaskVirtualPixelMethod:
2726 case WhiteVirtualPixelMethod:
2727 case EdgeVirtualPixelMethod:
2728 case CheckerTileVirtualPixelMethod:
2729 case HorizontalTileVirtualPixelMethod:
2730 case VerticalTileVirtualPixelMethod:
2732 if (cache_info->metacontent_extent != 0)
2735 Acquire a metacontent buffer.
2737 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2738 cache_info->metacontent_extent);
2739 if (virtual_metacontent == (void *) NULL)
2741 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2742 (void) ThrowMagickException(exception,GetMagickModule(),
2743 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2744 return((const Quantum *) NULL);
2746 (void) ResetMagickMemory(virtual_metacontent,0,
2747 cache_info->metacontent_extent);
2749 switch (virtual_pixel_method)
2751 case BlackVirtualPixelMethod:
2753 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2754 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2755 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2758 case GrayVirtualPixelMethod:
2760 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2761 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2763 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2766 case TransparentVirtualPixelMethod:
2768 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2769 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2770 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2773 case MaskVirtualPixelMethod:
2774 case WhiteVirtualPixelMethod:
2776 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2777 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2778 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2783 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2785 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2787 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2789 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2791 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2801 for (v=0; v < (ssize_t) rows; v++)
2803 for (u=0; u < (ssize_t) columns; u+=length)
2805 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
2806 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
2807 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
2815 Transfer a single pixel.
2817 length=(MagickSizeType) 1;
2818 switch (virtual_pixel_method)
2822 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2823 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
2824 1UL,1UL,*virtual_nexus,exception);
2825 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2828 case RandomVirtualPixelMethod:
2830 if (cache_info->random_info == (RandomInfo *) NULL)
2831 cache_info->random_info=AcquireRandomInfo();
2832 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2833 RandomX(cache_info->random_info,cache_info->columns),
2834 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2835 *virtual_nexus,exception);
2836 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2839 case DitherVirtualPixelMethod:
2841 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2842 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
2843 1UL,1UL,*virtual_nexus,exception);
2844 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2847 case TileVirtualPixelMethod:
2849 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2850 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2851 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2852 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2854 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2857 case MirrorVirtualPixelMethod:
2859 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2860 if ((x_modulo.quotient & 0x01) == 1L)
2861 x_modulo.remainder=(ssize_t) cache_info->columns-
2862 x_modulo.remainder-1L;
2863 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2864 if ((y_modulo.quotient & 0x01) == 1L)
2865 y_modulo.remainder=(ssize_t) cache_info->rows-
2866 y_modulo.remainder-1L;
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 HorizontalTileEdgeVirtualPixelMethod:
2875 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2876 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2877 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
2878 *virtual_nexus,exception);
2879 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2882 case VerticalTileEdgeVirtualPixelMethod:
2884 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2885 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2886 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
2887 *virtual_nexus,exception);
2888 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2891 case BackgroundVirtualPixelMethod:
2892 case BlackVirtualPixelMethod:
2893 case GrayVirtualPixelMethod:
2894 case TransparentVirtualPixelMethod:
2895 case MaskVirtualPixelMethod:
2896 case WhiteVirtualPixelMethod:
2899 r=virtual_metacontent;
2902 case EdgeVirtualPixelMethod:
2903 case CheckerTileVirtualPixelMethod:
2905 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2906 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2907 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2910 r=virtual_metacontent;
2913 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2914 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2916 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2919 case HorizontalTileVirtualPixelMethod:
2921 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
2924 r=virtual_metacontent;
2927 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2928 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2929 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2930 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2932 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2935 case VerticalTileVirtualPixelMethod:
2937 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
2940 r=virtual_metacontent;
2943 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2944 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2945 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2946 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2948 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2952 if (p == (const Quantum *) NULL)
2954 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2956 q+=cache_info->number_channels;
2957 if ((s != (void *) NULL) && (r != (const void *) NULL))
2959 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2960 s+=cache_info->metacontent_extent;
2965 Transfer a run of pixels.
2967 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
2968 length,1UL,*virtual_nexus,exception);
2969 if (p == (const Quantum *) NULL)
2971 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2972 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2973 q+=length*cache_info->number_channels;
2974 if ((r != (void *) NULL) && (s != (const void *) NULL))
2976 (void) memcpy(s,r,(size_t) length);
2977 s+=length*cache_info->metacontent_extent;
2984 if (virtual_metacontent != (void *) NULL)
2985 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2986 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2995 + G e t V i r t u a l P i x e l C a c h e %
2999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3002 % cache as defined by the geometry parameters. A pointer to the pixels
3003 % is returned if the pixels are transferred, otherwise a NULL is returned.
3005 % The format of the GetVirtualPixelCache() method is:
3007 % const Quantum *GetVirtualPixelCache(const Image *image,
3008 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3009 % const ssize_t y,const size_t columns,const size_t rows,
3010 % ExceptionInfo *exception)
3012 % A description of each parameter follows:
3014 % o image: the image.
3016 % o virtual_pixel_method: the virtual pixel method.
3018 % o x,y,columns,rows: These values define the perimeter of a region of
3021 % o exception: return any errors or warnings in this structure.
3024 static const Quantum *GetVirtualPixelCache(const Image *image,
3025 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3026 const size_t columns,const size_t rows,ExceptionInfo *exception)
3032 id = GetOpenMPThreadId();
3037 assert(image != (const Image *) NULL);
3038 assert(image->signature == MagickSignature);
3039 assert(image->cache != (Cache) NULL);
3040 cache_info=(CacheInfo *) image->cache;
3041 assert(cache_info->signature == MagickSignature);
3042 assert(id < (int) cache_info->number_threads);
3043 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3044 cache_info->nexus_info[id],exception);
3049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3053 % G e t V i r t u a l P i x e l Q u e u e %
3057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3059 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3060 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3062 % The format of the GetVirtualPixelQueue() method is:
3064 % const Quantum *GetVirtualPixelQueue(const Image image)
3066 % A description of each parameter follows:
3068 % o image: the image.
3071 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3077 id = GetOpenMPThreadId();
3079 assert(image != (const Image *) NULL);
3080 assert(image->signature == MagickSignature);
3081 assert(image->cache != (Cache) NULL);
3082 cache_info=(CacheInfo *) image->cache;
3083 assert(cache_info->signature == MagickSignature);
3084 if (cache_info->methods.get_virtual_pixels_handler !=
3085 (GetVirtualPixelsHandler) NULL)
3086 return(cache_info->methods.get_virtual_pixels_handler(image));
3087 assert(id < (int) cache_info->number_threads);
3088 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3096 % G e t V i r t u a l P i x e l s %
3100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3102 % GetVirtualPixels() returns an immutable pixel region. If the
3103 % region is successfully accessed, a pointer to it is returned, otherwise
3104 % NULL is returned. The returned pointer may point to a temporary working
3105 % copy of the pixels or it may point to the original pixels in memory.
3106 % Performance is maximized if the selected region is part of one row, or one
3107 % or more full rows, since there is opportunity to access the pixels in-place
3108 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3109 % returned pointer must *never* be deallocated by the user.
3111 % Pixels accessed via the returned pointer represent a simple array of type
3112 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3113 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3114 % access the meta-content (of type void) corresponding to the the
3117 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3119 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3120 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3121 % GetCacheViewAuthenticPixels() instead.
3123 % The format of the GetVirtualPixels() method is:
3125 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3126 % const ssize_t y,const size_t columns,const size_t rows,
3127 % ExceptionInfo *exception)
3129 % A description of each parameter follows:
3131 % o image: the image.
3133 % o x,y,columns,rows: These values define the perimeter of a region of
3136 % o exception: return any errors or warnings in this structure.
3139 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3140 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3141 ExceptionInfo *exception)
3147 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 if (cache_info->methods.get_virtual_pixel_handler !=
3158 (GetVirtualPixelHandler) NULL)
3159 return(cache_info->methods.get_virtual_pixel_handler(image,
3160 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3161 assert(id < (int) cache_info->number_threads);
3162 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3163 columns,rows,cache_info->nexus_info[id],exception);
3168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3172 + 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 %
3176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3178 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3179 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3181 % The format of the GetVirtualPixelsCache() method is:
3183 % Quantum *GetVirtualPixelsCache(const Image *image)
3185 % A description of each parameter follows:
3187 % o image: the image.
3190 static const Quantum *GetVirtualPixelsCache(const Image *image)
3196 id = GetOpenMPThreadId();
3198 assert(image != (const Image *) NULL);
3199 assert(image->signature == MagickSignature);
3200 assert(image->cache != (Cache) NULL);
3201 cache_info=(CacheInfo *) image->cache;
3202 assert(cache_info->signature == MagickSignature);
3203 assert(id < (int) cache_info->number_threads);
3204 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3212 + G e t V i r t u a l P i x e l s N e x u s %
3216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3218 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3221 % The format of the GetVirtualPixelsNexus() method is:
3223 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3224 % NexusInfo *nexus_info)
3226 % A description of each parameter follows:
3228 % o cache: the pixel cache.
3230 % o nexus_info: the cache nexus to return the colormap pixels.
3233 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3234 NexusInfo *nexus_info)
3239 assert(cache != (Cache) NULL);
3240 cache_info=(CacheInfo *) cache;
3241 assert(cache_info->signature == MagickSignature);
3242 if (cache_info->storage_class == UndefinedClass)
3243 return((Quantum *) NULL);
3244 return((const Quantum *) nexus_info->pixels);
3248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3252 + O p e n P i x e l C a c h e %
3256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3258 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3259 % dimensions, allocating space for the image pixels and optionally the
3260 % metacontent, and memory mapping the cache if it is disk based. The cache
3261 % nexus array is initialized as well.
3263 % The format of the OpenPixelCache() method is:
3265 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3266 % ExceptionInfo *exception)
3268 % A description of each parameter follows:
3270 % o image: the image.
3272 % o mode: ReadMode, WriteMode, or IOMode.
3274 % o exception: return any errors or warnings in this structure.
3278 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3280 cache_info->mapped=MagickFalse;
3281 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3282 (size_t) cache_info->length));
3283 if (cache_info->pixels == (Quantum *) NULL)
3285 cache_info->mapped=MagickTrue;
3286 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3287 cache_info->length);
3291 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3298 Open pixel cache on disk.
3300 if (cache_info->file != -1)
3301 return(MagickTrue); /* cache already open */
3302 if (*cache_info->cache_filename == '\0')
3303 file=AcquireUniqueFileResource(cache_info->cache_filename);
3309 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3314 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3315 O_BINARY | O_EXCL,S_MODE);
3317 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3323 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3326 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3331 return(MagickFalse);
3332 (void) AcquireMagickResource(FileResource,1);
3333 cache_info->file=file;
3334 cache_info->mode=mode;
3338 static inline MagickOffsetType WritePixelCacheRegion(
3339 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3340 const MagickSizeType length,const unsigned char *restrict buffer)
3342 register MagickOffsetType
3348 #if !defined(MAGICKCORE_HAVE_PWRITE)
3349 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3350 return((MagickOffsetType) -1);
3353 for (i=0; i < (MagickOffsetType) length; i+=count)
3355 #if !defined(MAGICKCORE_HAVE_PWRITE)
3356 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3357 (MagickSizeType) SSIZE_MAX));
3359 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3360 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3372 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3382 cache_info=(CacheInfo *) image->cache;
3383 if (image->debug != MagickFalse)
3386 format[MaxTextExtent],
3387 message[MaxTextExtent];
3389 (void) FormatMagickSize(length,MagickFalse,format);
3390 (void) FormatLocaleString(message,MaxTextExtent,
3391 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3392 cache_info->cache_filename,cache_info->file,format);
3393 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3395 if (length != (MagickSizeType) ((MagickOffsetType) length))
3396 return(MagickFalse);
3397 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3399 return(MagickFalse);
3400 if ((MagickSizeType) offset >= length)
3402 extent=(MagickOffsetType) length-1;
3403 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3404 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3405 if (cache_info->synchronize != MagickFalse)
3410 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3412 return(MagickFalse);
3415 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3418 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3419 ExceptionInfo *exception)
3426 format[MaxTextExtent],
3427 message[MaxTextExtent];
3443 assert(image != (const Image *) NULL);
3444 assert(image->signature == MagickSignature);
3445 assert(image->cache != (Cache) NULL);
3446 if (image->debug != MagickFalse)
3447 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3448 if ((image->columns == 0) || (image->rows == 0))
3449 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3450 cache_info=(CacheInfo *) image->cache;
3451 assert(cache_info->signature == MagickSignature);
3452 source_info=(*cache_info);
3453 source_info.file=(-1);
3454 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3455 image->filename,(double) GetImageIndexInList(image));
3456 cache_info->storage_class=image->storage_class;
3457 cache_info->colorspace=image->colorspace;
3458 cache_info->alpha_trait=image->alpha_trait;
3459 cache_info->mask=image->mask;
3460 cache_info->rows=image->rows;
3461 cache_info->columns=image->columns;
3462 InitializePixelChannelMap(image);
3463 cache_info->number_channels=GetPixelChannels(image);
3464 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3465 sizeof(*image->channel_map));
3466 cache_info->metacontent_extent=image->metacontent_extent;
3467 cache_info->mode=mode;
3468 if (image->ping != MagickFalse)
3470 cache_info->type=PingCache;
3471 cache_info->pixels=(Quantum *) NULL;
3472 cache_info->metacontent=(void *) NULL;
3473 cache_info->length=0;
3476 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3477 packet_size=cache_info->number_channels*sizeof(Quantum);
3478 if (image->metacontent_extent != 0)
3479 packet_size+=cache_info->metacontent_extent;
3480 length=number_pixels*packet_size;
3481 columns=(size_t) (length/cache_info->rows/packet_size);
3482 if (cache_info->columns != columns)
3483 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3485 cache_info->length=length;
3486 status=AcquireMagickResource(AreaResource,cache_info->length);
3487 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3488 cache_info->metacontent_extent);
3489 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3491 status=AcquireMagickResource(MemoryResource,cache_info->length);
3492 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3493 (cache_info->type == MemoryCache))
3495 AllocatePixelCachePixels(cache_info);
3496 if (cache_info->pixels == (Quantum *) NULL)
3497 cache_info->pixels=source_info.pixels;
3501 Create memory pixel cache.
3504 cache_info->type=MemoryCache;
3505 cache_info->metacontent=(void *) NULL;
3506 if (cache_info->metacontent_extent != 0)
3507 cache_info->metacontent=(void *) (cache_info->pixels+
3508 number_pixels*cache_info->number_channels);
3509 if ((source_info.storage_class != UndefinedClass) &&
3512 status=ClonePixelCacheRepository(cache_info,&source_info,
3514 RelinquishPixelCachePixels(&source_info);
3516 if (image->debug != MagickFalse)
3518 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3519 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3521 (void) FormatLocaleString(message,MaxTextExtent,
3522 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3523 cache_info->filename,cache_info->mapped != MagickFalse ?
3524 "Anonymous" : "Heap",type,(double) cache_info->columns,
3525 (double) cache_info->rows,(double)
3526 cache_info->number_channels,format);
3527 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3533 RelinquishMagickResource(MemoryResource,cache_info->length);
3536 Create pixel cache on disk.
3538 status=AcquireMagickResource(DiskResource,cache_info->length);
3539 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3544 if (cache_info->type == DistributedCache)
3545 RelinquishMagickResource(DiskResource,cache_info->length);
3546 server_info=AcquireDistributeCacheInfo(exception);
3547 if (server_info != (DistributeCacheInfo *) NULL)
3549 status=OpenDistributePixelCache(server_info,image);
3550 if (status == MagickFalse)
3551 server_info=DestroyDistributeCacheInfo(server_info);
3555 Create a distributed pixel cache.
3557 cache_info->type=DistributedCache;
3558 cache_info->server_info=server_info;
3559 (void) FormatLocaleString(cache_info->cache_filename,
3560 MaxTextExtent,"%s:%d",
3561 GetDistributeCacheHostname(cache_info->server_info),
3562 GetDistributeCachePort(cache_info->server_info));
3563 if ((source_info.storage_class != UndefinedClass) &&
3566 status=ClonePixelCacheRepository(cache_info,&source_info,
3568 RelinquishPixelCachePixels(&source_info);
3570 if (image->debug != MagickFalse)
3572 (void) FormatMagickSize(cache_info->length,MagickFalse,
3574 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3576 (void) FormatLocaleString(message,MaxTextExtent,
3577 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3578 cache_info->filename,cache_info->cache_filename,
3579 GetDistributeCacheFile(cache_info->server_info),type,
3580 (double) cache_info->columns,(double) cache_info->rows,
3581 (double) cache_info->number_channels,format);
3582 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3588 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3589 "CacheResourcesExhausted","`%s'",image->filename);
3590 return(MagickFalse);
3592 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3594 (void) ClosePixelCacheOnDisk(cache_info);
3595 *cache_info->cache_filename='\0';
3597 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3599 RelinquishMagickResource(DiskResource,cache_info->length);
3600 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3602 return(MagickFalse);
3604 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3605 cache_info->length);
3606 if (status == MagickFalse)
3608 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3610 return(MagickFalse);
3612 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3613 cache_info->metacontent_extent);
3614 if (length != (MagickSizeType) ((size_t) length))
3615 cache_info->type=DiskCache;
3618 status=AcquireMagickResource(MapResource,cache_info->length);
3619 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3620 (cache_info->type != MemoryCache))
3621 cache_info->type=DiskCache;
3624 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3625 cache_info->offset,(size_t) cache_info->length);
3626 if (cache_info->pixels == (Quantum *) NULL)
3628 cache_info->type=DiskCache;
3629 cache_info->pixels=source_info.pixels;
3634 Create file-backed memory-mapped pixel cache.
3637 (void) ClosePixelCacheOnDisk(cache_info);
3638 cache_info->type=MapCache;
3639 cache_info->mapped=MagickTrue;
3640 cache_info->metacontent=(void *) NULL;
3641 if (cache_info->metacontent_extent != 0)
3642 cache_info->metacontent=(void *) (cache_info->pixels+
3643 number_pixels*cache_info->number_channels);
3644 if ((source_info.storage_class != UndefinedClass) &&
3647 status=ClonePixelCacheRepository(cache_info,&source_info,
3649 RelinquishPixelCachePixels(&source_info);
3651 if (image->debug != MagickFalse)
3653 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3654 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3656 (void) FormatLocaleString(message,MaxTextExtent,
3657 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3658 cache_info->filename,cache_info->cache_filename,
3659 cache_info->file,type,(double) cache_info->columns,(double)
3660 cache_info->rows,(double) cache_info->number_channels,
3662 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3668 RelinquishMagickResource(MapResource,cache_info->length);
3671 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3673 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3674 RelinquishPixelCachePixels(&source_info);
3676 if (image->debug != MagickFalse)
3678 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3679 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3681 (void) FormatLocaleString(message,MaxTextExtent,
3682 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3683 cache_info->cache_filename,cache_info->file,type,(double)
3684 cache_info->columns,(double) cache_info->rows,(double)
3685 cache_info->number_channels,format);
3686 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3696 + P e r s i s t P i x e l C a c h e %
3700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3702 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3703 % persistent pixel cache is one that resides on disk and is not destroyed
3704 % when the program exits.
3706 % The format of the PersistPixelCache() method is:
3708 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3709 % const MagickBooleanType attach,MagickOffsetType *offset,
3710 % ExceptionInfo *exception)
3712 % A description of each parameter follows:
3714 % o image: the image.
3716 % o filename: the persistent pixel cache filename.
3718 % o attach: A value other than zero initializes the persistent pixel cache.
3720 % o initialize: A value other than zero initializes the persistent pixel
3723 % o offset: the offset in the persistent cache to store pixels.
3725 % o exception: return any errors or warnings in this structure.
3728 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3729 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3730 ExceptionInfo *exception)
3745 assert(image != (Image *) NULL);
3746 assert(image->signature == MagickSignature);
3747 if (image->debug != MagickFalse)
3748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3749 assert(image->cache != (void *) NULL);
3750 assert(filename != (const char *) NULL);
3751 assert(offset != (MagickOffsetType *) NULL);
3752 page_size=GetMagickPageSize();
3753 cache_info=(CacheInfo *) image->cache;
3754 assert(cache_info->signature == MagickSignature);
3755 if (attach != MagickFalse)
3758 Attach existing persistent pixel cache.
3760 if (image->debug != MagickFalse)
3761 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3762 "attach persistent cache");
3763 (void) CopyMagickString(cache_info->cache_filename,filename,
3765 cache_info->type=DiskCache;
3766 cache_info->offset=(*offset);
3767 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3768 return(MagickFalse);
3769 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3772 if ((cache_info->mode != ReadMode) &&
3773 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3774 (cache_info->reference_count == 1))
3776 LockSemaphoreInfo(cache_info->semaphore);
3777 if ((cache_info->mode != ReadMode) &&
3778 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3779 (cache_info->reference_count == 1))
3785 Usurp existing persistent pixel cache.
3787 status=rename_utf8(cache_info->cache_filename,filename);
3790 (void) CopyMagickString(cache_info->cache_filename,filename,
3792 *offset+=cache_info->length+page_size-(cache_info->length %
3794 UnlockSemaphoreInfo(cache_info->semaphore);
3795 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3796 if (image->debug != MagickFalse)
3797 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3798 "Usurp resident persistent cache");
3802 UnlockSemaphoreInfo(cache_info->semaphore);
3805 Clone persistent pixel cache.
3807 clone_image=(*image);
3808 clone_info=(CacheInfo *) clone_image.cache;
3809 image->cache=ClonePixelCache(cache_info);
3810 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3811 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3812 cache_info->type=DiskCache;
3813 cache_info->offset=(*offset);
3814 cache_info=(CacheInfo *) image->cache;
3815 status=OpenPixelCache(image,IOMode,exception);
3816 if (status != MagickFalse)
3817 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3818 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3819 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3828 + 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 %
3832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3834 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3835 % defined by the region rectangle and returns a pointer to the region. This
3836 % region is subsequently transferred from the pixel cache with
3837 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3838 % pixels are transferred, otherwise a NULL is returned.
3840 % The format of the QueueAuthenticPixelCacheNexus() method is:
3842 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3843 % const ssize_t y,const size_t columns,const size_t rows,
3844 % const MagickBooleanType clone,NexusInfo *nexus_info,
3845 % ExceptionInfo *exception)
3847 % A description of each parameter follows:
3849 % o image: the image.
3851 % o x,y,columns,rows: These values define the perimeter of a region of
3854 % o nexus_info: the cache nexus to set.
3856 % o clone: clone the pixel cache.
3858 % o exception: return any errors or warnings in this structure.
3861 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3862 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3863 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3881 Validate pixel cache geometry.
3883 assert(image != (const Image *) NULL);
3884 assert(image->signature == MagickSignature);
3885 assert(image->cache != (Cache) NULL);
3886 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3887 if (cache_info == (Cache) NULL)
3888 return((Quantum *) NULL);
3889 assert(cache_info->signature == MagickSignature);
3890 if ((cache_info->columns == 0) && (cache_info->rows == 0))
3892 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3893 "NoPixelsDefinedInCache","`%s'",image->filename);
3894 return((Quantum *) NULL);
3896 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3897 (y >= (ssize_t) cache_info->rows))
3899 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3900 "PixelsAreNotAuthentic","`%s'",image->filename);
3901 return((Quantum *) NULL);
3903 offset=(MagickOffsetType) y*cache_info->columns+x;
3905 return((Quantum *) NULL);
3906 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3907 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3908 if ((MagickSizeType) offset >= number_pixels)
3909 return((Quantum *) NULL);
3915 region.width=columns;
3917 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3927 + 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 %
3931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3933 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3934 % defined by the region rectangle and returns a pointer to the region. This
3935 % region is subsequently transferred from the pixel cache with
3936 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3937 % pixels are transferred, otherwise a NULL is returned.
3939 % The format of the QueueAuthenticPixelsCache() method is:
3941 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3942 % const ssize_t y,const size_t columns,const size_t rows,
3943 % ExceptionInfo *exception)
3945 % A description of each parameter follows:
3947 % o image: the image.
3949 % o x,y,columns,rows: These values define the perimeter of a region of
3952 % o exception: return any errors or warnings in this structure.
3955 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3956 const ssize_t y,const size_t columns,const size_t rows,
3957 ExceptionInfo *exception)
3963 id = GetOpenMPThreadId();
3968 assert(image != (const Image *) NULL);
3969 assert(image->signature == MagickSignature);
3970 assert(image->cache != (Cache) NULL);
3971 cache_info=(CacheInfo *) image->cache;
3972 assert(cache_info->signature == MagickSignature);
3973 assert(id < (int) cache_info->number_threads);
3974 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3975 cache_info->nexus_info[id],exception);
3980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3984 % Q u e u e A u t h e n t i c P i x e l s %
3988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3990 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3991 % successfully initialized a pointer to a Quantum array representing the
3992 % region is returned, otherwise NULL is returned. The returned pointer may
3993 % point to a temporary working buffer for the pixels or it may point to the
3994 % final location of the pixels in memory.
3996 % Write-only access means that any existing pixel values corresponding to
3997 % the region are ignored. This is useful if the initial image is being
3998 % created from scratch, or if the existing pixel values are to be
3999 % completely replaced without need to refer to their pre-existing values.
4000 % The application is free to read and write the pixel buffer returned by
4001 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4002 % initialize the pixel array values. Initializing pixel array values is the
4003 % application's responsibility.
4005 % Performance is maximized if the selected region is part of one row, or
4006 % one or more full rows, since then there is opportunity to access the
4007 % pixels in-place (without a copy) if the image is in memory, or in a
4008 % memory-mapped file. The returned pointer must *never* be deallocated
4011 % Pixels accessed via the returned pointer represent a simple array of type
4012 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4013 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4014 % obtain the meta-content (of type void) corresponding to the region.
4015 % Once the Quantum (and/or Quantum) array has been updated, the
4016 % changes must be saved back to the underlying image using
4017 % SyncAuthenticPixels() or they may be lost.
4019 % The format of the QueueAuthenticPixels() method is:
4021 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4022 % const ssize_t y,const size_t columns,const size_t rows,
4023 % ExceptionInfo *exception)
4025 % A description of each parameter follows:
4027 % o image: the image.
4029 % o x,y,columns,rows: These values define the perimeter of a region of
4032 % o exception: return any errors or warnings in this structure.
4035 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4036 const ssize_t y,const size_t columns,const size_t rows,
4037 ExceptionInfo *exception)
4043 id = GetOpenMPThreadId();
4048 assert(image != (Image *) NULL);
4049 assert(image->signature == MagickSignature);
4050 assert(image->cache != (Cache) NULL);
4051 cache_info=(CacheInfo *) image->cache;
4052 assert(cache_info->signature == MagickSignature);
4053 if (cache_info->methods.queue_authentic_pixels_handler !=
4054 (QueueAuthenticPixelsHandler) NULL)
4056 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4060 assert(id < (int) cache_info->number_threads);
4061 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4062 cache_info->nexus_info[id],exception);
4067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4071 + 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 %
4075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4077 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4080 % The format of the ReadPixelCacheMetacontent() method is:
4082 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4083 % NexusInfo *nexus_info,ExceptionInfo *exception)
4085 % A description of each parameter follows:
4087 % o cache_info: the pixel cache.
4089 % o nexus_info: the cache nexus to read the metacontent.
4091 % o exception: return any errors or warnings in this structure.
4095 static inline MagickOffsetType ReadPixelCacheRegion(
4096 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4097 const MagickSizeType length,unsigned char *restrict buffer)
4099 register MagickOffsetType
4105 #if !defined(MAGICKCORE_HAVE_PREAD)
4106 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4107 return((MagickOffsetType) -1);
4110 for (i=0; i < (MagickOffsetType) length; i+=count)
4112 #if !defined(MAGICKCORE_HAVE_PREAD)
4113 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4114 (MagickSizeType) SSIZE_MAX));
4116 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4117 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4129 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4130 NexusInfo *nexus_info,ExceptionInfo *exception)
4146 register unsigned char
4149 if (cache_info->metacontent_extent == 0)
4150 return(MagickFalse);
4151 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4153 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4154 nexus_info->region.x;
4155 length=(MagickSizeType) nexus_info->region.width*
4156 cache_info->metacontent_extent;
4157 extent=length*nexus_info->region.height;
4158 region=nexus_info->region;
4160 q=(unsigned char *) nexus_info->metacontent;
4161 switch (cache_info->type)
4166 register unsigned char
4170 Read meta-content from memory.
4172 if ((cache_info->columns == nexus_info->region.width) &&
4173 (extent == (MagickSizeType) ((size_t) extent)))
4178 p=(unsigned char *) cache_info->metacontent+offset*
4179 cache_info->metacontent_extent;
4180 for (y=0; y < (ssize_t) region.height; y++)
4182 (void) memcpy(q,p,(size_t) length);
4183 p+=cache_info->metacontent_extent*cache_info->columns;
4184 q+=cache_info->metacontent_extent*nexus_info->region.width;
4191 Read meta content from disk.
4193 LockSemaphoreInfo(cache_info->file_semaphore);
4194 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4196 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4197 cache_info->cache_filename);
4198 UnlockSemaphoreInfo(cache_info->file_semaphore);
4199 return(MagickFalse);
4201 if ((cache_info->columns == nexus_info->region.width) &&
4202 (extent <= MagickMaxBufferExtent))
4207 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4208 for (y=0; y < (ssize_t) region.height; y++)
4210 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4211 cache_info->number_channels*sizeof(Quantum)+offset*
4212 cache_info->metacontent_extent,length,(unsigned char *) q);
4213 if (count != (MagickOffsetType) length)
4215 offset+=cache_info->columns;
4216 q+=cache_info->metacontent_extent*nexus_info->region.width;
4218 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4219 (void) ClosePixelCacheOnDisk(cache_info);
4220 UnlockSemaphoreInfo(cache_info->file_semaphore);
4223 case DistributedCache:
4226 Read metacontent from distributed cache.
4228 LockSemaphoreInfo(cache_info->file_semaphore);
4230 for (y=0; y < (ssize_t) region.height; y++)
4232 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4233 length,(unsigned char *) q);
4234 if (count != (MagickOffsetType) length)
4236 q+=cache_info->metacontent_extent*nexus_info->region.width;
4239 UnlockSemaphoreInfo(cache_info->file_semaphore);
4245 if (y < (ssize_t) region.height)
4247 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4248 cache_info->cache_filename);
4249 return(MagickFalse);
4251 if ((cache_info->debug != MagickFalse) &&
4252 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4253 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4254 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4255 nexus_info->region.width,(double) nexus_info->region.height,(double)
4256 nexus_info->region.x,(double) nexus_info->region.y);
4261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4265 + R e a d P i x e l C a c h e P i x e l s %
4269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4271 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4274 % The format of the ReadPixelCachePixels() method is:
4276 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4277 % NexusInfo *nexus_info,ExceptionInfo *exception)
4279 % A description of each parameter follows:
4281 % o cache_info: the pixel cache.
4283 % o nexus_info: the cache nexus to read the pixels.
4285 % o exception: return any errors or warnings in this structure.
4288 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4289 NexusInfo *nexus_info,ExceptionInfo *exception)
4308 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4310 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4311 nexus_info->region.x;
4312 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4314 extent=length*nexus_info->region.height;
4315 region=nexus_info->region;
4317 q=nexus_info->pixels;
4318 switch (cache_info->type)
4327 Read pixels from memory.
4329 if ((cache_info->columns == nexus_info->region.width) &&
4330 (extent == (MagickSizeType) ((size_t) extent)))
4335 p=cache_info->pixels+offset*cache_info->number_channels;
4336 for (y=0; y < (ssize_t) region.height; y++)
4338 (void) memcpy(q,p,(size_t) length);
4339 p+=cache_info->number_channels*cache_info->columns;
4340 q+=cache_info->number_channels*nexus_info->region.width;
4347 Read pixels from disk.
4349 LockSemaphoreInfo(cache_info->file_semaphore);
4350 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4352 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4353 cache_info->cache_filename);
4354 UnlockSemaphoreInfo(cache_info->file_semaphore);
4355 return(MagickFalse);
4357 if ((cache_info->columns == nexus_info->region.width) &&
4358 (extent <= MagickMaxBufferExtent))
4363 for (y=0; y < (ssize_t) region.height; y++)
4365 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4366 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4367 if (count != (MagickOffsetType) length)
4369 offset+=cache_info->columns;
4370 q+=cache_info->number_channels*nexus_info->region.width;
4372 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4373 (void) ClosePixelCacheOnDisk(cache_info);
4374 UnlockSemaphoreInfo(cache_info->file_semaphore);
4377 case DistributedCache:
4380 Read pixels from distributed cache.
4382 LockSemaphoreInfo(cache_info->file_semaphore);
4384 for (y=0; y < (ssize_t) region.height; y++)
4386 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4387 length,(unsigned char *) q);
4388 if (count != (MagickOffsetType) length)
4390 q+=cache_info->number_channels*nexus_info->region.width;
4393 UnlockSemaphoreInfo(cache_info->file_semaphore);
4399 if (y < (ssize_t) region.height)
4401 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4402 cache_info->cache_filename);
4403 return(MagickFalse);
4405 if ((cache_info->debug != MagickFalse) &&
4406 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4407 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4408 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4409 nexus_info->region.width,(double) nexus_info->region.height,(double)
4410 nexus_info->region.x,(double) nexus_info->region.y);
4415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4419 + R e f e r e n c e P i x e l C a c h e %
4423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4425 % ReferencePixelCache() increments the reference count associated with the
4426 % pixel cache returning a pointer to the cache.
4428 % The format of the ReferencePixelCache method is:
4430 % Cache ReferencePixelCache(Cache cache_info)
4432 % A description of each parameter follows:
4434 % o cache_info: the pixel cache.
4437 MagickPrivate Cache ReferencePixelCache(Cache cache)
4442 assert(cache != (Cache *) NULL);
4443 cache_info=(CacheInfo *) cache;
4444 assert(cache_info->signature == MagickSignature);
4445 LockSemaphoreInfo(cache_info->semaphore);
4446 cache_info->reference_count++;
4447 UnlockSemaphoreInfo(cache_info->semaphore);
4452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4456 + S e t P i x e l C a c h e M e t h o d s %
4460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4462 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4464 % The format of the SetPixelCacheMethods() method is:
4466 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4468 % A description of each parameter follows:
4470 % o cache: the pixel cache.
4472 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4475 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4480 GetOneAuthenticPixelFromHandler
4481 get_one_authentic_pixel_from_handler;
4483 GetOneVirtualPixelFromHandler
4484 get_one_virtual_pixel_from_handler;
4487 Set cache pixel methods.
4489 assert(cache != (Cache) NULL);
4490 assert(cache_methods != (CacheMethods *) NULL);
4491 cache_info=(CacheInfo *) cache;
4492 assert(cache_info->signature == MagickSignature);
4493 if (cache_info->debug != MagickFalse)
4494 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4495 cache_info->filename);
4496 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4497 cache_info->methods.get_virtual_pixel_handler=
4498 cache_methods->get_virtual_pixel_handler;
4499 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4500 cache_info->methods.destroy_pixel_handler=
4501 cache_methods->destroy_pixel_handler;
4502 if (cache_methods->get_virtual_metacontent_from_handler !=
4503 (GetVirtualMetacontentFromHandler) NULL)
4504 cache_info->methods.get_virtual_metacontent_from_handler=
4505 cache_methods->get_virtual_metacontent_from_handler;
4506 if (cache_methods->get_authentic_pixels_handler !=
4507 (GetAuthenticPixelsHandler) NULL)
4508 cache_info->methods.get_authentic_pixels_handler=
4509 cache_methods->get_authentic_pixels_handler;
4510 if (cache_methods->queue_authentic_pixels_handler !=
4511 (QueueAuthenticPixelsHandler) NULL)
4512 cache_info->methods.queue_authentic_pixels_handler=
4513 cache_methods->queue_authentic_pixels_handler;
4514 if (cache_methods->sync_authentic_pixels_handler !=
4515 (SyncAuthenticPixelsHandler) NULL)
4516 cache_info->methods.sync_authentic_pixels_handler=
4517 cache_methods->sync_authentic_pixels_handler;
4518 if (cache_methods->get_authentic_pixels_from_handler !=
4519 (GetAuthenticPixelsFromHandler) NULL)
4520 cache_info->methods.get_authentic_pixels_from_handler=
4521 cache_methods->get_authentic_pixels_from_handler;
4522 if (cache_methods->get_authentic_metacontent_from_handler !=
4523 (GetAuthenticMetacontentFromHandler) NULL)
4524 cache_info->methods.get_authentic_metacontent_from_handler=
4525 cache_methods->get_authentic_metacontent_from_handler;
4526 get_one_virtual_pixel_from_handler=
4527 cache_info->methods.get_one_virtual_pixel_from_handler;
4528 if (get_one_virtual_pixel_from_handler !=
4529 (GetOneVirtualPixelFromHandler) NULL)
4530 cache_info->methods.get_one_virtual_pixel_from_handler=
4531 cache_methods->get_one_virtual_pixel_from_handler;
4532 get_one_authentic_pixel_from_handler=
4533 cache_methods->get_one_authentic_pixel_from_handler;
4534 if (get_one_authentic_pixel_from_handler !=
4535 (GetOneAuthenticPixelFromHandler) NULL)
4536 cache_info->methods.get_one_authentic_pixel_from_handler=
4537 cache_methods->get_one_authentic_pixel_from_handler;
4541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4545 + S e t P i x e l C a c h e N e x u s P i x e l s %
4549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4551 % SetPixelCacheNexusPixels() defines the region of the cache for the
4552 % specified cache nexus.
4554 % The format of the SetPixelCacheNexusPixels() method is:
4556 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4557 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4558 % ExceptionInfo *exception)
4560 % A description of each parameter follows:
4562 % o cache_info: the pixel cache.
4564 % o mode: ReadMode, WriteMode, or IOMode.
4566 % o region: A pointer to the RectangleInfo structure that defines the
4567 % region of this particular cache nexus.
4569 % o nexus_info: the cache nexus to set.
4571 % o exception: return any errors or warnings in this structure.
4575 static inline MagickBooleanType AcquireCacheNexusPixels(
4576 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4577 ExceptionInfo *exception)
4579 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4580 return(MagickFalse);
4581 nexus_info->mapped=MagickFalse;
4582 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4583 (size_t) nexus_info->length));
4584 if (nexus_info->cache == (Quantum *) NULL)
4586 nexus_info->mapped=MagickTrue;
4587 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4588 nexus_info->length);
4590 if (nexus_info->cache == (Quantum *) NULL)
4592 (void) ThrowMagickException(exception,GetMagickModule(),
4593 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4594 cache_info->filename);
4595 return(MagickFalse);
4600 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4603 if (mode == ReadMode)
4605 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4608 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4611 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4612 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4613 ExceptionInfo *exception)
4622 assert(cache_info != (const CacheInfo *) NULL);
4623 assert(cache_info->signature == MagickSignature);
4624 if (cache_info->type == UndefinedCache)
4625 return((Quantum *) NULL);
4626 nexus_info->region=(*region);
4627 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4633 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4634 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4635 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4636 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4637 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4638 ((nexus_info->region.width == cache_info->columns) ||
4639 ((nexus_info->region.width % cache_info->columns) == 0)))))
4645 Pixels are accessed directly from memory.
4647 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4648 nexus_info->region.x;
4649 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4651 nexus_info->metacontent=(void *) NULL;
4652 if (cache_info->metacontent_extent != 0)
4653 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4654 offset*cache_info->metacontent_extent;
4655 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4656 return(nexus_info->pixels);
4660 Pixels are stored in a cache region until they are synced to the cache.
4662 number_pixels=(MagickSizeType) nexus_info->region.width*
4663 nexus_info->region.height;
4664 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4665 if (cache_info->metacontent_extent != 0)
4666 length+=number_pixels*cache_info->metacontent_extent;
4667 if (nexus_info->cache == (Quantum *) NULL)
4669 nexus_info->length=length;
4670 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4671 if (status == MagickFalse)
4673 nexus_info->length=0;
4674 return((Quantum *) NULL);
4678 if (nexus_info->length != length)
4680 RelinquishCacheNexusPixels(nexus_info);
4681 nexus_info->length=length;
4682 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4683 if (status == MagickFalse)
4685 nexus_info->length=0;
4686 return((Quantum *) NULL);
4689 nexus_info->pixels=nexus_info->cache;
4690 nexus_info->metacontent=(void *) NULL;
4691 if (cache_info->metacontent_extent != 0)
4692 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4693 cache_info->number_channels);
4694 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4695 return(nexus_info->pixels);
4699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703 % 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 %
4707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4709 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4710 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4711 % access that is outside the boundaries of the image cache.
4713 % The format of the SetPixelCacheVirtualMethod() method is:
4715 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4716 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4718 % A description of each parameter follows:
4720 % o image: the image.
4722 % o virtual_pixel_method: choose the type of virtual pixel.
4724 % o exception: return any errors or warnings in this structure.
4728 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4729 ExceptionInfo *exception)
4743 assert(image != (Image *) NULL);
4744 assert(image->signature == MagickSignature);
4745 if (image->debug != MagickFalse)
4746 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4747 assert(image->cache != (Cache) NULL);
4748 cache_info=(CacheInfo *) image->cache;
4749 assert(cache_info->signature == MagickSignature);
4750 image->alpha_trait=BlendPixelTrait;
4752 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4753 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4754 #pragma omp parallel for schedule(static,4) shared(status) \
4755 magick_threads(image,image,1,1)
4757 for (y=0; y < (ssize_t) image->rows; y++)
4765 if (status == MagickFalse)
4767 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4768 if (q == (Quantum *) NULL)
4773 for (x=0; x < (ssize_t) image->columns; x++)
4775 SetPixelAlpha(image,alpha,q);
4776 q+=GetPixelChannels(image);
4778 status=SyncCacheViewAuthenticPixels(image_view,exception);
4780 image_view=DestroyCacheView(image_view);
4784 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4785 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4793 assert(image != (Image *) NULL);
4794 assert(image->signature == MagickSignature);
4795 if (image->debug != MagickFalse)
4796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4797 assert(image->cache != (Cache) NULL);
4798 cache_info=(CacheInfo *) image->cache;
4799 assert(cache_info->signature == MagickSignature);
4800 method=cache_info->virtual_pixel_method;
4801 cache_info->virtual_pixel_method=virtual_pixel_method;
4802 if ((image->columns != 0) && (image->rows != 0))
4803 switch (virtual_pixel_method)
4805 case BackgroundVirtualPixelMethod:
4807 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4808 (image->alpha_trait != BlendPixelTrait))
4809 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4810 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4811 (IsGrayColorspace(image->colorspace) != MagickFalse))
4812 (void) TransformImageColorspace(image,RGBColorspace,exception);
4815 case TransparentVirtualPixelMethod:
4817 if (image->alpha_trait != BlendPixelTrait)
4818 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4832 + 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 %
4836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4838 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4839 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4840 % is synced, otherwise MagickFalse.
4842 % The format of the SyncAuthenticPixelCacheNexus() method is:
4844 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4845 % NexusInfo *nexus_info,ExceptionInfo *exception)
4847 % A description of each parameter follows:
4849 % o image: the image.
4851 % o nexus_info: the cache nexus to sync.
4853 % o exception: return any errors or warnings in this structure.
4856 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4857 NexusInfo *nexus_info,ExceptionInfo *exception)
4866 Transfer pixels to the cache.
4868 assert(image != (Image *) NULL);
4869 assert(image->signature == MagickSignature);
4870 if (image->cache == (Cache) NULL)
4871 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4872 cache_info=(CacheInfo *) image->cache;
4873 assert(cache_info->signature == MagickSignature);
4874 if (cache_info->type == UndefinedCache)
4875 return(MagickFalse);
4876 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4878 assert(cache_info->signature == MagickSignature);
4879 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4880 if ((cache_info->metacontent_extent != 0) &&
4881 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4882 return(MagickFalse);
4887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4891 + S y n c A u t h e n t i c P i x e l C a c h e %
4895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4897 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4898 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4899 % otherwise MagickFalse.
4901 % The format of the SyncAuthenticPixelsCache() method is:
4903 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4904 % ExceptionInfo *exception)
4906 % A description of each parameter follows:
4908 % o image: the image.
4910 % o exception: return any errors or warnings in this structure.
4913 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4914 ExceptionInfo *exception)
4920 id = GetOpenMPThreadId();
4925 assert(image != (Image *) NULL);
4926 assert(image->signature == MagickSignature);
4927 assert(image->cache != (Cache) NULL);
4928 cache_info=(CacheInfo *) image->cache;
4929 assert(cache_info->signature == MagickSignature);
4930 assert(id < (int) cache_info->number_threads);
4931 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4941 % S y n c A u t h e n t i c P i x e l s %
4945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4947 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4948 % The method returns MagickTrue if the pixel region is flushed, otherwise
4951 % The format of the SyncAuthenticPixels() method is:
4953 % MagickBooleanType SyncAuthenticPixels(Image *image,
4954 % ExceptionInfo *exception)
4956 % A description of each parameter follows:
4958 % o image: the image.
4960 % o exception: return any errors or warnings in this structure.
4963 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4964 ExceptionInfo *exception)
4970 id = GetOpenMPThreadId();
4975 assert(image != (Image *) NULL);
4976 assert(image->signature == MagickSignature);
4977 assert(image->cache != (Cache) NULL);
4978 cache_info=(CacheInfo *) image->cache;
4979 assert(cache_info->signature == MagickSignature);
4980 if (cache_info->methods.sync_authentic_pixels_handler !=
4981 (SyncAuthenticPixelsHandler) NULL)
4983 status=cache_info->methods.sync_authentic_pixels_handler(image,
4987 assert(id < (int) cache_info->number_threads);
4988 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4998 + S y n c I m a g e P i x e l C a c h e %
5002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5004 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5005 % The method returns MagickTrue if the pixel region is flushed, otherwise
5008 % The format of the SyncImagePixelCache() method is:
5010 % MagickBooleanType SyncImagePixelCache(Image *image,
5011 % ExceptionInfo *exception)
5013 % A description of each parameter follows:
5015 % o image: the image.
5017 % o exception: return any errors or warnings in this structure.
5020 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5021 ExceptionInfo *exception)
5026 assert(image != (Image *) NULL);
5027 assert(exception != (ExceptionInfo *) NULL);
5028 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5029 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5037 + 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 %
5041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5043 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5044 % of the pixel cache.
5046 % The format of the WritePixelCacheMetacontent() method is:
5048 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5049 % NexusInfo *nexus_info,ExceptionInfo *exception)
5051 % A description of each parameter follows:
5053 % o cache_info: the pixel cache.
5055 % o nexus_info: the cache nexus to write the meta-content.
5057 % o exception: return any errors or warnings in this structure.
5060 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5061 NexusInfo *nexus_info,ExceptionInfo *exception)
5074 register const unsigned char
5080 if (cache_info->metacontent_extent == 0)
5081 return(MagickFalse);
5082 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5084 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5085 nexus_info->region.x;
5086 length=(MagickSizeType) nexus_info->region.width*
5087 cache_info->metacontent_extent;
5088 extent=(MagickSizeType) length*nexus_info->region.height;
5089 region=nexus_info->region;
5091 p=(unsigned char *) nexus_info->metacontent;
5092 switch (cache_info->type)
5097 register unsigned char
5101 Write associated pixels to memory.
5103 if ((cache_info->columns == nexus_info->region.width) &&
5104 (extent == (MagickSizeType) ((size_t) extent)))
5109 q=(unsigned char *) cache_info->metacontent+offset*
5110 cache_info->metacontent_extent;
5111 for (y=0; y < (ssize_t) region.height; y++)
5113 (void) memcpy(q,p,(size_t) length);
5114 p+=nexus_info->region.width*cache_info->metacontent_extent;
5115 q+=cache_info->columns*cache_info->metacontent_extent;
5122 Write associated pixels to disk.
5124 LockSemaphoreInfo(cache_info->file_semaphore);
5125 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5127 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5128 cache_info->cache_filename);
5129 UnlockSemaphoreInfo(cache_info->file_semaphore);
5130 return(MagickFalse);
5132 if ((cache_info->columns == nexus_info->region.width) &&
5133 (extent <= MagickMaxBufferExtent))
5138 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5139 for (y=0; y < (ssize_t) region.height; y++)
5141 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5142 cache_info->number_channels*sizeof(Quantum)+offset*
5143 cache_info->metacontent_extent,length,(const unsigned char *) p);
5144 if (count != (MagickOffsetType) length)
5146 p+=cache_info->metacontent_extent*nexus_info->region.width;
5147 offset+=cache_info->columns;
5149 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5150 (void) ClosePixelCacheOnDisk(cache_info);
5151 UnlockSemaphoreInfo(cache_info->file_semaphore);
5154 case DistributedCache:
5157 Write metacontent to distributed cache.
5159 LockSemaphoreInfo(cache_info->file_semaphore);
5161 for (y=0; y < (ssize_t) region.height; y++)
5163 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5164 length,(const unsigned char *) p);
5165 if (count != (MagickOffsetType) length)
5167 p+=cache_info->metacontent_extent*nexus_info->region.width;
5170 UnlockSemaphoreInfo(cache_info->file_semaphore);
5176 if (y < (ssize_t) region.height)
5178 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5179 cache_info->cache_filename);
5180 return(MagickFalse);
5182 if ((cache_info->debug != MagickFalse) &&
5183 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5184 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5185 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5186 nexus_info->region.width,(double) nexus_info->region.height,(double)
5187 nexus_info->region.x,(double) nexus_info->region.y);
5192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5196 + W r i t e C a c h e P i x e l s %
5200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5202 % WritePixelCachePixels() writes image pixels to the specified region of the
5205 % The format of the WritePixelCachePixels() method is:
5207 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5208 % NexusInfo *nexus_info,ExceptionInfo *exception)
5210 % A description of each parameter follows:
5212 % o cache_info: the pixel cache.
5214 % o nexus_info: the cache nexus to write the pixels.
5216 % o exception: return any errors or warnings in this structure.
5219 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5220 NexusInfo *nexus_info,ExceptionInfo *exception)
5233 register const Quantum
5239 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5241 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5242 nexus_info->region.x;
5243 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5245 extent=length*nexus_info->region.height;
5246 region=nexus_info->region;
5248 p=nexus_info->pixels;
5249 switch (cache_info->type)
5258 Write pixels to memory.
5260 if ((cache_info->columns == nexus_info->region.width) &&
5261 (extent == (MagickSizeType) ((size_t) extent)))
5266 q=cache_info->pixels+offset*cache_info->number_channels;
5267 for (y=0; y < (ssize_t) region.height; y++)
5269 (void) memcpy(q,p,(size_t) length);
5270 p+=cache_info->number_channels*nexus_info->region.width;
5271 q+=cache_info->columns*cache_info->number_channels;
5278 Write pixels to disk.
5280 LockSemaphoreInfo(cache_info->file_semaphore);
5281 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5283 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5284 cache_info->cache_filename);
5285 UnlockSemaphoreInfo(cache_info->file_semaphore);
5286 return(MagickFalse);
5288 if ((cache_info->columns == nexus_info->region.width) &&
5289 (extent <= MagickMaxBufferExtent))
5294 for (y=0; y < (ssize_t) region.height; y++)
5296 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5297 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5299 if (count != (MagickOffsetType) length)
5301 p+=cache_info->number_channels*nexus_info->region.width;
5302 offset+=cache_info->columns;
5304 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5305 (void) ClosePixelCacheOnDisk(cache_info);
5306 UnlockSemaphoreInfo(cache_info->file_semaphore);
5309 case DistributedCache:
5312 Write pixels to distributed cache.
5314 LockSemaphoreInfo(cache_info->file_semaphore);
5316 for (y=0; y < (ssize_t) region.height; y++)
5318 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5319 length,(const unsigned char *) p);
5320 if (count != (MagickOffsetType) length)
5322 p+=cache_info->number_channels*nexus_info->region.width;
5325 UnlockSemaphoreInfo(cache_info->file_semaphore);
5331 if (y < (ssize_t) region.height)
5333 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5334 cache_info->cache_filename);
5335 return(MagickFalse);
5337 if ((cache_info->debug != MagickFalse) &&
5338 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5339 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5340 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5341 nexus_info->region.width,(double) nexus_info->region.height,(double)
5342 nexus_info->region.x,(double) nexus_info->region.y);