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();
583 if (status == MagickFalse)
585 if (y >= (ssize_t) clone_info->rows)
587 region.width=cache_info->columns;
591 (void) SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
593 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
594 if (status == MagickFalse)
596 region.width=clone_info->columns;
598 (void) SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
599 clone_nexus[id],exception);
600 if (optimize != MagickFalse)
601 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
605 register const Quantum
612 Mismatched pixel channel map.
614 p=cache_nexus[id]->pixels;
615 q=clone_nexus[id]->pixels;
616 for (x=0; x < (ssize_t) cache_info->columns; x++)
621 if (x == (ssize_t) clone_info->columns)
623 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
631 channel=clone_info->channel_map[i].channel;
632 traits=cache_info->channel_map[channel].traits;
633 if (traits != UndefinedPixelTrait)
634 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
638 p+=cache_info->number_channels;
641 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
643 if ((cache_info->metacontent_extent != 0) &&
644 (clone_info->metacontent_extent != 0))
649 length=(size_t) MagickMin(cache_info->metacontent_extent,
650 clone_info->metacontent_extent);
651 for (y=0; y < (ssize_t) cache_info->rows; y++)
654 id = GetOpenMPThreadId();
659 if (status == MagickFalse)
661 if (y >= (ssize_t) clone_info->rows)
663 region.width=cache_info->columns;
667 (void) SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
668 cache_nexus[id],exception);
669 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
670 if (status == MagickFalse)
672 region.width=clone_info->columns;
674 (void) SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
675 clone_nexus[id],exception);
676 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
677 length*sizeof(*cache_nexus[id]->metacontent));
678 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
681 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
682 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
683 if (cache_info->debug != MagickFalse)
686 message[MaxTextExtent];
688 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
689 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
690 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
691 (void) LogMagickEvent(CacheEvent,GetMagickModule(),message);
697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
701 + D e s t r o y I m a g e P i x e l C a c h e %
705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
707 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
709 % The format of the DestroyImagePixelCache() method is:
711 % void DestroyImagePixelCache(Image *image)
713 % A description of each parameter follows:
715 % o image: the image.
718 static void DestroyImagePixelCache(Image *image)
720 assert(image != (Image *) NULL);
721 assert(image->signature == MagickSignature);
722 if (image->debug != MagickFalse)
723 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
724 if (image->cache == (void *) NULL)
726 image->cache=DestroyPixelCache(image->cache);
730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
734 + D e s t r o y I m a g e P i x e l s %
738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
740 % DestroyImagePixels() deallocates memory associated with the pixel cache.
742 % The format of the DestroyImagePixels() method is:
744 % void DestroyImagePixels(Image *image)
746 % A description of each parameter follows:
748 % o image: the image.
751 MagickExport void DestroyImagePixels(Image *image)
756 assert(image != (const Image *) NULL);
757 assert(image->signature == MagickSignature);
758 if (image->debug != MagickFalse)
759 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
760 assert(image->cache != (Cache) NULL);
761 cache_info=(CacheInfo *) image->cache;
762 assert(cache_info->signature == MagickSignature);
763 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
765 cache_info->methods.destroy_pixel_handler(image);
768 image->cache=DestroyPixelCache(image->cache);
772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776 + D e s t r o y P i x e l C a c h e %
780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782 % DestroyPixelCache() deallocates memory associated with the pixel cache.
784 % The format of the DestroyPixelCache() method is:
786 % Cache DestroyPixelCache(Cache cache)
788 % A description of each parameter follows:
790 % o cache: the pixel cache.
794 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
800 if (cache_info->file != -1)
802 status=close(cache_info->file);
803 cache_info->file=(-1);
804 RelinquishMagickResource(FileResource,1);
806 return(status == -1 ? MagickFalse : MagickTrue);
809 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
811 switch (cache_info->type)
815 if (cache_info->mapped == MagickFalse)
816 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
819 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
820 (size_t) cache_info->length);
821 RelinquishMagickResource(MemoryResource,cache_info->length);
826 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
828 if (cache_info->mode != ReadMode)
829 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
830 *cache_info->cache_filename='\0';
831 RelinquishMagickResource(MapResource,cache_info->length);
835 if (cache_info->file != -1)
836 (void) ClosePixelCacheOnDisk(cache_info);
837 if (cache_info->mode != ReadMode)
838 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
839 *cache_info->cache_filename='\0';
840 RelinquishMagickResource(DiskResource,cache_info->length);
843 case DistributedCache:
845 *cache_info->cache_filename='\0';
846 (void) RelinquishDistributePixelCache(cache_info->server_info);
852 cache_info->type=UndefinedCache;
853 cache_info->mapped=MagickFalse;
854 cache_info->metacontent=(void *) NULL;
857 MagickPrivate Cache DestroyPixelCache(Cache cache)
862 assert(cache != (Cache) NULL);
863 cache_info=(CacheInfo *) cache;
864 assert(cache_info->signature == MagickSignature);
865 if (cache_info->debug != MagickFalse)
866 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
867 cache_info->filename);
868 LockSemaphoreInfo(cache_info->semaphore);
869 cache_info->reference_count--;
870 if (cache_info->reference_count != 0)
872 UnlockSemaphoreInfo(cache_info->semaphore);
873 return((Cache) NULL);
875 UnlockSemaphoreInfo(cache_info->semaphore);
876 if (cache_info->debug != MagickFalse)
879 message[MaxTextExtent];
881 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
882 cache_info->filename);
883 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
885 RelinquishPixelCachePixels(cache_info);
886 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
887 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
888 if (cache_info->nexus_info != (NexusInfo **) NULL)
889 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
890 cache_info->number_threads);
891 if (cache_info->random_info != (RandomInfo *) NULL)
892 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
893 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
894 DestroySemaphoreInfo(&cache_info->file_semaphore);
895 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
896 DestroySemaphoreInfo(&cache_info->semaphore);
897 cache_info->signature=(~MagickSignature);
898 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908 + D e s t r o y P i x e l C a c h e N e x u s %
912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
914 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
916 % The format of the DestroyPixelCacheNexus() method is:
918 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
919 % const size_t number_threads)
921 % A description of each parameter follows:
923 % o nexus_info: the nexus to destroy.
925 % o number_threads: the number of nexus threads.
929 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
931 if (nexus_info->mapped == MagickFalse)
932 (void) RelinquishAlignedMemory(nexus_info->cache);
934 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
935 nexus_info->cache=(Quantum *) NULL;
936 nexus_info->pixels=(Quantum *) NULL;
937 nexus_info->metacontent=(void *) NULL;
938 nexus_info->length=0;
939 nexus_info->mapped=MagickFalse;
942 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
943 const size_t number_threads)
948 assert(nexus_info != (NexusInfo **) NULL);
949 for (i=0; i < (ssize_t) number_threads; i++)
951 if (nexus_info[i]->cache != (Quantum *) NULL)
952 RelinquishCacheNexusPixels(nexus_info[i]);
953 nexus_info[i]->signature=(~MagickSignature);
955 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
956 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965 % G e t A u t h e n t i c M e t a c o n t e n t %
969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
971 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
972 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
973 % returned if the associated pixels are not available.
975 % The format of the GetAuthenticMetacontent() method is:
977 % void *GetAuthenticMetacontent(const Image *image)
979 % A description of each parameter follows:
981 % o image: the image.
984 MagickExport void *GetAuthenticMetacontent(const Image *image)
990 id = GetOpenMPThreadId();
995 assert(image != (const Image *) NULL);
996 assert(image->signature == MagickSignature);
997 assert(image->cache != (Cache) NULL);
998 cache_info=(CacheInfo *) image->cache;
999 assert(cache_info->signature == MagickSignature);
1000 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1001 (GetAuthenticMetacontentFromHandler) NULL)
1003 metacontent=cache_info->methods.
1004 get_authentic_metacontent_from_handler(image);
1005 return(metacontent);
1007 assert(id < (int) cache_info->number_threads);
1008 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1009 cache_info->nexus_info[id]);
1010 return(metacontent);
1014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 + 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 %
1022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1024 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1025 % with the last call to QueueAuthenticPixelsCache() or
1026 % GetAuthenticPixelsCache().
1028 % The format of the GetAuthenticMetacontentFromCache() method is:
1030 % void *GetAuthenticMetacontentFromCache(const Image *image)
1032 % A description of each parameter follows:
1034 % o image: the image.
1037 static void *GetAuthenticMetacontentFromCache(const Image *image)
1043 id = GetOpenMPThreadId();
1048 assert(image != (const Image *) NULL);
1049 assert(image->signature == MagickSignature);
1050 assert(image->cache != (Cache) NULL);
1051 cache_info=(CacheInfo *) image->cache;
1052 assert(cache_info->signature == MagickSignature);
1053 assert(id < (int) cache_info->number_threads);
1054 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1055 cache_info->nexus_info[id]);
1056 return(metacontent);
1060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1064 + 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 %
1068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1070 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1071 % disk pixel cache as defined by the geometry parameters. A pointer to the
1072 % pixels is returned if the pixels are transferred, otherwise a NULL is
1075 % The format of the GetAuthenticPixelCacheNexus() method is:
1077 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1078 % const ssize_t y,const size_t columns,const size_t rows,
1079 % NexusInfo *nexus_info,ExceptionInfo *exception)
1081 % A description of each parameter follows:
1083 % o image: the image.
1085 % o x,y,columns,rows: These values define the perimeter of a region of
1088 % o nexus_info: the cache nexus to return.
1090 % o exception: return any errors or warnings in this structure.
1094 static inline MagickBooleanType IsPixelAuthentic(
1095 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1103 if (cache_info->type == PingCache)
1105 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1106 nexus_info->region.x;
1107 status=nexus_info->pixels == (cache_info->pixels+offset*
1108 cache_info->number_channels) ? MagickTrue : MagickFalse;
1112 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1113 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1114 NexusInfo *nexus_info,ExceptionInfo *exception)
1123 Transfer pixels from the cache.
1125 assert(image != (Image *) NULL);
1126 assert(image->signature == MagickSignature);
1127 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1129 if (q == (Quantum *) NULL)
1130 return((Quantum *) NULL);
1131 cache_info=(CacheInfo *) image->cache;
1132 assert(cache_info->signature == MagickSignature);
1133 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1135 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1136 return((Quantum *) NULL);
1137 if (cache_info->metacontent_extent != 0)
1138 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1139 return((Quantum *) NULL);
1144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1148 + 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 %
1152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1154 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1155 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1157 % The format of the GetAuthenticPixelsFromCache() method is:
1159 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1161 % A description of each parameter follows:
1163 % o image: the image.
1166 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1172 id = GetOpenMPThreadId();
1174 assert(image != (const Image *) NULL);
1175 assert(image->signature == MagickSignature);
1176 assert(image->cache != (Cache) NULL);
1177 cache_info=(CacheInfo *) image->cache;
1178 assert(cache_info->signature == MagickSignature);
1179 assert(id < (int) cache_info->number_threads);
1180 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1188 % G e t A u t h e n t i c P i x e l Q u e u e %
1192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1194 % GetAuthenticPixelQueue() returns the authentic pixels associated
1195 % corresponding with the last call to QueueAuthenticPixels() or
1196 % GetAuthenticPixels().
1198 % The format of the GetAuthenticPixelQueue() method is:
1200 % Quantum *GetAuthenticPixelQueue(const Image image)
1202 % A description of each parameter follows:
1204 % o image: the image.
1207 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1213 id = GetOpenMPThreadId();
1215 assert(image != (const Image *) NULL);
1216 assert(image->signature == MagickSignature);
1217 assert(image->cache != (Cache) NULL);
1218 cache_info=(CacheInfo *) image->cache;
1219 assert(cache_info->signature == MagickSignature);
1220 if (cache_info->methods.get_authentic_pixels_from_handler !=
1221 (GetAuthenticPixelsFromHandler) NULL)
1222 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1223 assert(id < (int) cache_info->number_threads);
1224 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1232 % G e t A u t h e n t i c P i x e l s %
1235 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1237 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1238 % region is successfully accessed, a pointer to a Quantum array
1239 % representing the region is returned, otherwise NULL is returned.
1241 % The returned pointer may point to a temporary working copy of the pixels
1242 % or it may point to the original pixels in memory. Performance is maximized
1243 % if the selected region is part of one row, or one or more full rows, since
1244 % then there is opportunity to access the pixels in-place (without a copy)
1245 % if the image is in memory, or in a memory-mapped file. The returned pointer
1246 % must *never* be deallocated by the user.
1248 % Pixels accessed via the returned pointer represent a simple array of type
1249 % Quantum. If the image has corresponding metacontent,call
1250 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1251 % meta-content corresponding to the region. Once the Quantum array has
1252 % been updated, the changes must be saved back to the underlying image using
1253 % SyncAuthenticPixels() or they may be lost.
1255 % The format of the GetAuthenticPixels() method is:
1257 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1258 % const ssize_t y,const size_t columns,const size_t rows,
1259 % ExceptionInfo *exception)
1261 % A description of each parameter follows:
1263 % o image: the image.
1265 % o x,y,columns,rows: These values define the perimeter of a region of
1268 % o exception: return any errors or warnings in this structure.
1271 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1272 const ssize_t y,const size_t columns,const size_t rows,
1273 ExceptionInfo *exception)
1279 id = GetOpenMPThreadId();
1284 assert(image != (Image *) NULL);
1285 assert(image->signature == MagickSignature);
1286 assert(image->cache != (Cache) NULL);
1287 cache_info=(CacheInfo *) image->cache;
1288 assert(cache_info->signature == MagickSignature);
1289 if (cache_info->methods.get_authentic_pixels_handler !=
1290 (GetAuthenticPixelsHandler) NULL)
1292 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1296 assert(id < (int) cache_info->number_threads);
1297 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1298 cache_info->nexus_info[id],exception);
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307 + G e t A u t h e n t i c P i x e l s C a c h e %
1311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1314 % as defined by the geometry parameters. A pointer to the pixels is returned
1315 % if the pixels are transferred, otherwise a NULL is returned.
1317 % The format of the GetAuthenticPixelsCache() method is:
1319 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1320 % const ssize_t y,const size_t columns,const size_t rows,
1321 % ExceptionInfo *exception)
1323 % A description of each parameter follows:
1325 % o image: the image.
1327 % o x,y,columns,rows: These values define the perimeter of a region of
1330 % o exception: return any errors or warnings in this structure.
1333 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1334 const ssize_t y,const size_t columns,const size_t rows,
1335 ExceptionInfo *exception)
1341 id = GetOpenMPThreadId();
1346 assert(image != (const Image *) NULL);
1347 assert(image->signature == MagickSignature);
1348 assert(image->cache != (Cache) NULL);
1349 cache_info=(CacheInfo *) image->cache;
1350 if (cache_info == (Cache) NULL)
1351 return((Quantum *) NULL);
1352 assert(cache_info->signature == MagickSignature);
1353 assert(id < (int) cache_info->number_threads);
1354 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1355 cache_info->nexus_info[id],exception);
1360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364 + G e t I m a g e E x t e n t %
1368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370 % GetImageExtent() returns the extent of the pixels associated corresponding
1371 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1373 % The format of the GetImageExtent() method is:
1375 % MagickSizeType GetImageExtent(const Image *image)
1377 % A description of each parameter follows:
1379 % o image: the image.
1382 MagickExport MagickSizeType GetImageExtent(const Image *image)
1388 id = GetOpenMPThreadId();
1390 assert(image != (Image *) NULL);
1391 assert(image->signature == MagickSignature);
1392 if (image->debug != MagickFalse)
1393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1394 assert(image->cache != (Cache) NULL);
1395 cache_info=(CacheInfo *) image->cache;
1396 assert(cache_info->signature == MagickSignature);
1397 assert(id < (int) cache_info->number_threads);
1398 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406 + G e t I m a g e P i x e l C a c h e %
1410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412 % GetImagePixelCache() ensures that there is only a single reference to the
1413 % pixel cache to be modified, updating the provided cache pointer to point to
1414 % a clone of the original pixel cache if necessary.
1416 % The format of the GetImagePixelCache method is:
1418 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1419 % ExceptionInfo *exception)
1421 % A description of each parameter follows:
1423 % o image: the image.
1425 % o clone: any value other than MagickFalse clones the cache pixels.
1427 % o exception: return any errors or warnings in this structure.
1431 static inline MagickBooleanType ValidatePixelCacheMorphology(
1432 const Image *restrict image)
1435 *restrict cache_info;
1437 const PixelChannelMap
1442 Does the image match the pixel cache morphology?
1444 cache_info=(CacheInfo *) image->cache;
1445 p=image->channel_map;
1446 q=cache_info->channel_map;
1447 if ((image->storage_class != cache_info->storage_class) ||
1448 (image->colorspace != cache_info->colorspace) ||
1449 (image->alpha_trait != cache_info->alpha_trait) ||
1450 (image->mask != cache_info->mask) ||
1451 (image->columns != cache_info->columns) ||
1452 (image->rows != cache_info->rows) ||
1453 (image->number_channels != cache_info->number_channels) ||
1454 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1455 (image->metacontent_extent != cache_info->metacontent_extent) ||
1456 (cache_info->nexus_info == (NexusInfo **) NULL))
1457 return(MagickFalse);
1461 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1462 ExceptionInfo *exception)
1471 static MagickSizeType
1477 cache_timestamp = 0;
1480 LockSemaphoreInfo(image->semaphore);
1481 if (cpu_throttle == 0)
1487 Set CPU throttle in milleseconds.
1489 cpu_throttle=MagickResourceInfinity;
1490 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1491 if (limit == (char *) NULL)
1492 limit=GetPolicyValue("throttle");
1493 if (limit != (char *) NULL)
1495 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1496 limit=DestroyString(limit);
1499 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1500 MagickDelay(cpu_throttle);
1501 if (time_limit == 0)
1504 Set the expire time in seconds.
1506 time_limit=GetMagickResourceLimit(TimeResource);
1507 cache_timestamp=time((time_t *) NULL);
1509 if ((time_limit != MagickResourceInfinity) &&
1510 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1511 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1512 assert(image->cache != (Cache) NULL);
1513 cache_info=(CacheInfo *) image->cache;
1514 destroy=MagickFalse;
1515 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1517 LockSemaphoreInfo(cache_info->semaphore);
1518 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1529 clone_image=(*image);
1530 clone_image.semaphore=AllocateSemaphoreInfo();
1531 clone_image.reference_count=1;
1532 clone_image.cache=ClonePixelCache(cache_info);
1533 clone_info=(CacheInfo *) clone_image.cache;
1534 status=OpenPixelCache(&clone_image,IOMode,exception);
1535 if (status != MagickFalse)
1537 if (clone != MagickFalse)
1538 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
1539 if (status != MagickFalse)
1541 if (cache_info->reference_count == 1)
1542 cache_info->nexus_info=(NexusInfo **) NULL;
1544 image->cache=clone_image.cache;
1547 DestroySemaphoreInfo(&clone_image.semaphore);
1549 UnlockSemaphoreInfo(cache_info->semaphore);
1551 if (destroy != MagickFalse)
1552 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1553 if (status != MagickFalse)
1556 Ensure the image matches the pixel cache morphology.
1558 image->taint=MagickTrue;
1559 image->type=UndefinedType;
1560 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1562 status=OpenPixelCache(image,IOMode,exception);
1563 cache_info=(CacheInfo *) image->cache;
1564 if (cache_info->type == DiskCache)
1565 (void) ClosePixelCacheOnDisk(cache_info);
1568 UnlockSemaphoreInfo(image->semaphore);
1569 if (status == MagickFalse)
1570 return((Cache) NULL);
1571 return(image->cache);
1575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579 + G e t I m a g e P i x e l C a c h e T y p e %
1583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1586 % DiskCache, MemoryCache, MapCache, or PingCache.
1588 % The format of the GetImagePixelCacheType() method is:
1590 % CacheType GetImagePixelCacheType(const Image *image)
1592 % A description of each parameter follows:
1594 % o image: the image.
1597 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1602 assert(image != (Image *) NULL);
1603 assert(image->signature == MagickSignature);
1604 assert(image->cache != (Cache) NULL);
1605 cache_info=(CacheInfo *) image->cache;
1606 assert(cache_info->signature == MagickSignature);
1607 return(cache_info->type);
1611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615 % G e t O n e A u t h e n t i c P i x e l %
1619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1622 % location. The image background color is returned if an error occurs.
1624 % The format of the GetOneAuthenticPixel() method is:
1626 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1627 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1629 % A description of each parameter follows:
1631 % o image: the image.
1633 % o x,y: These values define the location of the pixel to return.
1635 % o pixel: return a pixel at the specified (x,y) location.
1637 % o exception: return any errors or warnings in this structure.
1640 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1641 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1652 assert(image != (Image *) NULL);
1653 assert(image->signature == MagickSignature);
1654 assert(image->cache != (Cache) NULL);
1655 cache_info=(CacheInfo *) image->cache;
1656 assert(cache_info->signature == MagickSignature);
1657 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1658 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1659 (GetOneAuthenticPixelFromHandler) NULL)
1660 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1662 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1663 if (q == (Quantum *) NULL)
1665 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1666 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1667 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1668 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1669 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1670 return(MagickFalse);
1672 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1677 channel=GetPixelChannelChannel(image,i);
1678 pixel[channel]=q[i];
1684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688 + 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 %
1692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1694 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1695 % location. The image background color is returned if an error occurs.
1697 % The format of the GetOneAuthenticPixelFromCache() method is:
1699 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1700 % const ssize_t x,const ssize_t y,Quantum *pixel,
1701 % ExceptionInfo *exception)
1703 % A description of each parameter follows:
1705 % o image: the image.
1707 % o x,y: These values define the location of the pixel to return.
1709 % o pixel: return a pixel at the specified (x,y) location.
1711 % o exception: return any errors or warnings in this structure.
1714 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1715 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1721 id = GetOpenMPThreadId();
1729 assert(image != (const Image *) NULL);
1730 assert(image->signature == MagickSignature);
1731 assert(image->cache != (Cache) NULL);
1732 cache_info=(CacheInfo *) image->cache;
1733 assert(cache_info->signature == MagickSignature);
1734 assert(id < (int) cache_info->number_threads);
1735 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1736 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1738 if (q == (Quantum *) NULL)
1740 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1741 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1742 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1743 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1744 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1745 return(MagickFalse);
1747 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1752 channel=GetPixelChannelChannel(image,i);
1753 pixel[channel]=q[i];
1759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763 % G e t O n e V i r t u a l P i x e l %
1767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1770 % (x,y) location. The image background color is returned if an error occurs.
1771 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1773 % The format of the GetOneVirtualPixel() method is:
1775 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1776 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1778 % A description of each parameter follows:
1780 % o image: the image.
1782 % o x,y: These values define the location of the pixel to return.
1784 % o pixel: return a pixel at the specified (x,y) location.
1786 % o exception: return any errors or warnings in this structure.
1789 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1790 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1796 id = GetOpenMPThreadId();
1804 assert(image != (const Image *) NULL);
1805 assert(image->signature == MagickSignature);
1806 assert(image->cache != (Cache) NULL);
1807 cache_info=(CacheInfo *) image->cache;
1808 assert(cache_info->signature == MagickSignature);
1809 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1810 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1811 (GetOneVirtualPixelFromHandler) NULL)
1812 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1813 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1814 assert(id < (int) cache_info->number_threads);
1815 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1816 1UL,1UL,cache_info->nexus_info[id],exception);
1817 if (p == (const Quantum *) NULL)
1819 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1820 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1821 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1822 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1823 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1824 return(MagickFalse);
1826 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1831 channel=GetPixelChannelChannel(image,i);
1832 pixel[channel]=p[i];
1838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1842 + 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 %
1846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1848 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1849 % specified (x,y) location. The image background color is returned if an
1852 % The format of the GetOneVirtualPixelFromCache() method is:
1854 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1855 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1856 % Quantum *pixel,ExceptionInfo *exception)
1858 % A description of each parameter follows:
1860 % o image: the image.
1862 % o virtual_pixel_method: the virtual pixel method.
1864 % o x,y: These values define the location of the pixel to return.
1866 % o pixel: return a pixel at the specified (x,y) location.
1868 % o exception: return any errors or warnings in this structure.
1871 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1872 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1873 Quantum *pixel,ExceptionInfo *exception)
1879 id = GetOpenMPThreadId();
1887 assert(image != (const Image *) NULL);
1888 assert(image->signature == MagickSignature);
1889 assert(image->cache != (Cache) NULL);
1890 cache_info=(CacheInfo *) image->cache;
1891 assert(cache_info->signature == MagickSignature);
1892 assert(id < (int) cache_info->number_threads);
1893 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1894 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1895 cache_info->nexus_info[id],exception);
1896 if (p == (const Quantum *) NULL)
1898 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1899 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1900 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1901 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1902 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1903 return(MagickFalse);
1905 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1910 channel=GetPixelChannelChannel(image,i);
1911 pixel[channel]=p[i];
1917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1921 % G e t O n e V i r t u a l P i x e l I n f o %
1925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1927 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1928 % location. The image background color is returned if an error occurs. If
1929 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1931 % The format of the GetOneVirtualPixelInfo() method is:
1933 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1934 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1935 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1937 % A description of each parameter follows:
1939 % o image: the image.
1941 % o virtual_pixel_method: the virtual pixel method.
1943 % o x,y: these values define the location of the pixel to return.
1945 % o pixel: return a pixel at the specified (x,y) location.
1947 % o exception: return any errors or warnings in this structure.
1950 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1951 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1952 PixelInfo *pixel,ExceptionInfo *exception)
1958 id = GetOpenMPThreadId();
1960 register const Quantum
1963 assert(image != (const Image *) NULL);
1964 assert(image->signature == MagickSignature);
1965 assert(image->cache != (Cache) NULL);
1966 cache_info=(CacheInfo *) image->cache;
1967 assert(cache_info->signature == MagickSignature);
1968 assert(id < (int) cache_info->number_threads);
1969 GetPixelInfo(image,pixel);
1970 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1971 cache_info->nexus_info[id],exception);
1972 if (p == (const Quantum *) NULL)
1973 return(MagickFalse);
1974 GetPixelInfoPixel(image,p,pixel);
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983 + G e t P i x e l C a c h e C o l o r s p a c e %
1987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1991 % The format of the GetPixelCacheColorspace() method is:
1993 % Colorspace GetPixelCacheColorspace(Cache cache)
1995 % A description of each parameter follows:
1997 % o cache: the pixel cache.
2000 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2005 assert(cache != (Cache) NULL);
2006 cache_info=(CacheInfo *) cache;
2007 assert(cache_info->signature == MagickSignature);
2008 if (cache_info->debug != MagickFalse)
2009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2010 cache_info->filename);
2011 return(cache_info->colorspace);
2015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019 + G e t P i x e l C a c h e M e t h o d s %
2023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2025 % GetPixelCacheMethods() initializes the CacheMethods structure.
2027 % The format of the GetPixelCacheMethods() method is:
2029 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2031 % A description of each parameter follows:
2033 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2036 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2038 assert(cache_methods != (CacheMethods *) NULL);
2039 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2040 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2041 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2042 cache_methods->get_virtual_metacontent_from_handler=
2043 GetVirtualMetacontentFromCache;
2044 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2045 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2046 cache_methods->get_authentic_metacontent_from_handler=
2047 GetAuthenticMetacontentFromCache;
2048 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2049 cache_methods->get_one_authentic_pixel_from_handler=
2050 GetOneAuthenticPixelFromCache;
2051 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2052 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2053 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2061 + G e t P i x e l C a c h e N e x u s E x t e n t %
2065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2067 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2068 % corresponding with the last call to SetPixelCacheNexusPixels() or
2069 % GetPixelCacheNexusPixels().
2071 % The format of the GetPixelCacheNexusExtent() method is:
2073 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2074 % NexusInfo *nexus_info)
2076 % A description of each parameter follows:
2078 % o nexus_info: the nexus info.
2081 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2082 NexusInfo *nexus_info)
2090 assert(cache != NULL);
2091 cache_info=(CacheInfo *) cache;
2092 assert(cache_info->signature == MagickSignature);
2093 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2095 return((MagickSizeType) cache_info->columns*cache_info->rows);
2100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2104 + 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 %
2108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2113 % The format of the GetPixelCacheNexusMetacontent() method is:
2115 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2116 % NexusInfo *nexus_info)
2118 % A description of each parameter follows:
2120 % o cache: the pixel cache.
2122 % o nexus_info: the cache nexus to return the meta-content.
2125 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2126 NexusInfo *nexus_info)
2131 assert(cache != NULL);
2132 cache_info=(CacheInfo *) cache;
2133 assert(cache_info->signature == MagickSignature);
2134 if (cache_info->storage_class == UndefinedClass)
2135 return((void *) NULL);
2136 return(nexus_info->metacontent);
2140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2144 + G e t P i x e l C a c h e N e x u s P i x e l s %
2148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2150 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2153 % The format of the GetPixelCacheNexusPixels() method is:
2155 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2156 % NexusInfo *nexus_info)
2158 % A description of each parameter follows:
2160 % o cache: the pixel cache.
2162 % o nexus_info: the cache nexus to return the pixels.
2165 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2166 NexusInfo *nexus_info)
2171 assert(cache != NULL);
2172 cache_info=(CacheInfo *) cache;
2173 assert(cache_info->signature == MagickSignature);
2174 if (cache_info->storage_class == UndefinedClass)
2175 return((Quantum *) NULL);
2176 return(nexus_info->pixels);
2180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184 + G e t P i x e l C a c h e P i x e l s %
2188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2190 % GetPixelCachePixels() returns the pixels associated with the specified image.
2192 % The format of the GetPixelCachePixels() method is:
2194 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2195 % ExceptionInfo *exception)
2197 % A description of each parameter follows:
2199 % o image: the image.
2201 % o length: the pixel cache length.
2203 % o exception: return any errors or warnings in this structure.
2206 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2207 ExceptionInfo *exception)
2212 assert(image != (const Image *) NULL);
2213 assert(image->signature == MagickSignature);
2214 assert(image->cache != (Cache) NULL);
2215 assert(length != (MagickSizeType *) NULL);
2216 assert(exception != (ExceptionInfo *) NULL);
2217 assert(exception->signature == MagickSignature);
2218 cache_info=(CacheInfo *) image->cache;
2219 assert(cache_info->signature == MagickSignature);
2221 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2222 return((void *) NULL);
2223 *length=cache_info->length;
2224 return((void *) cache_info->pixels);
2228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2232 + 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 %
2236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2238 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2240 % The format of the GetPixelCacheStorageClass() method is:
2242 % ClassType GetPixelCacheStorageClass(Cache cache)
2244 % A description of each parameter follows:
2246 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2248 % o cache: the pixel cache.
2251 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2256 assert(cache != (Cache) NULL);
2257 cache_info=(CacheInfo *) cache;
2258 assert(cache_info->signature == MagickSignature);
2259 if (cache_info->debug != MagickFalse)
2260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2261 cache_info->filename);
2262 return(cache_info->storage_class);
2266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270 + G e t P i x e l C a c h e T i l e S i z e %
2274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2276 % GetPixelCacheTileSize() returns the pixel cache tile size.
2278 % The format of the GetPixelCacheTileSize() method is:
2280 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2283 % A description of each parameter follows:
2285 % o image: the image.
2287 % o width: the optimize cache tile width in pixels.
2289 % o height: the optimize cache tile height in pixels.
2292 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2298 assert(image != (Image *) NULL);
2299 assert(image->signature == MagickSignature);
2300 if (image->debug != MagickFalse)
2301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2302 cache_info=(CacheInfo *) image->cache;
2303 assert(cache_info->signature == MagickSignature);
2304 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2305 if (GetImagePixelCacheType(image) == DiskCache)
2306 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315 + 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 %
2319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2322 % pixel cache. A virtual pixel is any pixel access that is outside the
2323 % boundaries of the image cache.
2325 % The format of the GetPixelCacheVirtualMethod() method is:
2327 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2329 % A description of each parameter follows:
2331 % o image: the image.
2334 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2339 assert(image != (Image *) NULL);
2340 assert(image->signature == MagickSignature);
2341 assert(image->cache != (Cache) NULL);
2342 cache_info=(CacheInfo *) image->cache;
2343 assert(cache_info->signature == MagickSignature);
2344 return(cache_info->virtual_pixel_method);
2348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352 + 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 %
2356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2359 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2361 % The format of the GetVirtualMetacontentFromCache() method is:
2363 % void *GetVirtualMetacontentFromCache(const Image *image)
2365 % A description of each parameter follows:
2367 % o image: the image.
2370 static const void *GetVirtualMetacontentFromCache(const Image *image)
2376 id = GetOpenMPThreadId();
2381 assert(image != (const Image *) NULL);
2382 assert(image->signature == MagickSignature);
2383 assert(image->cache != (Cache) NULL);
2384 cache_info=(CacheInfo *) image->cache;
2385 assert(cache_info->signature == MagickSignature);
2386 assert(id < (int) cache_info->number_threads);
2387 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2388 cache_info->nexus_info[id]);
2389 return(metacontent);
2393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2397 + 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 %
2401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2406 % The format of the GetVirtualMetacontentFromNexus() method is:
2408 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2409 % NexusInfo *nexus_info)
2411 % A description of each parameter follows:
2413 % o cache: the pixel cache.
2415 % o nexus_info: the cache nexus to return the meta-content.
2418 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2419 NexusInfo *nexus_info)
2424 assert(cache != (Cache) NULL);
2425 cache_info=(CacheInfo *) cache;
2426 assert(cache_info->signature == MagickSignature);
2427 if (cache_info->storage_class == UndefinedClass)
2428 return((void *) NULL);
2429 return(nexus_info->metacontent);
2433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2437 % G e t V i r t u a l M e t a c o n t e n t %
2441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2443 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2444 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2445 % returned if the meta-content are not available.
2447 % The format of the GetVirtualMetacontent() method is:
2449 % const void *GetVirtualMetacontent(const Image *image)
2451 % A description of each parameter follows:
2453 % o image: the image.
2456 MagickExport const void *GetVirtualMetacontent(const Image *image)
2462 id = GetOpenMPThreadId();
2467 assert(image != (const Image *) NULL);
2468 assert(image->signature == MagickSignature);
2469 assert(image->cache != (Cache) NULL);
2470 cache_info=(CacheInfo *) image->cache;
2471 assert(cache_info->signature == MagickSignature);
2472 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2473 if (metacontent != (void *) NULL)
2474 return(metacontent);
2475 assert(id < (int) cache_info->number_threads);
2476 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2477 cache_info->nexus_info[id]);
2478 return(metacontent);
2482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2486 + 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 %
2490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2492 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2493 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2494 % is returned if the pixels are transferred, otherwise a NULL is returned.
2496 % The format of the GetVirtualPixelsFromNexus() method is:
2498 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2499 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2500 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2501 % ExceptionInfo *exception)
2503 % A description of each parameter follows:
2505 % o image: the image.
2507 % o virtual_pixel_method: the virtual pixel method.
2509 % o x,y,columns,rows: These values define the perimeter of a region of
2512 % o nexus_info: the cache nexus to acquire.
2514 % o exception: return any errors or warnings in this structure.
2521 0, 48, 12, 60, 3, 51, 15, 63,
2522 32, 16, 44, 28, 35, 19, 47, 31,
2523 8, 56, 4, 52, 11, 59, 7, 55,
2524 40, 24, 36, 20, 43, 27, 39, 23,
2525 2, 50, 14, 62, 1, 49, 13, 61,
2526 34, 18, 46, 30, 33, 17, 45, 29,
2527 10, 58, 6, 54, 9, 57, 5, 53,
2528 42, 26, 38, 22, 41, 25, 37, 21
2531 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2536 index=x+DitherMatrix[x & 0x07]-32L;
2539 if (index >= (ssize_t) columns)
2540 return((ssize_t) columns-1L);
2544 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2549 index=y+DitherMatrix[y & 0x07]-32L;
2552 if (index >= (ssize_t) rows)
2553 return((ssize_t) rows-1L);
2557 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2561 if (x >= (ssize_t) columns)
2562 return((ssize_t) (columns-1));
2566 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2570 if (y >= (ssize_t) rows)
2571 return((ssize_t) (rows-1));
2575 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2577 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2580 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2582 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2585 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2586 const size_t extent)
2592 Compute the remainder of dividing offset by extent. It returns not only
2593 the quotient (tile the offset falls in) but also the positive remainer
2594 within that tile such that 0 <= remainder < extent. This method is
2595 essentially a ldiv() using a floored modulo division rather than the
2596 normal default truncated modulo division.
2598 modulo.quotient=offset/(ssize_t) extent;
2601 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2605 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2606 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2607 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2608 ExceptionInfo *exception)
2625 virtual_pixel[CompositePixelChannel];
2630 register const Quantum
2643 register unsigned char
2650 *virtual_metacontent;
2655 assert(image != (const Image *) NULL);
2656 assert(image->signature == MagickSignature);
2657 assert(image->cache != (Cache) NULL);
2658 cache_info=(CacheInfo *) image->cache;
2659 assert(cache_info->signature == MagickSignature);
2660 if (cache_info->type == UndefinedCache)
2661 return((const Quantum *) NULL);
2664 region.width=columns;
2666 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2668 if (pixels == (Quantum *) NULL)
2669 return((const Quantum *) NULL);
2671 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2672 nexus_info->region.x;
2673 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2674 nexus_info->region.width-1L;
2675 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2676 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2677 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2678 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2684 Pixel request is inside cache extents.
2686 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
2688 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2689 if (status == MagickFalse)
2690 return((const Quantum *) NULL);
2691 if (cache_info->metacontent_extent != 0)
2693 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2694 if (status == MagickFalse)
2695 return((const Quantum *) NULL);
2700 Pixel request is outside cache extents.
2702 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
2703 virtual_nexus=AcquirePixelCacheNexus(1);
2704 if (virtual_nexus == (NexusInfo **) NULL)
2706 if (virtual_nexus != (NexusInfo **) NULL)
2707 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2708 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2709 "UnableToGetCacheNexus","`%s'",image->filename);
2710 return((const Quantum *) NULL);
2712 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2713 sizeof(*virtual_pixel));
2714 virtual_metacontent=(void *) NULL;
2715 switch (virtual_pixel_method)
2717 case BackgroundVirtualPixelMethod:
2718 case BlackVirtualPixelMethod:
2719 case GrayVirtualPixelMethod:
2720 case TransparentVirtualPixelMethod:
2721 case MaskVirtualPixelMethod:
2722 case WhiteVirtualPixelMethod:
2723 case EdgeVirtualPixelMethod:
2724 case CheckerTileVirtualPixelMethod:
2725 case HorizontalTileVirtualPixelMethod:
2726 case VerticalTileVirtualPixelMethod:
2728 if (cache_info->metacontent_extent != 0)
2731 Acquire a metacontent buffer.
2733 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2734 cache_info->metacontent_extent);
2735 if (virtual_metacontent == (void *) NULL)
2737 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2738 (void) ThrowMagickException(exception,GetMagickModule(),
2739 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2740 return((const Quantum *) NULL);
2742 (void) ResetMagickMemory(virtual_metacontent,0,
2743 cache_info->metacontent_extent);
2745 switch (virtual_pixel_method)
2747 case BlackVirtualPixelMethod:
2749 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2750 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2751 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2754 case GrayVirtualPixelMethod:
2756 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2757 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2759 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2762 case TransparentVirtualPixelMethod:
2764 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2765 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2766 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2769 case MaskVirtualPixelMethod:
2770 case WhiteVirtualPixelMethod:
2772 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2773 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2774 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2779 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2781 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2783 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2785 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2787 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2797 for (v=0; v < (ssize_t) rows; v++)
2799 for (u=0; u < (ssize_t) columns; u+=length)
2801 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
2802 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
2803 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
2811 Transfer a single pixel.
2813 length=(MagickSizeType) 1;
2814 switch (virtual_pixel_method)
2818 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2819 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
2820 1UL,1UL,*virtual_nexus,exception);
2821 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2824 case RandomVirtualPixelMethod:
2826 if (cache_info->random_info == (RandomInfo *) NULL)
2827 cache_info->random_info=AcquireRandomInfo();
2828 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2829 RandomX(cache_info->random_info,cache_info->columns),
2830 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2831 *virtual_nexus,exception);
2832 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2835 case DitherVirtualPixelMethod:
2837 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2838 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
2839 1UL,1UL,*virtual_nexus,exception);
2840 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2843 case TileVirtualPixelMethod:
2845 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2846 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2847 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2848 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2850 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2853 case MirrorVirtualPixelMethod:
2855 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2856 if ((x_modulo.quotient & 0x01) == 1L)
2857 x_modulo.remainder=(ssize_t) cache_info->columns-
2858 x_modulo.remainder-1L;
2859 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2860 if ((y_modulo.quotient & 0x01) == 1L)
2861 y_modulo.remainder=(ssize_t) cache_info->rows-
2862 y_modulo.remainder-1L;
2863 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2864 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2866 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2869 case HorizontalTileEdgeVirtualPixelMethod:
2871 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2872 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2873 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
2874 *virtual_nexus,exception);
2875 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2878 case VerticalTileEdgeVirtualPixelMethod:
2880 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2881 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2882 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
2883 *virtual_nexus,exception);
2884 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2887 case BackgroundVirtualPixelMethod:
2888 case BlackVirtualPixelMethod:
2889 case GrayVirtualPixelMethod:
2890 case TransparentVirtualPixelMethod:
2891 case MaskVirtualPixelMethod:
2892 case WhiteVirtualPixelMethod:
2895 r=virtual_metacontent;
2898 case EdgeVirtualPixelMethod:
2899 case CheckerTileVirtualPixelMethod:
2901 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2902 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2903 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2906 r=virtual_metacontent;
2909 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2910 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2912 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2915 case HorizontalTileVirtualPixelMethod:
2917 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
2920 r=virtual_metacontent;
2923 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2924 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2925 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2926 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2928 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2931 case VerticalTileVirtualPixelMethod:
2933 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
2936 r=virtual_metacontent;
2939 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
2940 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
2941 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2942 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2944 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2948 if (p == (const Quantum *) NULL)
2950 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2952 q+=cache_info->number_channels;
2953 if ((s != (void *) NULL) && (r != (const void *) NULL))
2955 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2956 s+=cache_info->metacontent_extent;
2961 Transfer a run of pixels.
2963 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
2964 length,1UL,*virtual_nexus,exception);
2965 if (p == (const Quantum *) NULL)
2967 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2968 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2969 q+=length*cache_info->number_channels;
2970 if ((r != (void *) NULL) && (s != (const void *) NULL))
2972 (void) memcpy(s,r,(size_t) length);
2973 s+=length*cache_info->metacontent_extent;
2980 if (virtual_metacontent != (void *) NULL)
2981 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2982 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2991 + G e t V i r t u a l P i x e l C a c h e %
2995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2997 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2998 % cache as defined by the geometry parameters. A pointer to the pixels
2999 % is returned if the pixels are transferred, otherwise a NULL is returned.
3001 % The format of the GetVirtualPixelCache() method is:
3003 % const Quantum *GetVirtualPixelCache(const Image *image,
3004 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3005 % const ssize_t y,const size_t columns,const size_t rows,
3006 % ExceptionInfo *exception)
3008 % A description of each parameter follows:
3010 % o image: the image.
3012 % o virtual_pixel_method: the virtual pixel method.
3014 % o x,y,columns,rows: These values define the perimeter of a region of
3017 % o exception: return any errors or warnings in this structure.
3020 static const Quantum *GetVirtualPixelCache(const Image *image,
3021 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3022 const size_t columns,const size_t rows,ExceptionInfo *exception)
3028 id = GetOpenMPThreadId();
3033 assert(image != (const Image *) NULL);
3034 assert(image->signature == MagickSignature);
3035 assert(image->cache != (Cache) NULL);
3036 cache_info=(CacheInfo *) image->cache;
3037 assert(cache_info->signature == MagickSignature);
3038 assert(id < (int) cache_info->number_threads);
3039 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3040 cache_info->nexus_info[id],exception);
3045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049 % G e t V i r t u a l P i x e l Q u e u e %
3053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3056 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3058 % The format of the GetVirtualPixelQueue() method is:
3060 % const Quantum *GetVirtualPixelQueue(const Image image)
3062 % A description of each parameter follows:
3064 % o image: the image.
3067 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3073 id = GetOpenMPThreadId();
3075 assert(image != (const Image *) NULL);
3076 assert(image->signature == MagickSignature);
3077 assert(image->cache != (Cache) NULL);
3078 cache_info=(CacheInfo *) image->cache;
3079 assert(cache_info->signature == MagickSignature);
3080 if (cache_info->methods.get_virtual_pixels_handler !=
3081 (GetVirtualPixelsHandler) NULL)
3082 return(cache_info->methods.get_virtual_pixels_handler(image));
3083 assert(id < (int) cache_info->number_threads);
3084 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3092 % G e t V i r t u a l P i x e l s %
3096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3098 % GetVirtualPixels() returns an immutable pixel region. If the
3099 % region is successfully accessed, a pointer to it is returned, otherwise
3100 % NULL is returned. The returned pointer may point to a temporary working
3101 % copy of the pixels or it may point to the original pixels in memory.
3102 % Performance is maximized if the selected region is part of one row, or one
3103 % or more full rows, since there is opportunity to access the pixels in-place
3104 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3105 % returned pointer must *never* be deallocated by the user.
3107 % Pixels accessed via the returned pointer represent a simple array of type
3108 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3109 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3110 % access the meta-content (of type void) corresponding to the the
3113 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3115 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3116 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3117 % GetCacheViewAuthenticPixels() instead.
3119 % The format of the GetVirtualPixels() method is:
3121 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3122 % const ssize_t y,const size_t columns,const size_t rows,
3123 % ExceptionInfo *exception)
3125 % A description of each parameter follows:
3127 % o image: the image.
3129 % o x,y,columns,rows: These values define the perimeter of a region of
3132 % o exception: return any errors or warnings in this structure.
3135 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3136 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3137 ExceptionInfo *exception)
3143 id = GetOpenMPThreadId();
3148 assert(image != (const Image *) NULL);
3149 assert(image->signature == MagickSignature);
3150 assert(image->cache != (Cache) NULL);
3151 cache_info=(CacheInfo *) image->cache;
3152 assert(cache_info->signature == MagickSignature);
3153 if (cache_info->methods.get_virtual_pixel_handler !=
3154 (GetVirtualPixelHandler) NULL)
3155 return(cache_info->methods.get_virtual_pixel_handler(image,
3156 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3157 assert(id < (int) cache_info->number_threads);
3158 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3159 columns,rows,cache_info->nexus_info[id],exception);
3164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3168 + 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 %
3172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3174 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3175 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3177 % The format of the GetVirtualPixelsCache() method is:
3179 % Quantum *GetVirtualPixelsCache(const Image *image)
3181 % A description of each parameter follows:
3183 % o image: the image.
3186 static const Quantum *GetVirtualPixelsCache(const Image *image)
3192 id = GetOpenMPThreadId();
3194 assert(image != (const Image *) NULL);
3195 assert(image->signature == MagickSignature);
3196 assert(image->cache != (Cache) NULL);
3197 cache_info=(CacheInfo *) image->cache;
3198 assert(cache_info->signature == MagickSignature);
3199 assert(id < (int) cache_info->number_threads);
3200 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3208 + G e t V i r t u a l P i x e l s N e x u s %
3212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3214 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3217 % The format of the GetVirtualPixelsNexus() method is:
3219 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3220 % NexusInfo *nexus_info)
3222 % A description of each parameter follows:
3224 % o cache: the pixel cache.
3226 % o nexus_info: the cache nexus to return the colormap pixels.
3229 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3230 NexusInfo *nexus_info)
3235 assert(cache != (Cache) NULL);
3236 cache_info=(CacheInfo *) cache;
3237 assert(cache_info->signature == MagickSignature);
3238 if (cache_info->storage_class == UndefinedClass)
3239 return((Quantum *) NULL);
3240 return((const Quantum *) nexus_info->pixels);
3244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3248 + O p e n P i x e l C a c h e %
3252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3254 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3255 % dimensions, allocating space for the image pixels and optionally the
3256 % metacontent, and memory mapping the cache if it is disk based. The cache
3257 % nexus array is initialized as well.
3259 % The format of the OpenPixelCache() method is:
3261 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3262 % ExceptionInfo *exception)
3264 % A description of each parameter follows:
3266 % o image: the image.
3268 % o mode: ReadMode, WriteMode, or IOMode.
3270 % o exception: return any errors or warnings in this structure.
3274 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3276 cache_info->mapped=MagickFalse;
3277 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3278 (size_t) cache_info->length));
3279 if (cache_info->pixels == (Quantum *) NULL)
3281 cache_info->mapped=MagickTrue;
3282 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3283 cache_info->length);
3287 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3294 Open pixel cache on disk.
3296 if (cache_info->file != -1)
3297 return(MagickTrue); /* cache already open */
3298 if (*cache_info->cache_filename == '\0')
3299 file=AcquireUniqueFileResource(cache_info->cache_filename);
3305 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3310 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3311 O_BINARY | O_EXCL,S_MODE);
3313 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3319 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3322 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3327 return(MagickFalse);
3328 (void) AcquireMagickResource(FileResource,1);
3329 cache_info->file=file;
3330 cache_info->mode=mode;
3334 static inline MagickOffsetType WritePixelCacheRegion(
3335 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3336 const MagickSizeType length,const unsigned char *restrict buffer)
3338 register MagickOffsetType
3344 #if !defined(MAGICKCORE_HAVE_PWRITE)
3345 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3346 return((MagickOffsetType) -1);
3349 for (i=0; i < (MagickOffsetType) length; i+=count)
3351 #if !defined(MAGICKCORE_HAVE_PWRITE)
3352 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3353 (MagickSizeType) SSIZE_MAX));
3355 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3356 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3368 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3378 cache_info=(CacheInfo *) image->cache;
3379 if (image->debug != MagickFalse)
3382 format[MaxTextExtent],
3383 message[MaxTextExtent];
3385 (void) FormatMagickSize(length,MagickFalse,format);
3386 (void) FormatLocaleString(message,MaxTextExtent,
3387 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3388 cache_info->cache_filename,cache_info->file,format);
3389 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3391 if (length != (MagickSizeType) ((MagickOffsetType) length))
3392 return(MagickFalse);
3393 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3395 return(MagickFalse);
3396 if ((MagickSizeType) offset >= length)
3398 extent=(MagickOffsetType) length-1;
3399 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3400 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3401 if (cache_info->synchronize != MagickFalse)
3406 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3408 return(MagickFalse);
3411 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3414 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3415 ExceptionInfo *exception)
3422 format[MaxTextExtent],
3423 message[MaxTextExtent];
3439 assert(image != (const Image *) NULL);
3440 assert(image->signature == MagickSignature);
3441 assert(image->cache != (Cache) NULL);
3442 if (image->debug != MagickFalse)
3443 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3444 if ((image->columns == 0) || (image->rows == 0))
3445 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3446 cache_info=(CacheInfo *) image->cache;
3447 assert(cache_info->signature == MagickSignature);
3448 source_info=(*cache_info);
3449 source_info.file=(-1);
3450 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3451 image->filename,(double) GetImageIndexInList(image));
3452 cache_info->storage_class=image->storage_class;
3453 cache_info->colorspace=image->colorspace;
3454 cache_info->alpha_trait=image->alpha_trait;
3455 cache_info->mask=image->mask;
3456 cache_info->rows=image->rows;
3457 cache_info->columns=image->columns;
3458 InitializePixelChannelMap(image);
3459 cache_info->number_channels=GetPixelChannels(image);
3460 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3461 sizeof(*image->channel_map));
3462 cache_info->metacontent_extent=image->metacontent_extent;
3463 cache_info->mode=mode;
3464 if (image->ping != MagickFalse)
3466 cache_info->type=PingCache;
3467 cache_info->pixels=(Quantum *) NULL;
3468 cache_info->metacontent=(void *) NULL;
3469 cache_info->length=0;
3472 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3473 packet_size=cache_info->number_channels*sizeof(Quantum);
3474 if (image->metacontent_extent != 0)
3475 packet_size+=cache_info->metacontent_extent;
3476 length=number_pixels*packet_size;
3477 columns=(size_t) (length/cache_info->rows/packet_size);
3478 if (cache_info->columns != columns)
3479 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3481 cache_info->length=length;
3482 status=AcquireMagickResource(AreaResource,cache_info->length);
3483 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3484 cache_info->metacontent_extent);
3485 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3487 status=AcquireMagickResource(MemoryResource,cache_info->length);
3488 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3489 (cache_info->type == MemoryCache))
3491 AllocatePixelCachePixels(cache_info);
3492 if (cache_info->pixels == (Quantum *) NULL)
3493 cache_info->pixels=source_info.pixels;
3497 Create memory pixel cache.
3500 cache_info->type=MemoryCache;
3501 cache_info->metacontent=(void *) NULL;
3502 if (cache_info->metacontent_extent != 0)
3503 cache_info->metacontent=(void *) (cache_info->pixels+
3504 number_pixels*cache_info->number_channels);
3505 if ((source_info.storage_class != UndefinedClass) &&
3508 status=ClonePixelCacheRepository(cache_info,&source_info,
3510 RelinquishPixelCachePixels(&source_info);
3512 if (image->debug != MagickFalse)
3514 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3515 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3517 (void) FormatLocaleString(message,MaxTextExtent,
3518 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3519 cache_info->filename,cache_info->mapped != MagickFalse ?
3520 "Anonymous" : "Heap",type,(double) cache_info->columns,
3521 (double) cache_info->rows,(double)
3522 cache_info->number_channels,format);
3523 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3529 RelinquishMagickResource(MemoryResource,cache_info->length);
3532 Create pixel cache on disk.
3534 status=AcquireMagickResource(DiskResource,cache_info->length);
3535 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3540 if (cache_info->type == DistributedCache)
3541 RelinquishMagickResource(DiskResource,cache_info->length);
3542 server_info=AcquireDistributeCacheInfo(exception);
3543 if (server_info != (DistributeCacheInfo *) NULL)
3545 status=OpenDistributePixelCache(server_info,image);
3546 if (status == MagickFalse)
3547 server_info=DestroyDistributeCacheInfo(server_info);
3551 Create a distributed pixel cache.
3553 cache_info->type=DistributedCache;
3554 cache_info->server_info=server_info;
3555 (void) FormatLocaleString(cache_info->cache_filename,
3556 MaxTextExtent,"%s:%d",
3557 GetDistributeCacheHostname(cache_info->server_info),
3558 GetDistributeCachePort(cache_info->server_info));
3559 if ((source_info.storage_class != UndefinedClass) &&
3562 status=ClonePixelCacheRepository(cache_info,&source_info,
3564 RelinquishPixelCachePixels(&source_info);
3566 if (image->debug != MagickFalse)
3568 (void) FormatMagickSize(cache_info->length,MagickFalse,
3570 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3572 (void) FormatLocaleString(message,MaxTextExtent,
3573 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3574 cache_info->filename,cache_info->cache_filename,
3575 GetDistributeCacheFile(cache_info->server_info),type,
3576 (double) cache_info->columns,(double) cache_info->rows,
3577 (double) cache_info->number_channels,format);
3578 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3584 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3585 "CacheResourcesExhausted","`%s'",image->filename);
3586 return(MagickFalse);
3588 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3590 (void) ClosePixelCacheOnDisk(cache_info);
3591 *cache_info->cache_filename='\0';
3593 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3595 RelinquishMagickResource(DiskResource,cache_info->length);
3596 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3598 return(MagickFalse);
3600 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3601 cache_info->length);
3602 if (status == MagickFalse)
3604 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3606 return(MagickFalse);
3608 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3609 cache_info->metacontent_extent);
3610 if (length != (MagickSizeType) ((size_t) length))
3611 cache_info->type=DiskCache;
3614 status=AcquireMagickResource(MapResource,cache_info->length);
3615 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3616 (cache_info->type != MemoryCache))
3617 cache_info->type=DiskCache;
3620 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3621 cache_info->offset,(size_t) cache_info->length);
3622 if (cache_info->pixels == (Quantum *) NULL)
3624 cache_info->type=DiskCache;
3625 cache_info->pixels=source_info.pixels;
3630 Create file-backed memory-mapped pixel cache.
3633 (void) ClosePixelCacheOnDisk(cache_info);
3634 cache_info->type=MapCache;
3635 cache_info->mapped=MagickTrue;
3636 cache_info->metacontent=(void *) NULL;
3637 if (cache_info->metacontent_extent != 0)
3638 cache_info->metacontent=(void *) (cache_info->pixels+
3639 number_pixels*cache_info->number_channels);
3640 if ((source_info.storage_class != UndefinedClass) &&
3643 status=ClonePixelCacheRepository(cache_info,&source_info,
3645 RelinquishPixelCachePixels(&source_info);
3647 if (image->debug != MagickFalse)
3649 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3650 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3652 (void) FormatLocaleString(message,MaxTextExtent,
3653 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3654 cache_info->filename,cache_info->cache_filename,
3655 cache_info->file,type,(double) cache_info->columns,(double)
3656 cache_info->rows,(double) cache_info->number_channels,
3658 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3664 RelinquishMagickResource(MapResource,cache_info->length);
3667 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3669 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3670 RelinquishPixelCachePixels(&source_info);
3672 if (image->debug != MagickFalse)
3674 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3675 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3677 (void) FormatLocaleString(message,MaxTextExtent,
3678 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3679 cache_info->cache_filename,cache_info->file,type,(double)
3680 cache_info->columns,(double) cache_info->rows,(double)
3681 cache_info->number_channels,format);
3682 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3692 + P e r s i s t P i x e l C a c h e %
3696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3698 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3699 % persistent pixel cache is one that resides on disk and is not destroyed
3700 % when the program exits.
3702 % The format of the PersistPixelCache() method is:
3704 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3705 % const MagickBooleanType attach,MagickOffsetType *offset,
3706 % ExceptionInfo *exception)
3708 % A description of each parameter follows:
3710 % o image: the image.
3712 % o filename: the persistent pixel cache filename.
3714 % o attach: A value other than zero initializes the persistent pixel cache.
3716 % o initialize: A value other than zero initializes the persistent pixel
3719 % o offset: the offset in the persistent cache to store pixels.
3721 % o exception: return any errors or warnings in this structure.
3724 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3725 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3726 ExceptionInfo *exception)
3741 assert(image != (Image *) NULL);
3742 assert(image->signature == MagickSignature);
3743 if (image->debug != MagickFalse)
3744 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3745 assert(image->cache != (void *) NULL);
3746 assert(filename != (const char *) NULL);
3747 assert(offset != (MagickOffsetType *) NULL);
3748 page_size=GetMagickPageSize();
3749 cache_info=(CacheInfo *) image->cache;
3750 assert(cache_info->signature == MagickSignature);
3751 if (attach != MagickFalse)
3754 Attach existing persistent pixel cache.
3756 if (image->debug != MagickFalse)
3757 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3758 "attach persistent cache");
3759 (void) CopyMagickString(cache_info->cache_filename,filename,
3761 cache_info->type=DiskCache;
3762 cache_info->offset=(*offset);
3763 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3764 return(MagickFalse);
3765 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3768 if ((cache_info->mode != ReadMode) &&
3769 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3770 (cache_info->reference_count == 1))
3772 LockSemaphoreInfo(cache_info->semaphore);
3773 if ((cache_info->mode != ReadMode) &&
3774 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3775 (cache_info->reference_count == 1))
3781 Usurp existing persistent pixel cache.
3783 status=rename_utf8(cache_info->cache_filename,filename);
3786 (void) CopyMagickString(cache_info->cache_filename,filename,
3788 *offset+=cache_info->length+page_size-(cache_info->length %
3790 UnlockSemaphoreInfo(cache_info->semaphore);
3791 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3792 if (image->debug != MagickFalse)
3793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3794 "Usurp resident persistent cache");
3798 UnlockSemaphoreInfo(cache_info->semaphore);
3801 Clone persistent pixel cache.
3803 clone_image=(*image);
3804 clone_info=(CacheInfo *) clone_image.cache;
3805 image->cache=ClonePixelCache(cache_info);
3806 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3807 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3808 cache_info->type=DiskCache;
3809 cache_info->offset=(*offset);
3810 cache_info=(CacheInfo *) image->cache;
3811 status=OpenPixelCache(image,IOMode,exception);
3812 if (status != MagickFalse)
3813 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3814 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3815 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3824 + 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 %
3828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3830 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3831 % defined by the region rectangle and returns a pointer to the region. This
3832 % region is subsequently transferred from the pixel cache with
3833 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3834 % pixels are transferred, otherwise a NULL is returned.
3836 % The format of the QueueAuthenticPixelCacheNexus() method is:
3838 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3839 % const ssize_t y,const size_t columns,const size_t rows,
3840 % const MagickBooleanType clone,NexusInfo *nexus_info,
3841 % ExceptionInfo *exception)
3843 % A description of each parameter follows:
3845 % o image: the image.
3847 % o x,y,columns,rows: These values define the perimeter of a region of
3850 % o nexus_info: the cache nexus to set.
3852 % o clone: clone the pixel cache.
3854 % o exception: return any errors or warnings in this structure.
3857 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3858 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3859 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3877 Validate pixel cache geometry.
3879 assert(image != (const Image *) NULL);
3880 assert(image->signature == MagickSignature);
3881 assert(image->cache != (Cache) NULL);
3882 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3883 if (cache_info == (Cache) NULL)
3884 return((Quantum *) NULL);
3885 assert(cache_info->signature == MagickSignature);
3886 if ((cache_info->columns == 0) && (cache_info->rows == 0))
3888 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3889 "NoPixelsDefinedInCache","`%s'",image->filename);
3890 return((Quantum *) NULL);
3892 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3893 (y >= (ssize_t) cache_info->rows))
3895 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3896 "PixelsAreNotAuthentic","`%s'",image->filename);
3897 return((Quantum *) NULL);
3899 offset=(MagickOffsetType) y*cache_info->columns+x;
3901 return((Quantum *) NULL);
3902 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3903 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3904 if ((MagickSizeType) offset >= number_pixels)
3905 return((Quantum *) NULL);
3911 region.width=columns;
3913 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3923 + 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 %
3927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3929 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3930 % defined by the region rectangle and returns a pointer to the region. This
3931 % region is subsequently transferred from the pixel cache with
3932 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3933 % pixels are transferred, otherwise a NULL is returned.
3935 % The format of the QueueAuthenticPixelsCache() method is:
3937 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3938 % const ssize_t y,const size_t columns,const size_t rows,
3939 % ExceptionInfo *exception)
3941 % A description of each parameter follows:
3943 % o image: the image.
3945 % o x,y,columns,rows: These values define the perimeter of a region of
3948 % o exception: return any errors or warnings in this structure.
3951 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3952 const ssize_t y,const size_t columns,const size_t rows,
3953 ExceptionInfo *exception)
3959 id = GetOpenMPThreadId();
3964 assert(image != (const Image *) NULL);
3965 assert(image->signature == MagickSignature);
3966 assert(image->cache != (Cache) NULL);
3967 cache_info=(CacheInfo *) image->cache;
3968 assert(cache_info->signature == MagickSignature);
3969 assert(id < (int) cache_info->number_threads);
3970 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3971 cache_info->nexus_info[id],exception);
3976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3980 % Q u e u e A u t h e n t i c P i x e l s %
3984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3986 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3987 % successfully initialized a pointer to a Quantum array representing the
3988 % region is returned, otherwise NULL is returned. The returned pointer may
3989 % point to a temporary working buffer for the pixels or it may point to the
3990 % final location of the pixels in memory.
3992 % Write-only access means that any existing pixel values corresponding to
3993 % the region are ignored. This is useful if the initial image is being
3994 % created from scratch, or if the existing pixel values are to be
3995 % completely replaced without need to refer to their pre-existing values.
3996 % The application is free to read and write the pixel buffer returned by
3997 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3998 % initialize the pixel array values. Initializing pixel array values is the
3999 % application's responsibility.
4001 % Performance is maximized if the selected region is part of one row, or
4002 % one or more full rows, since then there is opportunity to access the
4003 % pixels in-place (without a copy) if the image is in memory, or in a
4004 % memory-mapped file. The returned pointer must *never* be deallocated
4007 % Pixels accessed via the returned pointer represent a simple array of type
4008 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4009 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4010 % obtain the meta-content (of type void) corresponding to the region.
4011 % Once the Quantum (and/or Quantum) array has been updated, the
4012 % changes must be saved back to the underlying image using
4013 % SyncAuthenticPixels() or they may be lost.
4015 % The format of the QueueAuthenticPixels() method is:
4017 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4018 % const ssize_t y,const size_t columns,const size_t rows,
4019 % ExceptionInfo *exception)
4021 % A description of each parameter follows:
4023 % o image: the image.
4025 % o x,y,columns,rows: These values define the perimeter of a region of
4028 % o exception: return any errors or warnings in this structure.
4031 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4032 const ssize_t y,const size_t columns,const size_t rows,
4033 ExceptionInfo *exception)
4039 id = GetOpenMPThreadId();
4044 assert(image != (Image *) NULL);
4045 assert(image->signature == MagickSignature);
4046 assert(image->cache != (Cache) NULL);
4047 cache_info=(CacheInfo *) image->cache;
4048 assert(cache_info->signature == MagickSignature);
4049 if (cache_info->methods.queue_authentic_pixels_handler !=
4050 (QueueAuthenticPixelsHandler) NULL)
4052 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4056 assert(id < (int) cache_info->number_threads);
4057 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4058 cache_info->nexus_info[id],exception);
4063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4067 + 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 %
4071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4073 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4076 % The format of the ReadPixelCacheMetacontent() method is:
4078 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4079 % NexusInfo *nexus_info,ExceptionInfo *exception)
4081 % A description of each parameter follows:
4083 % o cache_info: the pixel cache.
4085 % o nexus_info: the cache nexus to read the metacontent.
4087 % o exception: return any errors or warnings in this structure.
4091 static inline MagickOffsetType ReadPixelCacheRegion(
4092 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4093 const MagickSizeType length,unsigned char *restrict buffer)
4095 register MagickOffsetType
4101 #if !defined(MAGICKCORE_HAVE_PREAD)
4102 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4103 return((MagickOffsetType) -1);
4106 for (i=0; i < (MagickOffsetType) length; i+=count)
4108 #if !defined(MAGICKCORE_HAVE_PREAD)
4109 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4110 (MagickSizeType) SSIZE_MAX));
4112 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4113 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4125 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4126 NexusInfo *nexus_info,ExceptionInfo *exception)
4142 register unsigned char
4145 if (cache_info->metacontent_extent == 0)
4146 return(MagickFalse);
4147 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4149 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4150 nexus_info->region.x;
4151 length=(MagickSizeType) nexus_info->region.width*
4152 cache_info->metacontent_extent;
4153 extent=length*nexus_info->region.height;
4154 region=nexus_info->region;
4156 q=(unsigned char *) nexus_info->metacontent;
4157 switch (cache_info->type)
4162 register unsigned char
4166 Read meta-content from memory.
4168 if ((cache_info->columns == nexus_info->region.width) &&
4169 (extent == (MagickSizeType) ((size_t) extent)))
4174 p=(unsigned char *) cache_info->metacontent+offset*
4175 cache_info->metacontent_extent;
4176 for (y=0; y < (ssize_t) region.height; y++)
4178 (void) memcpy(q,p,(size_t) length);
4179 p+=cache_info->metacontent_extent*cache_info->columns;
4180 q+=cache_info->metacontent_extent*nexus_info->region.width;
4187 Read meta content from disk.
4189 LockSemaphoreInfo(cache_info->file_semaphore);
4190 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4192 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4193 cache_info->cache_filename);
4194 UnlockSemaphoreInfo(cache_info->file_semaphore);
4195 return(MagickFalse);
4197 if ((cache_info->columns == nexus_info->region.width) &&
4198 (extent <= MagickMaxBufferExtent))
4203 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4204 for (y=0; y < (ssize_t) region.height; y++)
4206 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4207 cache_info->number_channels*sizeof(Quantum)+offset*
4208 cache_info->metacontent_extent,length,(unsigned char *) q);
4209 if (count != (MagickOffsetType) length)
4211 offset+=cache_info->columns;
4212 q+=cache_info->metacontent_extent*nexus_info->region.width;
4214 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4215 (void) ClosePixelCacheOnDisk(cache_info);
4216 UnlockSemaphoreInfo(cache_info->file_semaphore);
4219 case DistributedCache:
4222 Read metacontent from distributed cache.
4224 LockSemaphoreInfo(cache_info->file_semaphore);
4226 for (y=0; y < (ssize_t) region.height; y++)
4228 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4229 length,(unsigned char *) q);
4230 if (count != (MagickOffsetType) length)
4232 q+=cache_info->metacontent_extent*nexus_info->region.width;
4235 UnlockSemaphoreInfo(cache_info->file_semaphore);
4241 if (y < (ssize_t) region.height)
4243 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4244 cache_info->cache_filename);
4245 return(MagickFalse);
4247 if ((cache_info->debug != MagickFalse) &&
4248 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4249 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4250 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4251 nexus_info->region.width,(double) nexus_info->region.height,(double)
4252 nexus_info->region.x,(double) nexus_info->region.y);
4257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4261 + R e a d P i x e l C a c h e P i x e l s %
4265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4267 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4270 % The format of the ReadPixelCachePixels() method is:
4272 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4273 % NexusInfo *nexus_info,ExceptionInfo *exception)
4275 % A description of each parameter follows:
4277 % o cache_info: the pixel cache.
4279 % o nexus_info: the cache nexus to read the pixels.
4281 % o exception: return any errors or warnings in this structure.
4284 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4285 NexusInfo *nexus_info,ExceptionInfo *exception)
4304 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4306 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4307 nexus_info->region.x;
4308 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4310 extent=length*nexus_info->region.height;
4311 region=nexus_info->region;
4313 q=nexus_info->pixels;
4314 switch (cache_info->type)
4323 Read pixels from memory.
4325 if ((cache_info->columns == nexus_info->region.width) &&
4326 (extent == (MagickSizeType) ((size_t) extent)))
4331 p=cache_info->pixels+offset*cache_info->number_channels;
4332 for (y=0; y < (ssize_t) region.height; y++)
4334 (void) memcpy(q,p,(size_t) length);
4335 p+=cache_info->number_channels*cache_info->columns;
4336 q+=cache_info->number_channels*nexus_info->region.width;
4343 Read pixels from disk.
4345 LockSemaphoreInfo(cache_info->file_semaphore);
4346 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4348 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4349 cache_info->cache_filename);
4350 UnlockSemaphoreInfo(cache_info->file_semaphore);
4351 return(MagickFalse);
4353 if ((cache_info->columns == nexus_info->region.width) &&
4354 (extent <= MagickMaxBufferExtent))
4359 for (y=0; y < (ssize_t) region.height; y++)
4361 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4362 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4363 if (count != (MagickOffsetType) length)
4365 offset+=cache_info->columns;
4366 q+=cache_info->number_channels*nexus_info->region.width;
4368 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4369 (void) ClosePixelCacheOnDisk(cache_info);
4370 UnlockSemaphoreInfo(cache_info->file_semaphore);
4373 case DistributedCache:
4376 Read pixels from distributed cache.
4378 LockSemaphoreInfo(cache_info->file_semaphore);
4380 for (y=0; y < (ssize_t) region.height; y++)
4382 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4383 length,(unsigned char *) q);
4384 if (count != (MagickOffsetType) length)
4386 q+=cache_info->number_channels*nexus_info->region.width;
4389 UnlockSemaphoreInfo(cache_info->file_semaphore);
4395 if (y < (ssize_t) region.height)
4397 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4398 cache_info->cache_filename);
4399 return(MagickFalse);
4401 if ((cache_info->debug != MagickFalse) &&
4402 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4403 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4404 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4405 nexus_info->region.width,(double) nexus_info->region.height,(double)
4406 nexus_info->region.x,(double) nexus_info->region.y);
4411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4415 + R e f e r e n c e P i x e l C a c h e %
4419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4421 % ReferencePixelCache() increments the reference count associated with the
4422 % pixel cache returning a pointer to the cache.
4424 % The format of the ReferencePixelCache method is:
4426 % Cache ReferencePixelCache(Cache cache_info)
4428 % A description of each parameter follows:
4430 % o cache_info: the pixel cache.
4433 MagickPrivate Cache ReferencePixelCache(Cache cache)
4438 assert(cache != (Cache *) NULL);
4439 cache_info=(CacheInfo *) cache;
4440 assert(cache_info->signature == MagickSignature);
4441 LockSemaphoreInfo(cache_info->semaphore);
4442 cache_info->reference_count++;
4443 UnlockSemaphoreInfo(cache_info->semaphore);
4448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4452 + S e t P i x e l C a c h e M e t h o d s %
4456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4458 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4460 % The format of the SetPixelCacheMethods() method is:
4462 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4464 % A description of each parameter follows:
4466 % o cache: the pixel cache.
4468 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4471 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4476 GetOneAuthenticPixelFromHandler
4477 get_one_authentic_pixel_from_handler;
4479 GetOneVirtualPixelFromHandler
4480 get_one_virtual_pixel_from_handler;
4483 Set cache pixel methods.
4485 assert(cache != (Cache) NULL);
4486 assert(cache_methods != (CacheMethods *) NULL);
4487 cache_info=(CacheInfo *) cache;
4488 assert(cache_info->signature == MagickSignature);
4489 if (cache_info->debug != MagickFalse)
4490 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4491 cache_info->filename);
4492 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4493 cache_info->methods.get_virtual_pixel_handler=
4494 cache_methods->get_virtual_pixel_handler;
4495 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4496 cache_info->methods.destroy_pixel_handler=
4497 cache_methods->destroy_pixel_handler;
4498 if (cache_methods->get_virtual_metacontent_from_handler !=
4499 (GetVirtualMetacontentFromHandler) NULL)
4500 cache_info->methods.get_virtual_metacontent_from_handler=
4501 cache_methods->get_virtual_metacontent_from_handler;
4502 if (cache_methods->get_authentic_pixels_handler !=
4503 (GetAuthenticPixelsHandler) NULL)
4504 cache_info->methods.get_authentic_pixels_handler=
4505 cache_methods->get_authentic_pixels_handler;
4506 if (cache_methods->queue_authentic_pixels_handler !=
4507 (QueueAuthenticPixelsHandler) NULL)
4508 cache_info->methods.queue_authentic_pixels_handler=
4509 cache_methods->queue_authentic_pixels_handler;
4510 if (cache_methods->sync_authentic_pixels_handler !=
4511 (SyncAuthenticPixelsHandler) NULL)
4512 cache_info->methods.sync_authentic_pixels_handler=
4513 cache_methods->sync_authentic_pixels_handler;
4514 if (cache_methods->get_authentic_pixels_from_handler !=
4515 (GetAuthenticPixelsFromHandler) NULL)
4516 cache_info->methods.get_authentic_pixels_from_handler=
4517 cache_methods->get_authentic_pixels_from_handler;
4518 if (cache_methods->get_authentic_metacontent_from_handler !=
4519 (GetAuthenticMetacontentFromHandler) NULL)
4520 cache_info->methods.get_authentic_metacontent_from_handler=
4521 cache_methods->get_authentic_metacontent_from_handler;
4522 get_one_virtual_pixel_from_handler=
4523 cache_info->methods.get_one_virtual_pixel_from_handler;
4524 if (get_one_virtual_pixel_from_handler !=
4525 (GetOneVirtualPixelFromHandler) NULL)
4526 cache_info->methods.get_one_virtual_pixel_from_handler=
4527 cache_methods->get_one_virtual_pixel_from_handler;
4528 get_one_authentic_pixel_from_handler=
4529 cache_methods->get_one_authentic_pixel_from_handler;
4530 if (get_one_authentic_pixel_from_handler !=
4531 (GetOneAuthenticPixelFromHandler) NULL)
4532 cache_info->methods.get_one_authentic_pixel_from_handler=
4533 cache_methods->get_one_authentic_pixel_from_handler;
4537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4541 + S e t P i x e l C a c h e N e x u s P i x e l s %
4545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4547 % SetPixelCacheNexusPixels() defines the region of the cache for the
4548 % specified cache nexus.
4550 % The format of the SetPixelCacheNexusPixels() method is:
4552 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4553 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4554 % ExceptionInfo *exception)
4556 % A description of each parameter follows:
4558 % o cache_info: the pixel cache.
4560 % o mode: ReadMode, WriteMode, or IOMode.
4562 % o region: A pointer to the RectangleInfo structure that defines the
4563 % region of this particular cache nexus.
4565 % o nexus_info: the cache nexus to set.
4567 % o exception: return any errors or warnings in this structure.
4571 static inline MagickBooleanType AcquireCacheNexusPixels(
4572 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4573 ExceptionInfo *exception)
4575 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4576 return(MagickFalse);
4577 nexus_info->mapped=MagickFalse;
4578 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4579 (size_t) nexus_info->length));
4580 if (nexus_info->cache == (Quantum *) NULL)
4582 nexus_info->mapped=MagickTrue;
4583 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4584 nexus_info->length);
4586 if (nexus_info->cache == (Quantum *) NULL)
4588 (void) ThrowMagickException(exception,GetMagickModule(),
4589 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4590 cache_info->filename);
4591 return(MagickFalse);
4596 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4599 if (mode == ReadMode)
4601 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4604 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4607 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4608 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4609 ExceptionInfo *exception)
4618 assert(cache_info != (const CacheInfo *) NULL);
4619 assert(cache_info->signature == MagickSignature);
4620 if (cache_info->type == UndefinedCache)
4621 return((Quantum *) NULL);
4622 nexus_info->region=(*region);
4623 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4629 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4630 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4631 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4632 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4633 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4634 ((nexus_info->region.width == cache_info->columns) ||
4635 ((nexus_info->region.width % cache_info->columns) == 0)))))
4641 Pixels are accessed directly from memory.
4643 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4644 nexus_info->region.x;
4645 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4647 nexus_info->metacontent=(void *) NULL;
4648 if (cache_info->metacontent_extent != 0)
4649 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4650 offset*cache_info->metacontent_extent;
4651 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4652 return(nexus_info->pixels);
4656 Pixels are stored in a cache region until they are synced to the cache.
4658 number_pixels=(MagickSizeType) nexus_info->region.width*
4659 nexus_info->region.height;
4660 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4661 if (cache_info->metacontent_extent != 0)
4662 length+=number_pixels*cache_info->metacontent_extent;
4663 if (nexus_info->cache == (Quantum *) NULL)
4665 nexus_info->length=length;
4666 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4667 if (status == MagickFalse)
4669 nexus_info->length=0;
4670 return((Quantum *) NULL);
4674 if (nexus_info->length != length)
4676 RelinquishCacheNexusPixels(nexus_info);
4677 nexus_info->length=length;
4678 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4679 if (status == MagickFalse)
4681 nexus_info->length=0;
4682 return((Quantum *) NULL);
4685 nexus_info->pixels=nexus_info->cache;
4686 nexus_info->metacontent=(void *) NULL;
4687 if (cache_info->metacontent_extent != 0)
4688 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4689 cache_info->number_channels);
4690 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4691 return(nexus_info->pixels);
4695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4699 % 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 %
4703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4705 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4706 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4707 % access that is outside the boundaries of the image cache.
4709 % The format of the SetPixelCacheVirtualMethod() method is:
4711 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4712 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4714 % A description of each parameter follows:
4716 % o image: the image.
4718 % o virtual_pixel_method: choose the type of virtual pixel.
4720 % o exception: return any errors or warnings in this structure.
4724 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4725 ExceptionInfo *exception)
4739 assert(image != (Image *) NULL);
4740 assert(image->signature == MagickSignature);
4741 if (image->debug != MagickFalse)
4742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4743 assert(image->cache != (Cache) NULL);
4744 cache_info=(CacheInfo *) image->cache;
4745 assert(cache_info->signature == MagickSignature);
4746 image->alpha_trait=BlendPixelTrait;
4748 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4749 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4750 #pragma omp parallel for schedule(static,4) shared(status) \
4751 magick_threads(image,image,1,1)
4753 for (y=0; y < (ssize_t) image->rows; y++)
4761 if (status == MagickFalse)
4763 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4764 if (q == (Quantum *) NULL)
4769 for (x=0; x < (ssize_t) image->columns; x++)
4771 SetPixelAlpha(image,alpha,q);
4772 q+=GetPixelChannels(image);
4774 status=SyncCacheViewAuthenticPixels(image_view,exception);
4776 image_view=DestroyCacheView(image_view);
4780 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4781 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4789 assert(image != (Image *) NULL);
4790 assert(image->signature == MagickSignature);
4791 if (image->debug != MagickFalse)
4792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4793 assert(image->cache != (Cache) NULL);
4794 cache_info=(CacheInfo *) image->cache;
4795 assert(cache_info->signature == MagickSignature);
4796 method=cache_info->virtual_pixel_method;
4797 cache_info->virtual_pixel_method=virtual_pixel_method;
4798 if ((image->columns != 0) && (image->rows != 0))
4799 switch (virtual_pixel_method)
4801 case BackgroundVirtualPixelMethod:
4803 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4804 (image->alpha_trait != BlendPixelTrait))
4805 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4806 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4807 (IsGrayColorspace(image->colorspace) != MagickFalse))
4808 (void) TransformImageColorspace(image,RGBColorspace,exception);
4811 case TransparentVirtualPixelMethod:
4813 if (image->alpha_trait != BlendPixelTrait)
4814 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4828 + 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 %
4832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4834 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4835 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4836 % is synced, otherwise MagickFalse.
4838 % The format of the SyncAuthenticPixelCacheNexus() method is:
4840 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4841 % NexusInfo *nexus_info,ExceptionInfo *exception)
4843 % A description of each parameter follows:
4845 % o image: the image.
4847 % o nexus_info: the cache nexus to sync.
4849 % o exception: return any errors or warnings in this structure.
4852 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4853 NexusInfo *nexus_info,ExceptionInfo *exception)
4862 Transfer pixels to the cache.
4864 assert(image != (Image *) NULL);
4865 assert(image->signature == MagickSignature);
4866 if (image->cache == (Cache) NULL)
4867 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4868 cache_info=(CacheInfo *) image->cache;
4869 assert(cache_info->signature == MagickSignature);
4870 if (cache_info->type == UndefinedCache)
4871 return(MagickFalse);
4872 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4874 assert(cache_info->signature == MagickSignature);
4875 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4876 if ((cache_info->metacontent_extent != 0) &&
4877 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4878 return(MagickFalse);
4883 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4887 + S y n c A u t h e n t i c P i x e l C a c h e %
4891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4893 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4894 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4895 % otherwise MagickFalse.
4897 % The format of the SyncAuthenticPixelsCache() method is:
4899 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4900 % ExceptionInfo *exception)
4902 % A description of each parameter follows:
4904 % o image: the image.
4906 % o exception: return any errors or warnings in this structure.
4909 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4910 ExceptionInfo *exception)
4916 id = GetOpenMPThreadId();
4921 assert(image != (Image *) NULL);
4922 assert(image->signature == MagickSignature);
4923 assert(image->cache != (Cache) NULL);
4924 cache_info=(CacheInfo *) image->cache;
4925 assert(cache_info->signature == MagickSignature);
4926 assert(id < (int) cache_info->number_threads);
4927 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4937 % S y n c A u t h e n t i c P i x e l s %
4941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4943 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4944 % The method returns MagickTrue if the pixel region is flushed, otherwise
4947 % The format of the SyncAuthenticPixels() method is:
4949 % MagickBooleanType SyncAuthenticPixels(Image *image,
4950 % ExceptionInfo *exception)
4952 % A description of each parameter follows:
4954 % o image: the image.
4956 % o exception: return any errors or warnings in this structure.
4959 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4960 ExceptionInfo *exception)
4966 id = GetOpenMPThreadId();
4971 assert(image != (Image *) NULL);
4972 assert(image->signature == MagickSignature);
4973 assert(image->cache != (Cache) NULL);
4974 cache_info=(CacheInfo *) image->cache;
4975 assert(cache_info->signature == MagickSignature);
4976 if (cache_info->methods.sync_authentic_pixels_handler !=
4977 (SyncAuthenticPixelsHandler) NULL)
4979 status=cache_info->methods.sync_authentic_pixels_handler(image,
4983 assert(id < (int) cache_info->number_threads);
4984 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4994 + S y n c I m a g e P i x e l C a c h e %
4998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5000 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5001 % The method returns MagickTrue if the pixel region is flushed, otherwise
5004 % The format of the SyncImagePixelCache() method is:
5006 % MagickBooleanType SyncImagePixelCache(Image *image,
5007 % ExceptionInfo *exception)
5009 % A description of each parameter follows:
5011 % o image: the image.
5013 % o exception: return any errors or warnings in this structure.
5016 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5017 ExceptionInfo *exception)
5022 assert(image != (Image *) NULL);
5023 assert(exception != (ExceptionInfo *) NULL);
5024 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5025 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5033 + 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 %
5037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5039 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5040 % of the pixel cache.
5042 % The format of the WritePixelCacheMetacontent() method is:
5044 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5045 % NexusInfo *nexus_info,ExceptionInfo *exception)
5047 % A description of each parameter follows:
5049 % o cache_info: the pixel cache.
5051 % o nexus_info: the cache nexus to write the meta-content.
5053 % o exception: return any errors or warnings in this structure.
5056 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5057 NexusInfo *nexus_info,ExceptionInfo *exception)
5070 register const unsigned char
5076 if (cache_info->metacontent_extent == 0)
5077 return(MagickFalse);
5078 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5080 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5081 nexus_info->region.x;
5082 length=(MagickSizeType) nexus_info->region.width*
5083 cache_info->metacontent_extent;
5084 extent=(MagickSizeType) length*nexus_info->region.height;
5085 region=nexus_info->region;
5087 p=(unsigned char *) nexus_info->metacontent;
5088 switch (cache_info->type)
5093 register unsigned char
5097 Write associated pixels to memory.
5099 if ((cache_info->columns == nexus_info->region.width) &&
5100 (extent == (MagickSizeType) ((size_t) extent)))
5105 q=(unsigned char *) cache_info->metacontent+offset*
5106 cache_info->metacontent_extent;
5107 for (y=0; y < (ssize_t) region.height; y++)
5109 (void) memcpy(q,p,(size_t) length);
5110 p+=nexus_info->region.width*cache_info->metacontent_extent;
5111 q+=cache_info->columns*cache_info->metacontent_extent;
5118 Write associated pixels to disk.
5120 LockSemaphoreInfo(cache_info->file_semaphore);
5121 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5123 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5124 cache_info->cache_filename);
5125 UnlockSemaphoreInfo(cache_info->file_semaphore);
5126 return(MagickFalse);
5128 if ((cache_info->columns == nexus_info->region.width) &&
5129 (extent <= MagickMaxBufferExtent))
5134 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5135 for (y=0; y < (ssize_t) region.height; y++)
5137 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5138 cache_info->number_channels*sizeof(Quantum)+offset*
5139 cache_info->metacontent_extent,length,(const unsigned char *) p);
5140 if (count != (MagickOffsetType) length)
5142 p+=cache_info->metacontent_extent*nexus_info->region.width;
5143 offset+=cache_info->columns;
5145 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5146 (void) ClosePixelCacheOnDisk(cache_info);
5147 UnlockSemaphoreInfo(cache_info->file_semaphore);
5150 case DistributedCache:
5153 Write metacontent to distributed cache.
5155 LockSemaphoreInfo(cache_info->file_semaphore);
5157 for (y=0; y < (ssize_t) region.height; y++)
5159 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5160 length,(const unsigned char *) p);
5161 if (count != (MagickOffsetType) length)
5163 p+=cache_info->metacontent_extent*nexus_info->region.width;
5166 UnlockSemaphoreInfo(cache_info->file_semaphore);
5172 if (y < (ssize_t) region.height)
5174 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5175 cache_info->cache_filename);
5176 return(MagickFalse);
5178 if ((cache_info->debug != MagickFalse) &&
5179 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5180 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5181 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5182 nexus_info->region.width,(double) nexus_info->region.height,(double)
5183 nexus_info->region.x,(double) nexus_info->region.y);
5188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5192 + W r i t e C a c h e P i x e l s %
5196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5198 % WritePixelCachePixels() writes image pixels to the specified region of the
5201 % The format of the WritePixelCachePixels() method is:
5203 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5204 % NexusInfo *nexus_info,ExceptionInfo *exception)
5206 % A description of each parameter follows:
5208 % o cache_info: the pixel cache.
5210 % o nexus_info: the cache nexus to write the pixels.
5212 % o exception: return any errors or warnings in this structure.
5215 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5216 NexusInfo *nexus_info,ExceptionInfo *exception)
5229 register const Quantum
5235 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5237 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5238 nexus_info->region.x;
5239 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5241 extent=length*nexus_info->region.height;
5242 region=nexus_info->region;
5244 p=nexus_info->pixels;
5245 switch (cache_info->type)
5254 Write pixels to memory.
5256 if ((cache_info->columns == nexus_info->region.width) &&
5257 (extent == (MagickSizeType) ((size_t) extent)))
5262 q=cache_info->pixels+offset*cache_info->number_channels;
5263 for (y=0; y < (ssize_t) region.height; y++)
5265 (void) memcpy(q,p,(size_t) length);
5266 p+=cache_info->number_channels*nexus_info->region.width;
5267 q+=cache_info->columns*cache_info->number_channels;
5274 Write pixels to disk.
5276 LockSemaphoreInfo(cache_info->file_semaphore);
5277 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5279 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5280 cache_info->cache_filename);
5281 UnlockSemaphoreInfo(cache_info->file_semaphore);
5282 return(MagickFalse);
5284 if ((cache_info->columns == nexus_info->region.width) &&
5285 (extent <= MagickMaxBufferExtent))
5290 for (y=0; y < (ssize_t) region.height; y++)
5292 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5293 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5295 if (count != (MagickOffsetType) length)
5297 p+=cache_info->number_channels*nexus_info->region.width;
5298 offset+=cache_info->columns;
5300 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5301 (void) ClosePixelCacheOnDisk(cache_info);
5302 UnlockSemaphoreInfo(cache_info->file_semaphore);
5305 case DistributedCache:
5308 Write pixels to distributed cache.
5310 LockSemaphoreInfo(cache_info->file_semaphore);
5312 for (y=0; y < (ssize_t) region.height; y++)
5314 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5315 length,(const unsigned char *) p);
5316 if (count != (MagickOffsetType) length)
5318 p+=cache_info->number_channels*nexus_info->region.width;
5321 UnlockSemaphoreInfo(cache_info->file_semaphore);
5327 if (y < (ssize_t) region.height)
5329 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5330 cache_info->cache_filename);
5331 return(MagickFalse);
5333 if ((cache_info->debug != MagickFalse) &&
5334 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5335 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5336 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5337 nexus_info->region.width,(double) nexus_info->region.height,(double)
5338 nexus_info->region.x,(double) nexus_info->region.y);