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
100 #if defined(__cplusplus) || defined(c_plusplus)
105 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
109 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
110 const ssize_t,const size_t,const size_t,ExceptionInfo *),
111 *GetVirtualPixelsCache(const Image *);
114 *GetVirtualMetacontentFromCache(const Image *);
116 static MagickBooleanType
117 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
120 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
122 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
123 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
124 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
125 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
129 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
130 const size_t,ExceptionInfo *),
131 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
132 const size_t,ExceptionInfo *),
133 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
134 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
136 #if defined(__cplusplus) || defined(c_plusplus)
143 static volatile MagickBooleanType
144 instantiate_cache = MagickFalse;
147 *cache_semaphore = (SemaphoreInfo *) NULL;
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 + A c q u i r e P i x e l C a c h e %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % AcquirePixelCache() acquires a pixel cache.
162 % The format of the AcquirePixelCache() method is:
164 % Cache AcquirePixelCache(const size_t number_threads)
166 % A description of each parameter follows:
168 % o number_threads: the number of nexus threads.
171 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
174 *restrict cache_info;
179 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
180 if (cache_info == (CacheInfo *) NULL)
181 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
182 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
183 cache_info->type=UndefinedCache;
184 cache_info->mode=IOMode;
185 cache_info->colorspace=sRGBColorspace;
186 cache_info->file=(-1);
187 cache_info->id=GetMagickThreadId();
188 cache_info->number_threads=number_threads;
189 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
190 cache_info->number_threads=GetOpenMPMaximumThreads();
191 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
192 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
193 if (cache_info->number_threads == 0)
194 cache_info->number_threads=1;
195 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
196 if (cache_info->nexus_info == (NexusInfo **) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
199 if (synchronize != (const char *) NULL)
201 cache_info->synchronize=IsStringTrue(synchronize);
202 synchronize=DestroyString(synchronize);
204 cache_info->semaphore=AllocateSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->file_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 return((Cache ) cache_info);
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % A c q u i r e P i x e l C a c h e N e x u s %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
225 % The format of the AcquirePixelCacheNexus method is:
227 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
229 % A description of each parameter follows:
231 % o number_threads: the number of nexus threads.
234 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
237 **restrict nexus_info;
242 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
243 number_threads,sizeof(*nexus_info)));
244 if (nexus_info == (NexusInfo **) NULL)
245 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
246 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
247 sizeof(**nexus_info));
248 if (nexus_info[0] == (NexusInfo *) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
251 for (i=0; i < (ssize_t) number_threads; i++)
253 nexus_info[i]=(&nexus_info[0][i]);
254 nexus_info[i]->signature=MagickSignature;
260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264 + A c q u i r e P i x e l C a c h e P i x e l s %
268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 % AcquirePixelCachePixels() returns the pixels associated with the specified
273 % The format of the AcquirePixelCachePixels() method is:
275 % const void *AcquirePixelCachePixels(const Image *image,
276 % MagickSizeType *length,ExceptionInfo *exception)
278 % A description of each parameter follows:
280 % o image: the image.
282 % o length: the pixel cache length.
284 % o exception: return any errors or warnings in this structure.
287 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
288 MagickSizeType *length,ExceptionInfo *exception)
291 *restrict cache_info;
293 assert(image != (const Image *) NULL);
294 assert(image->signature == MagickSignature);
295 assert(exception != (ExceptionInfo *) NULL);
296 assert(exception->signature == MagickSignature);
297 assert(image->cache != (Cache) NULL);
298 cache_info=(CacheInfo *) image->cache;
299 assert(cache_info->signature == MagickSignature);
301 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
302 return((const void *) NULL);
303 *length=cache_info->length;
304 return((const void *) cache_info->pixels);
308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 + C a c h e C o m p o n e n t G e n e s i s %
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 % CacheComponentGenesis() instantiates the cache component.
320 % The format of the CacheComponentGenesis method is:
322 % MagickBooleanType CacheComponentGenesis(void)
325 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
327 AcquireSemaphoreInfo(&cache_semaphore);
332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 + C a c h e C o m p o n e n t T e r m i n u s %
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 % CacheComponentTerminus() destroys the cache component.
344 % The format of the CacheComponentTerminus() method is:
346 % CacheComponentTerminus(void)
349 MagickPrivate void CacheComponentTerminus(void)
351 if (cache_semaphore == (SemaphoreInfo *) NULL)
352 AcquireSemaphoreInfo(&cache_semaphore);
353 LockSemaphoreInfo(cache_semaphore);
354 instantiate_cache=MagickFalse;
355 UnlockSemaphoreInfo(cache_semaphore);
356 DestroySemaphoreInfo(&cache_semaphore);
360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 + C l o n e P i x e l C a c h e %
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 % ClonePixelCache() clones a pixel cache.
372 % The format of the ClonePixelCache() method is:
374 % Cache ClonePixelCache(const Cache cache)
376 % A description of each parameter follows:
378 % o cache: the pixel cache.
381 MagickPrivate Cache ClonePixelCache(const Cache cache)
384 *restrict clone_info;
387 *restrict cache_info;
389 assert(cache != NULL);
390 cache_info=(const CacheInfo *) cache;
391 assert(cache_info->signature == MagickSignature);
392 if (cache_info->debug != MagickFalse)
393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
394 cache_info->filename);
395 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
396 if (clone_info == (Cache) NULL)
397 return((Cache) NULL);
398 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
399 return((Cache ) clone_info);
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 + C l o n e P i x e l C a c h e M e t h o d s %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
416 % The format of the ClonePixelCacheMethods() method is:
418 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
420 % A description of each parameter follows:
422 % o clone: Specifies a pointer to a Cache structure.
424 % o cache: the pixel cache.
427 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
430 *restrict cache_info,
431 *restrict source_info;
433 assert(clone != (Cache) NULL);
434 source_info=(CacheInfo *) clone;
435 assert(source_info->signature == MagickSignature);
436 if (source_info->debug != MagickFalse)
437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
438 source_info->filename);
439 assert(cache != (Cache) NULL);
440 cache_info=(CacheInfo *) cache;
441 assert(cache_info->signature == MagickSignature);
442 source_info->methods=cache_info->methods;
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450 + 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 %
454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
455 % ClonePixelCacheRepository() clones the source pixel cache to the destination
458 % The format of the ClonePixelCacheRepository() method is:
460 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
461 % CacheInfo *source_info,ExceptionInfo *exception)
463 % A description of each parameter follows:
465 % o cache_info: the pixel cache.
467 % o source_info: the source pixel cache.
469 % o exception: return any errors or warnings in this structure.
473 static inline MagickSizeType MagickMin(const MagickSizeType x,
474 const MagickSizeType y)
481 static MagickBooleanType ClonePixelCacheRepository(
482 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
483 ExceptionInfo *exception)
485 #define MaxCacheThreads 2
486 #define cache_threads(source,destination,chunk) \
487 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
488 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
489 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
496 **restrict cache_nexus,
497 **restrict clone_nexus;
505 assert(cache_info != (CacheInfo *) NULL);
506 assert(clone_info != (CacheInfo *) NULL);
507 assert(exception != (ExceptionInfo *) NULL);
508 if (cache_info->type == PingCache)
510 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
511 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
512 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
513 (cache_info->columns == clone_info->columns) &&
514 (cache_info->rows == clone_info->rows) &&
515 (cache_info->number_channels == clone_info->number_channels) &&
516 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
517 (cache_info->metacontent_extent == clone_info->metacontent_extent))
520 Identical pixel cache morphology.
522 (void) memcpy(clone_info->pixels,cache_info->pixels,cache_info->columns*
523 cache_info->number_channels*cache_info->rows*
524 sizeof(*cache_info->pixels));
525 if (cache_info->metacontent_extent != 0)
526 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
527 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
528 sizeof(cache_info->metacontent));
532 Mismatched pixel cache morphology.
534 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
535 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
536 if ((cache_nexus == (NexusInfo **) NULL) ||
537 (clone_nexus == (NexusInfo **) NULL))
538 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
539 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
540 optimize=(cache_info->number_channels == clone_info->number_channels) &&
541 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
542 MagickTrue : MagickFalse;
543 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
544 clone_info->columns*clone_info->number_channels);
546 #if defined(MAGICKCORE_OPENMP_SUPPORT)
547 #pragma omp parallel for schedule(static,4) shared(status) \
548 cache_threads(cache_info,clone_info,cache_info->rows)
550 for (y=0; y < (ssize_t) cache_info->rows; y++)
553 id = GetOpenMPThreadId();
564 if (status == MagickFalse)
566 if (y >= (ssize_t) clone_info->rows)
568 region.width=cache_info->columns;
572 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
574 if (pixels == (Quantum *) NULL)
576 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
577 if (status == MagickFalse)
579 region.width=clone_info->columns;
580 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
581 clone_nexus[id],exception);
582 if (pixels == (Quantum *) NULL)
584 if (optimize != MagickFalse)
585 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
589 register const Quantum
596 Mismatched pixel channel map.
598 p=cache_nexus[id]->pixels;
599 q=clone_nexus[id]->pixels;
600 for (x=0; x < (ssize_t) cache_info->columns; x++)
605 if (x == (ssize_t) clone_info->columns)
607 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
615 channel=clone_info->channel_map[i].channel;
616 traits=cache_info->channel_map[channel].traits;
617 if (traits != UndefinedPixelTrait)
618 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
622 p+=cache_info->number_channels;
625 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
627 if ((cache_info->metacontent_extent != 0) &&
628 (clone_info->metacontent_extent != 0))
633 length=(size_t) MagickMin(cache_info->metacontent_extent,
634 clone_info->metacontent_extent);
635 #if defined(MAGICKCORE_OPENMP_SUPPORT)
636 #pragma omp parallel for schedule(static,4) shared(status) \
637 cache_threads(cache_info,clone_info,cache_info->rows)
639 for (y=0; y < (ssize_t) cache_info->rows; y++)
642 id = GetOpenMPThreadId();
650 if (status == MagickFalse)
652 if (y >= (ssize_t) clone_info->rows)
654 region.width=cache_info->columns;
658 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
659 cache_nexus[id],exception);
660 if (pixels == (Quantum *) NULL)
662 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
663 if (status == MagickFalse)
665 region.width=clone_info->columns;
666 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
667 clone_nexus[id],exception);
668 if (pixels == (Quantum *) NULL)
670 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
671 length*sizeof(cache_nexus[id]->metacontent));
672 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
675 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
676 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
677 if (cache_info->debug != MagickFalse)
680 message[MaxTextExtent];
682 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
683 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
684 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
685 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
695 + D e s t r o y I m a g e P i x e l C a c h e %
699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
701 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
703 % The format of the DestroyImagePixelCache() method is:
705 % void DestroyImagePixelCache(Image *image)
707 % A description of each parameter follows:
709 % o image: the image.
712 static void DestroyImagePixelCache(Image *image)
714 assert(image != (Image *) NULL);
715 assert(image->signature == MagickSignature);
716 if (image->debug != MagickFalse)
717 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
718 if (image->cache == (void *) NULL)
720 image->cache=DestroyPixelCache(image->cache);
724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728 + D e s t r o y I m a g e P i x e l s %
732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
734 % DestroyImagePixels() deallocates memory associated with the pixel cache.
736 % The format of the DestroyImagePixels() method is:
738 % void DestroyImagePixels(Image *image)
740 % A description of each parameter follows:
742 % o image: the image.
745 MagickExport void DestroyImagePixels(Image *image)
748 *restrict cache_info;
750 assert(image != (const Image *) NULL);
751 assert(image->signature == MagickSignature);
752 if (image->debug != MagickFalse)
753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
754 assert(image->cache != (Cache) NULL);
755 cache_info=(CacheInfo *) image->cache;
756 assert(cache_info->signature == MagickSignature);
757 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
759 cache_info->methods.destroy_pixel_handler(image);
762 image->cache=DestroyPixelCache(image->cache);
766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
770 + D e s t r o y P i x e l C a c h e %
774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776 % DestroyPixelCache() deallocates memory associated with the pixel cache.
778 % The format of the DestroyPixelCache() method is:
780 % Cache DestroyPixelCache(Cache cache)
782 % A description of each parameter follows:
784 % o cache: the pixel cache.
788 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
794 if (cache_info->file != -1)
796 status=close(cache_info->file);
797 cache_info->file=(-1);
798 RelinquishMagickResource(FileResource,1);
800 return(status == -1 ? MagickFalse : MagickTrue);
803 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
805 switch (cache_info->type)
809 if (cache_info->mapped == MagickFalse)
810 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
813 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
814 (size_t) cache_info->length);
815 RelinquishMagickResource(MemoryResource,cache_info->length);
820 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
822 if (cache_info->mode != ReadMode)
823 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
824 *cache_info->cache_filename='\0';
825 RelinquishMagickResource(MapResource,cache_info->length);
829 if (cache_info->file != -1)
830 (void) ClosePixelCacheOnDisk(cache_info);
831 if (cache_info->mode != ReadMode)
832 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
833 *cache_info->cache_filename='\0';
834 RelinquishMagickResource(DiskResource,cache_info->length);
837 case DistributedCache:
839 *cache_info->cache_filename='\0';
840 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
841 cache_info->server_info);
847 cache_info->type=UndefinedCache;
848 cache_info->mapped=MagickFalse;
849 cache_info->metacontent=(void *) NULL;
852 MagickPrivate Cache DestroyPixelCache(Cache cache)
855 *restrict cache_info;
857 assert(cache != (Cache) NULL);
858 cache_info=(CacheInfo *) cache;
859 assert(cache_info->signature == MagickSignature);
860 if (cache_info->debug != MagickFalse)
861 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
862 cache_info->filename);
863 LockSemaphoreInfo(cache_info->semaphore);
864 cache_info->reference_count--;
865 if (cache_info->reference_count != 0)
867 UnlockSemaphoreInfo(cache_info->semaphore);
868 return((Cache) NULL);
870 UnlockSemaphoreInfo(cache_info->semaphore);
871 if (cache_info->debug != MagickFalse)
874 message[MaxTextExtent];
876 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
877 cache_info->filename);
878 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
880 RelinquishPixelCachePixels(cache_info);
881 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
882 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
883 cache_info->server_info);
884 if (cache_info->nexus_info != (NexusInfo **) NULL)
885 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
886 cache_info->number_threads);
887 if (cache_info->random_info != (RandomInfo *) NULL)
888 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
889 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
890 DestroySemaphoreInfo(&cache_info->file_semaphore);
891 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
892 DestroySemaphoreInfo(&cache_info->semaphore);
893 cache_info->signature=(~MagickSignature);
894 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
904 + D e s t r o y P i x e l C a c h e N e x u s %
908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
912 % The format of the DestroyPixelCacheNexus() method is:
914 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
915 % const size_t number_threads)
917 % A description of each parameter follows:
919 % o nexus_info: the nexus to destroy.
921 % o number_threads: the number of nexus threads.
925 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
927 if (nexus_info->mapped == MagickFalse)
928 (void) RelinquishAlignedMemory(nexus_info->cache);
930 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
931 nexus_info->cache=(Quantum *) NULL;
932 nexus_info->pixels=(Quantum *) NULL;
933 nexus_info->metacontent=(void *) NULL;
934 nexus_info->length=0;
935 nexus_info->mapped=MagickFalse;
938 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
939 const size_t number_threads)
944 assert(nexus_info != (NexusInfo **) NULL);
945 for (i=0; i < (ssize_t) number_threads; i++)
947 if (nexus_info[i]->cache != (Quantum *) NULL)
948 RelinquishCacheNexusPixels(nexus_info[i]);
949 nexus_info[i]->signature=(~MagickSignature);
951 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
952 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961 % G e t A u t h e n t i c M e t a c o n t e n t %
965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
967 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
968 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
969 % returned if the associated pixels are not available.
971 % The format of the GetAuthenticMetacontent() method is:
973 % void *GetAuthenticMetacontent(const Image *image)
975 % A description of each parameter follows:
977 % o image: the image.
980 MagickExport void *GetAuthenticMetacontent(const Image *image)
983 *restrict cache_info;
986 id = GetOpenMPThreadId();
988 assert(image != (const Image *) NULL);
989 assert(image->signature == MagickSignature);
990 assert(image->cache != (Cache) NULL);
991 cache_info=(CacheInfo *) image->cache;
992 assert(cache_info->signature == MagickSignature);
993 if (cache_info->methods.get_authentic_metacontent_from_handler !=
994 (GetAuthenticMetacontentFromHandler) NULL)
999 metacontent=cache_info->methods.
1000 get_authentic_metacontent_from_handler(image);
1001 return(metacontent);
1003 assert(id < (int) cache_info->number_threads);
1004 return(cache_info->nexus_info[id]->metacontent);
1008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1012 + 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 %
1016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1019 % with the last call to QueueAuthenticPixelsCache() or
1020 % GetAuthenticPixelsCache().
1022 % The format of the GetAuthenticMetacontentFromCache() method is:
1024 % void *GetAuthenticMetacontentFromCache(const Image *image)
1026 % A description of each parameter follows:
1028 % o image: the image.
1031 static void *GetAuthenticMetacontentFromCache(const Image *image)
1034 *restrict cache_info;
1037 id = GetOpenMPThreadId();
1039 assert(image != (const Image *) NULL);
1040 assert(image->signature == MagickSignature);
1041 assert(image->cache != (Cache) NULL);
1042 cache_info=(CacheInfo *) image->cache;
1043 assert(cache_info->signature == MagickSignature);
1044 assert(id < (int) cache_info->number_threads);
1045 return(cache_info->nexus_info[id]->metacontent);
1049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 + 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 %
1057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1059 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1060 % disk pixel cache as defined by the geometry parameters. A pointer to the
1061 % pixels is returned if the pixels are transferred, otherwise a NULL is
1064 % The format of the GetAuthenticPixelCacheNexus() method is:
1066 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1067 % const ssize_t y,const size_t columns,const size_t rows,
1068 % NexusInfo *nexus_info,ExceptionInfo *exception)
1070 % A description of each parameter follows:
1072 % o image: the image.
1074 % o x,y,columns,rows: These values define the perimeter of a region of
1077 % o nexus_info: the cache nexus to return.
1079 % o exception: return any errors or warnings in this structure.
1083 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1084 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1085 ExceptionInfo *exception)
1088 *restrict cache_info;
1094 Transfer pixels from the cache.
1096 assert(image != (Image *) NULL);
1097 assert(image->signature == MagickSignature);
1098 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1099 nexus_info,exception);
1100 if (pixels == (Quantum *) NULL)
1101 return((Quantum *) NULL);
1102 cache_info=(CacheInfo *) image->cache;
1103 assert(cache_info->signature == MagickSignature);
1104 if (nexus_info->authentic_pixel_cache != MagickFalse)
1106 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1107 return((Quantum *) NULL);
1108 if (cache_info->metacontent_extent != 0)
1109 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1110 return((Quantum *) NULL);
1115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 + 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 %
1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1126 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1128 % The format of the GetAuthenticPixelsFromCache() method is:
1130 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1132 % A description of each parameter follows:
1134 % o image: the image.
1137 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1140 *restrict cache_info;
1143 id = GetOpenMPThreadId();
1145 assert(image != (const Image *) NULL);
1146 assert(image->signature == MagickSignature);
1147 assert(image->cache != (Cache) NULL);
1148 cache_info=(CacheInfo *) image->cache;
1149 assert(cache_info->signature == MagickSignature);
1150 assert(id < (int) cache_info->number_threads);
1151 return(cache_info->nexus_info[id]->pixels);
1155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1159 % G e t A u t h e n t i c P i x e l Q u e u e %
1163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 % GetAuthenticPixelQueue() returns the authentic pixels associated
1166 % corresponding with the last call to QueueAuthenticPixels() or
1167 % GetAuthenticPixels().
1169 % The format of the GetAuthenticPixelQueue() method is:
1171 % Quantum *GetAuthenticPixelQueue(const Image image)
1173 % A description of each parameter follows:
1175 % o image: the image.
1178 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1181 *restrict cache_info;
1184 id = GetOpenMPThreadId();
1186 assert(image != (const Image *) NULL);
1187 assert(image->signature == MagickSignature);
1188 assert(image->cache != (Cache) NULL);
1189 cache_info=(CacheInfo *) image->cache;
1190 assert(cache_info->signature == MagickSignature);
1191 if (cache_info->methods.get_authentic_pixels_from_handler !=
1192 (GetAuthenticPixelsFromHandler) NULL)
1193 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1194 assert(id < (int) cache_info->number_threads);
1195 return(cache_info->nexus_info[id]->pixels);
1199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203 % G e t A u t h e n t i c P i x e l s %
1206 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1208 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1209 % region is successfully accessed, a pointer to a Quantum array
1210 % representing the region is returned, otherwise NULL is returned.
1212 % The returned pointer may point to a temporary working copy of the pixels
1213 % or it may point to the original pixels in memory. Performance is maximized
1214 % if the selected region is part of one row, or one or more full rows, since
1215 % then there is opportunity to access the pixels in-place (without a copy)
1216 % if the image is in memory, or in a memory-mapped file. The returned pointer
1217 % must *never* be deallocated by the user.
1219 % Pixels accessed via the returned pointer represent a simple array of type
1220 % Quantum. If the image has corresponding metacontent,call
1221 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1222 % meta-content corresponding to the region. Once the Quantum array has
1223 % been updated, the changes must be saved back to the underlying image using
1224 % SyncAuthenticPixels() or they may be lost.
1226 % The format of the GetAuthenticPixels() method is:
1228 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1229 % const ssize_t y,const size_t columns,const size_t rows,
1230 % ExceptionInfo *exception)
1232 % A description of each parameter follows:
1234 % o image: the image.
1236 % o x,y,columns,rows: These values define the perimeter of a region of
1239 % o exception: return any errors or warnings in this structure.
1242 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1243 const ssize_t y,const size_t columns,const size_t rows,
1244 ExceptionInfo *exception)
1247 *restrict cache_info;
1250 id = GetOpenMPThreadId();
1255 assert(image != (Image *) NULL);
1256 assert(image->signature == MagickSignature);
1257 assert(image->cache != (Cache) NULL);
1258 cache_info=(CacheInfo *) image->cache;
1259 assert(cache_info->signature == MagickSignature);
1260 if (cache_info->methods.get_authentic_pixels_handler !=
1261 (GetAuthenticPixelsHandler) NULL)
1263 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1267 assert(id < (int) cache_info->number_threads);
1268 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1269 cache_info->nexus_info[id],exception);
1274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1278 + G e t A u t h e n t i c P i x e l s C a c h e %
1282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1284 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1285 % as defined by the geometry parameters. A pointer to the pixels is returned
1286 % if the pixels are transferred, otherwise a NULL is returned.
1288 % The format of the GetAuthenticPixelsCache() method is:
1290 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1291 % const ssize_t y,const size_t columns,const size_t rows,
1292 % ExceptionInfo *exception)
1294 % A description of each parameter follows:
1296 % o image: the image.
1298 % o x,y,columns,rows: These values define the perimeter of a region of
1301 % o exception: return any errors or warnings in this structure.
1304 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1305 const ssize_t y,const size_t columns,const size_t rows,
1306 ExceptionInfo *exception)
1309 *restrict cache_info;
1312 id = GetOpenMPThreadId();
1317 assert(image != (const Image *) NULL);
1318 assert(image->signature == MagickSignature);
1319 assert(image->cache != (Cache) NULL);
1320 cache_info=(CacheInfo *) image->cache;
1321 if (cache_info == (Cache) NULL)
1322 return((Quantum *) NULL);
1323 assert(cache_info->signature == MagickSignature);
1324 assert(id < (int) cache_info->number_threads);
1325 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1326 cache_info->nexus_info[id],exception);
1331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1335 + G e t I m a g e E x t e n t %
1339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341 % GetImageExtent() returns the extent of the pixels associated corresponding
1342 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1344 % The format of the GetImageExtent() method is:
1346 % MagickSizeType GetImageExtent(const Image *image)
1348 % A description of each parameter follows:
1350 % o image: the image.
1353 MagickExport MagickSizeType GetImageExtent(const Image *image)
1356 *restrict cache_info;
1359 id = GetOpenMPThreadId();
1361 assert(image != (Image *) NULL);
1362 assert(image->signature == MagickSignature);
1363 if (image->debug != MagickFalse)
1364 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1365 assert(image->cache != (Cache) NULL);
1366 cache_info=(CacheInfo *) image->cache;
1367 assert(cache_info->signature == MagickSignature);
1368 assert(id < (int) cache_info->number_threads);
1369 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 + G e t I m a g e P i x e l C a c h e %
1381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383 % GetImagePixelCache() ensures that there is only a single reference to the
1384 % pixel cache to be modified, updating the provided cache pointer to point to
1385 % a clone of the original pixel cache if necessary.
1387 % The format of the GetImagePixelCache method is:
1389 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1390 % ExceptionInfo *exception)
1392 % A description of each parameter follows:
1394 % o image: the image.
1396 % o clone: any value other than MagickFalse clones the cache pixels.
1398 % o exception: return any errors or warnings in this structure.
1402 static inline MagickBooleanType ValidatePixelCacheMorphology(
1403 const Image *restrict image)
1406 *restrict cache_info;
1408 const PixelChannelMap
1413 Does the image match the pixel cache morphology?
1415 cache_info=(CacheInfo *) image->cache;
1416 p=image->channel_map;
1417 q=cache_info->channel_map;
1418 if ((image->storage_class != cache_info->storage_class) ||
1419 (image->colorspace != cache_info->colorspace) ||
1420 (image->alpha_trait != cache_info->alpha_trait) ||
1421 (image->read_mask != cache_info->read_mask) ||
1422 (image->write_mask != cache_info->write_mask) ||
1423 (image->columns != cache_info->columns) ||
1424 (image->rows != cache_info->rows) ||
1425 (image->number_channels != cache_info->number_channels) ||
1426 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1427 (image->metacontent_extent != cache_info->metacontent_extent) ||
1428 (cache_info->nexus_info == (NexusInfo **) NULL))
1429 return(MagickFalse);
1433 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1434 ExceptionInfo *exception)
1437 *restrict cache_info;
1443 static MagickSizeType
1449 cache_timestamp = 0;
1452 LockSemaphoreInfo(image->semaphore);
1453 if (cpu_throttle == 0)
1454 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1455 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1456 MagickDelay(cpu_throttle);
1457 if (time_limit == 0)
1460 Set the expire time in seconds.
1462 time_limit=GetMagickResourceLimit(TimeResource);
1463 cache_timestamp=time((time_t *) NULL);
1465 if ((time_limit != MagickResourceInfinity) &&
1466 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1467 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1468 assert(image->cache != (Cache) NULL);
1469 cache_info=(CacheInfo *) image->cache;
1470 destroy=MagickFalse;
1471 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1473 LockSemaphoreInfo(cache_info->semaphore);
1474 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1485 clone_image=(*image);
1486 clone_image.semaphore=AllocateSemaphoreInfo();
1487 clone_image.reference_count=1;
1488 clone_image.cache=ClonePixelCache(cache_info);
1489 clone_info=(CacheInfo *) clone_image.cache;
1490 status=OpenPixelCache(&clone_image,IOMode,exception);
1491 if (status != MagickFalse)
1493 if (clone != MagickFalse)
1494 status=ClonePixelCacheRepository(clone_info,cache_info,
1496 if (status != MagickFalse)
1498 if (cache_info->reference_count == 1)
1499 cache_info->nexus_info=(NexusInfo **) NULL;
1501 image->cache=clone_image.cache;
1504 DestroySemaphoreInfo(&clone_image.semaphore);
1506 UnlockSemaphoreInfo(cache_info->semaphore);
1508 if (destroy != MagickFalse)
1509 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1510 if (status != MagickFalse)
1513 Ensure the image matches the pixel cache morphology.
1515 image->taint=MagickTrue;
1516 image->type=UndefinedType;
1517 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1519 status=OpenPixelCache(image,IOMode,exception);
1520 cache_info=(CacheInfo *) image->cache;
1521 if (cache_info->type == DiskCache)
1522 (void) ClosePixelCacheOnDisk(cache_info);
1525 UnlockSemaphoreInfo(image->semaphore);
1526 if (status == MagickFalse)
1527 return((Cache) NULL);
1528 return(image->cache);
1532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 + G e t I m a g e P i x e l C a c h e T y p e %
1540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1543 % DiskCache, MemoryCache, MapCache, or PingCache.
1545 % The format of the GetImagePixelCacheType() method is:
1547 % CacheType GetImagePixelCacheType(const Image *image)
1549 % A description of each parameter follows:
1551 % o image: the image.
1554 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1557 *restrict cache_info;
1559 assert(image != (Image *) NULL);
1560 assert(image->signature == MagickSignature);
1561 assert(image->cache != (Cache) NULL);
1562 cache_info=(CacheInfo *) image->cache;
1563 assert(cache_info->signature == MagickSignature);
1564 return(cache_info->type);
1568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1572 % G e t O n e A u t h e n t i c P i x e l %
1576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1578 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1579 % location. The image background color is returned if an error occurs.
1581 % The format of the GetOneAuthenticPixel() method is:
1583 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1584 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1586 % A description of each parameter follows:
1588 % o image: the image.
1590 % o x,y: These values define the location of the pixel to return.
1592 % o pixel: return a pixel at the specified (x,y) location.
1594 % o exception: return any errors or warnings in this structure.
1597 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1598 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1601 *restrict cache_info;
1609 assert(image != (Image *) NULL);
1610 assert(image->signature == MagickSignature);
1611 assert(image->cache != (Cache) NULL);
1612 cache_info=(CacheInfo *) image->cache;
1613 assert(cache_info->signature == MagickSignature);
1614 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1615 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1616 (GetOneAuthenticPixelFromHandler) NULL)
1617 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1619 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1620 if (q == (Quantum *) NULL)
1622 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1623 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1624 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1625 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1626 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1627 return(MagickFalse);
1629 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1631 PixelChannel channel=GetPixelChannelChannel(image,i);
1632 pixel[channel]=q[i];
1638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642 + 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 %
1646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1648 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1649 % location. The image background color is returned if an error occurs.
1651 % The format of the GetOneAuthenticPixelFromCache() method is:
1653 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1654 % const ssize_t x,const ssize_t y,Quantum *pixel,
1655 % ExceptionInfo *exception)
1657 % A description of each parameter follows:
1659 % o image: the image.
1661 % o x,y: These values define the location of the pixel to return.
1663 % o pixel: return a pixel at the specified (x,y) location.
1665 % o exception: return any errors or warnings in this structure.
1668 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1669 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1672 *restrict cache_info;
1675 id = GetOpenMPThreadId();
1683 assert(image != (const Image *) NULL);
1684 assert(image->signature == MagickSignature);
1685 assert(image->cache != (Cache) NULL);
1686 cache_info=(CacheInfo *) image->cache;
1687 assert(cache_info->signature == MagickSignature);
1688 assert(id < (int) cache_info->number_threads);
1689 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1690 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1692 if (q == (Quantum *) NULL)
1694 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1695 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1696 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1697 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1698 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1699 return(MagickFalse);
1701 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1703 PixelChannel channel=GetPixelChannelChannel(image,i);
1704 pixel[channel]=q[i];
1710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1714 % G e t O n e V i r t u a l P i x e l %
1718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1720 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1721 % (x,y) location. The image background color is returned if an error occurs.
1722 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1724 % The format of the GetOneVirtualPixel() method is:
1726 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1727 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1729 % A description of each parameter follows:
1731 % o image: the image.
1733 % o x,y: These values define the location of the pixel to return.
1735 % o pixel: return a pixel at the specified (x,y) location.
1737 % o exception: return any errors or warnings in this structure.
1740 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1741 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1744 *restrict cache_info;
1747 id = GetOpenMPThreadId();
1755 assert(image != (const Image *) NULL);
1756 assert(image->signature == MagickSignature);
1757 assert(image->cache != (Cache) NULL);
1758 cache_info=(CacheInfo *) image->cache;
1759 assert(cache_info->signature == MagickSignature);
1760 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1761 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1762 (GetOneVirtualPixelFromHandler) NULL)
1763 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1764 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1765 assert(id < (int) cache_info->number_threads);
1766 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1767 1UL,1UL,cache_info->nexus_info[id],exception);
1768 if (p == (const Quantum *) NULL)
1770 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1771 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1772 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1773 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1774 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1775 return(MagickFalse);
1777 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1779 PixelChannel channel=GetPixelChannelChannel(image,i);
1780 pixel[channel]=p[i];
1786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790 + 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 %
1794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1796 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1797 % specified (x,y) location. The image background color is returned if an
1800 % The format of the GetOneVirtualPixelFromCache() method is:
1802 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1803 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1804 % Quantum *pixel,ExceptionInfo *exception)
1806 % A description of each parameter follows:
1808 % o image: the image.
1810 % o virtual_pixel_method: the virtual pixel method.
1812 % o x,y: These values define the location of the pixel to return.
1814 % o pixel: return a pixel at the specified (x,y) location.
1816 % o exception: return any errors or warnings in this structure.
1819 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1820 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1821 Quantum *pixel,ExceptionInfo *exception)
1824 *restrict cache_info;
1827 id = GetOpenMPThreadId();
1835 assert(image != (const Image *) NULL);
1836 assert(image->signature == MagickSignature);
1837 assert(image->cache != (Cache) NULL);
1838 cache_info=(CacheInfo *) image->cache;
1839 assert(cache_info->signature == MagickSignature);
1840 assert(id < (int) cache_info->number_threads);
1841 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1842 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1843 cache_info->nexus_info[id],exception);
1844 if (p == (const Quantum *) NULL)
1846 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1847 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1848 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1849 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1850 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1851 return(MagickFalse);
1853 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1855 PixelChannel channel=GetPixelChannelChannel(image,i);
1856 pixel[channel]=p[i];
1862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1866 % G e t O n e V i r t u a l P i x e l I n f o %
1870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1872 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1873 % location. The image background color is returned if an error occurs. If
1874 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1876 % The format of the GetOneVirtualPixelInfo() method is:
1878 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1879 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1880 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1882 % A description of each parameter follows:
1884 % o image: the image.
1886 % o virtual_pixel_method: the virtual pixel method.
1888 % o x,y: these values define the location of the pixel to return.
1890 % o pixel: return a pixel at the specified (x,y) location.
1892 % o exception: return any errors or warnings in this structure.
1895 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1896 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1897 PixelInfo *pixel,ExceptionInfo *exception)
1900 *restrict cache_info;
1903 id = GetOpenMPThreadId();
1905 register const Quantum
1908 assert(image != (const Image *) NULL);
1909 assert(image->signature == MagickSignature);
1910 assert(image->cache != (Cache) NULL);
1911 cache_info=(CacheInfo *) image->cache;
1912 assert(cache_info->signature == MagickSignature);
1913 assert(id < (int) cache_info->number_threads);
1914 GetPixelInfo(image,pixel);
1915 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1916 cache_info->nexus_info[id],exception);
1917 if (p == (const Quantum *) NULL)
1918 return(MagickFalse);
1919 GetPixelInfoPixel(image,p,pixel);
1924 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1928 + G e t P i x e l C a c h e C o l o r s p a c e %
1932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1934 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1936 % The format of the GetPixelCacheColorspace() method is:
1938 % Colorspace GetPixelCacheColorspace(Cache cache)
1940 % A description of each parameter follows:
1942 % o cache: the pixel cache.
1945 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1948 *restrict cache_info;
1950 assert(cache != (Cache) NULL);
1951 cache_info=(CacheInfo *) cache;
1952 assert(cache_info->signature == MagickSignature);
1953 if (cache_info->debug != MagickFalse)
1954 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1955 cache_info->filename);
1956 return(cache_info->colorspace);
1960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964 + G e t P i x e l C a c h e M e t h o d s %
1968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970 % GetPixelCacheMethods() initializes the CacheMethods structure.
1972 % The format of the GetPixelCacheMethods() method is:
1974 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1976 % A description of each parameter follows:
1978 % o cache_methods: Specifies a pointer to a CacheMethods structure.
1981 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
1983 assert(cache_methods != (CacheMethods *) NULL);
1984 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
1985 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
1986 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
1987 cache_methods->get_virtual_metacontent_from_handler=
1988 GetVirtualMetacontentFromCache;
1989 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
1990 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
1991 cache_methods->get_authentic_metacontent_from_handler=
1992 GetAuthenticMetacontentFromCache;
1993 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
1994 cache_methods->get_one_authentic_pixel_from_handler=
1995 GetOneAuthenticPixelFromCache;
1996 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
1997 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
1998 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2006 + G e t P i x e l C a c h e N e x u s E x t e n t %
2010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2013 % corresponding with the last call to SetPixelCacheNexusPixels() or
2014 % GetPixelCacheNexusPixels().
2016 % The format of the GetPixelCacheNexusExtent() method is:
2018 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2019 % NexusInfo *nexus_info)
2021 % A description of each parameter follows:
2023 % o nexus_info: the nexus info.
2026 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2027 NexusInfo *restrict nexus_info)
2030 *restrict cache_info;
2035 assert(cache != NULL);
2036 cache_info=(CacheInfo *) cache;
2037 assert(cache_info->signature == MagickSignature);
2038 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2040 return((MagickSizeType) cache_info->columns*cache_info->rows);
2045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2049 + G e t P i x e l C a c h e P i x e l s %
2053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2055 % GetPixelCachePixels() returns the pixels associated with the specified image.
2057 % The format of the GetPixelCachePixels() method is:
2059 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2060 % ExceptionInfo *exception)
2062 % A description of each parameter follows:
2064 % o image: the image.
2066 % o length: the pixel cache length.
2068 % o exception: return any errors or warnings in this structure.
2071 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2072 ExceptionInfo *exception)
2075 *restrict cache_info;
2077 assert(image != (const Image *) NULL);
2078 assert(image->signature == MagickSignature);
2079 assert(image->cache != (Cache) NULL);
2080 assert(length != (MagickSizeType *) NULL);
2081 assert(exception != (ExceptionInfo *) NULL);
2082 assert(exception->signature == MagickSignature);
2083 cache_info=(CacheInfo *) image->cache;
2084 assert(cache_info->signature == MagickSignature);
2086 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2087 return((void *) NULL);
2088 *length=cache_info->length;
2089 return((void *) cache_info->pixels);
2093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2097 + 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 %
2101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2103 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2105 % The format of the GetPixelCacheStorageClass() method is:
2107 % ClassType GetPixelCacheStorageClass(Cache cache)
2109 % A description of each parameter follows:
2111 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2113 % o cache: the pixel cache.
2116 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2119 *restrict cache_info;
2121 assert(cache != (Cache) NULL);
2122 cache_info=(CacheInfo *) cache;
2123 assert(cache_info->signature == MagickSignature);
2124 if (cache_info->debug != MagickFalse)
2125 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2126 cache_info->filename);
2127 return(cache_info->storage_class);
2131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2135 + G e t P i x e l C a c h e T i l e S i z e %
2139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2141 % GetPixelCacheTileSize() returns the pixel cache tile size.
2143 % The format of the GetPixelCacheTileSize() method is:
2145 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2148 % A description of each parameter follows:
2150 % o image: the image.
2152 % o width: the optimize cache tile width in pixels.
2154 % o height: the optimize cache tile height in pixels.
2157 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2161 *restrict cache_info;
2163 assert(image != (Image *) NULL);
2164 assert(image->signature == MagickSignature);
2165 if (image->debug != MagickFalse)
2166 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2167 cache_info=(CacheInfo *) image->cache;
2168 assert(cache_info->signature == MagickSignature);
2169 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2170 if (GetImagePixelCacheType(image) == DiskCache)
2171 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2180 + 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 %
2184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2186 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2187 % pixel cache. A virtual pixel is any pixel access that is outside the
2188 % boundaries of the image cache.
2190 % The format of the GetPixelCacheVirtualMethod() method is:
2192 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2194 % A description of each parameter follows:
2196 % o image: the image.
2199 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2202 *restrict cache_info;
2204 assert(image != (Image *) NULL);
2205 assert(image->signature == MagickSignature);
2206 assert(image->cache != (Cache) NULL);
2207 cache_info=(CacheInfo *) image->cache;
2208 assert(cache_info->signature == MagickSignature);
2209 return(cache_info->virtual_pixel_method);
2213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2217 + 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 %
2221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2224 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2226 % The format of the GetVirtualMetacontentFromCache() method is:
2228 % void *GetVirtualMetacontentFromCache(const Image *image)
2230 % A description of each parameter follows:
2232 % o image: the image.
2235 static const void *GetVirtualMetacontentFromCache(const Image *image)
2238 *restrict cache_info;
2241 id = GetOpenMPThreadId();
2244 *restrict metacontent;
2246 assert(image != (const Image *) NULL);
2247 assert(image->signature == MagickSignature);
2248 assert(image->cache != (Cache) NULL);
2249 cache_info=(CacheInfo *) image->cache;
2250 assert(cache_info->signature == MagickSignature);
2251 assert(id < (int) cache_info->number_threads);
2252 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2253 cache_info->nexus_info[id]);
2254 return(metacontent);
2258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2262 + 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 %
2266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2268 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2271 % The format of the GetVirtualMetacontentFromNexus() method is:
2273 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2274 % NexusInfo *nexus_info)
2276 % A description of each parameter follows:
2278 % o cache: the pixel cache.
2280 % o nexus_info: the cache nexus to return the meta-content.
2283 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2284 NexusInfo *restrict nexus_info)
2287 *restrict cache_info;
2289 assert(cache != (Cache) NULL);
2290 cache_info=(CacheInfo *) cache;
2291 assert(cache_info->signature == MagickSignature);
2292 if (cache_info->storage_class == UndefinedClass)
2293 return((void *) NULL);
2294 return(nexus_info->metacontent);
2298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2302 % G e t V i r t u a l M e t a c o n t e n t %
2306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2308 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2309 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2310 % returned if the meta-content are not available.
2312 % The format of the GetVirtualMetacontent() method is:
2314 % const void *GetVirtualMetacontent(const Image *image)
2316 % A description of each parameter follows:
2318 % o image: the image.
2321 MagickExport const void *GetVirtualMetacontent(const Image *image)
2324 *restrict cache_info;
2327 id = GetOpenMPThreadId();
2330 *restrict metacontent;
2332 assert(image != (const Image *) NULL);
2333 assert(image->signature == MagickSignature);
2334 assert(image->cache != (Cache) NULL);
2335 cache_info=(CacheInfo *) image->cache;
2336 assert(cache_info->signature == MagickSignature);
2337 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2338 if (metacontent != (void *) NULL)
2339 return(metacontent);
2340 assert(id < (int) cache_info->number_threads);
2341 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2342 cache_info->nexus_info[id]);
2343 return(metacontent);
2347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2351 + 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 %
2355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2357 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2358 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2359 % is returned if the pixels are transferred, otherwise a NULL is returned.
2361 % The format of the GetVirtualPixelsFromNexus() method is:
2363 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2364 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2365 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2366 % ExceptionInfo *exception)
2368 % A description of each parameter follows:
2370 % o image: the image.
2372 % o virtual_pixel_method: the virtual pixel method.
2374 % o x,y,columns,rows: These values define the perimeter of a region of
2377 % o nexus_info: the cache nexus to acquire.
2379 % o exception: return any errors or warnings in this structure.
2386 0, 48, 12, 60, 3, 51, 15, 63,
2387 32, 16, 44, 28, 35, 19, 47, 31,
2388 8, 56, 4, 52, 11, 59, 7, 55,
2389 40, 24, 36, 20, 43, 27, 39, 23,
2390 2, 50, 14, 62, 1, 49, 13, 61,
2391 34, 18, 46, 30, 33, 17, 45, 29,
2392 10, 58, 6, 54, 9, 57, 5, 53,
2393 42, 26, 38, 22, 41, 25, 37, 21
2396 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2401 index=x+DitherMatrix[x & 0x07]-32L;
2404 if (index >= (ssize_t) columns)
2405 return((ssize_t) columns-1L);
2409 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2414 index=y+DitherMatrix[y & 0x07]-32L;
2417 if (index >= (ssize_t) rows)
2418 return((ssize_t) rows-1L);
2422 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2426 if (x >= (ssize_t) columns)
2427 return((ssize_t) (columns-1));
2431 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2435 if (y >= (ssize_t) rows)
2436 return((ssize_t) (rows-1));
2440 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2442 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2445 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2447 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2450 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2451 const size_t extent)
2457 Compute the remainder of dividing offset by extent. It returns not only
2458 the quotient (tile the offset falls in) but also the positive remainer
2459 within that tile such that 0 <= remainder < extent. This method is
2460 essentially a ldiv() using a floored modulo division rather than the
2461 normal default truncated modulo division.
2463 modulo.quotient=offset/(ssize_t) extent;
2466 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2470 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2471 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2472 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2473 ExceptionInfo *exception)
2476 *restrict cache_info;
2486 **restrict virtual_nexus;
2490 virtual_pixel[MaxPixelChannels];
2495 register const Quantum
2508 register unsigned char
2515 *restrict virtual_metacontent;
2520 assert(image != (const Image *) NULL);
2521 assert(image->signature == MagickSignature);
2522 assert(image->cache != (Cache) NULL);
2523 cache_info=(CacheInfo *) image->cache;
2524 assert(cache_info->signature == MagickSignature);
2525 if (cache_info->type == UndefinedCache)
2526 return((const Quantum *) NULL);
2529 region.width=columns;
2531 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2533 if (pixels == (Quantum *) NULL)
2534 return((const Quantum *) NULL);
2536 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2537 nexus_info->region.x;
2538 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2539 nexus_info->region.width-1L;
2540 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2541 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2542 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2543 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2549 Pixel request is inside cache extents.
2551 if (nexus_info->authentic_pixel_cache != MagickFalse)
2553 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2554 if (status == MagickFalse)
2555 return((const Quantum *) NULL);
2556 if (cache_info->metacontent_extent != 0)
2558 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2559 if (status == MagickFalse)
2560 return((const Quantum *) NULL);
2565 Pixel request is outside cache extents.
2567 s=(unsigned char *) nexus_info->metacontent;
2568 virtual_nexus=AcquirePixelCacheNexus(1);
2569 if (virtual_nexus == (NexusInfo **) NULL)
2571 if (virtual_nexus != (NexusInfo **) NULL)
2572 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2573 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2574 "UnableToGetCacheNexus","`%s'",image->filename);
2575 return((const Quantum *) NULL);
2577 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2578 sizeof(*virtual_pixel));
2579 virtual_metacontent=(void *) NULL;
2580 switch (virtual_pixel_method)
2582 case BackgroundVirtualPixelMethod:
2583 case BlackVirtualPixelMethod:
2584 case GrayVirtualPixelMethod:
2585 case TransparentVirtualPixelMethod:
2586 case MaskVirtualPixelMethod:
2587 case WhiteVirtualPixelMethod:
2588 case EdgeVirtualPixelMethod:
2589 case CheckerTileVirtualPixelMethod:
2590 case HorizontalTileVirtualPixelMethod:
2591 case VerticalTileVirtualPixelMethod:
2593 if (cache_info->metacontent_extent != 0)
2596 Acquire a metacontent buffer.
2598 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2599 cache_info->metacontent_extent);
2600 if (virtual_metacontent == (void *) NULL)
2602 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2603 (void) ThrowMagickException(exception,GetMagickModule(),
2604 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2605 return((const Quantum *) NULL);
2607 (void) ResetMagickMemory(virtual_metacontent,0,
2608 cache_info->metacontent_extent);
2610 switch (virtual_pixel_method)
2612 case BlackVirtualPixelMethod:
2614 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2615 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2616 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2619 case GrayVirtualPixelMethod:
2621 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2622 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2624 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2627 case TransparentVirtualPixelMethod:
2629 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2630 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2631 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2634 case MaskVirtualPixelMethod:
2635 case WhiteVirtualPixelMethod:
2637 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2638 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2639 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2644 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2646 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2648 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2650 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2652 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2662 for (v=0; v < (ssize_t) rows; v++)
2668 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2669 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2670 y_offset=EdgeY(y_offset,cache_info->rows);
2671 for (u=0; u < (ssize_t) columns; u+=length)
2677 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2678 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2679 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2687 Transfer a single pixel.
2689 length=(MagickSizeType) 1;
2690 switch (virtual_pixel_method)
2692 case EdgeVirtualPixelMethod:
2695 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2696 EdgeX(x_offset,cache_info->columns),
2697 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2699 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2702 case RandomVirtualPixelMethod:
2704 if (cache_info->random_info == (RandomInfo *) NULL)
2705 cache_info->random_info=AcquireRandomInfo();
2706 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2707 RandomX(cache_info->random_info,cache_info->columns),
2708 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2709 *virtual_nexus,exception);
2710 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2713 case DitherVirtualPixelMethod:
2715 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2716 DitherX(x_offset,cache_info->columns),
2717 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2719 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2722 case TileVirtualPixelMethod:
2724 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2725 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2726 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2727 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2729 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2732 case MirrorVirtualPixelMethod:
2734 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2735 if ((x_modulo.quotient & 0x01) == 1L)
2736 x_modulo.remainder=(ssize_t) cache_info->columns-
2737 x_modulo.remainder-1L;
2738 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2739 if ((y_modulo.quotient & 0x01) == 1L)
2740 y_modulo.remainder=(ssize_t) cache_info->rows-
2741 y_modulo.remainder-1L;
2742 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2743 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2745 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2748 case HorizontalTileEdgeVirtualPixelMethod:
2750 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2751 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2752 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2753 *virtual_nexus,exception);
2754 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2757 case VerticalTileEdgeVirtualPixelMethod:
2759 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2760 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2761 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2762 *virtual_nexus,exception);
2763 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2766 case BackgroundVirtualPixelMethod:
2767 case BlackVirtualPixelMethod:
2768 case GrayVirtualPixelMethod:
2769 case TransparentVirtualPixelMethod:
2770 case MaskVirtualPixelMethod:
2771 case WhiteVirtualPixelMethod:
2774 r=virtual_metacontent;
2777 case CheckerTileVirtualPixelMethod:
2779 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2780 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2781 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2784 r=virtual_metacontent;
2787 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2788 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2790 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2793 case HorizontalTileVirtualPixelMethod:
2795 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2798 r=virtual_metacontent;
2801 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2802 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2803 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2804 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2806 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2809 case VerticalTileVirtualPixelMethod:
2811 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2814 r=virtual_metacontent;
2817 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2818 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2819 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2820 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2822 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2826 if (p == (const Quantum *) NULL)
2828 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2830 q+=cache_info->number_channels;
2831 if ((s != (void *) NULL) && (r != (const void *) NULL))
2833 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2834 s+=cache_info->metacontent_extent;
2839 Transfer a run of pixels.
2841 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2842 (size_t) length,1UL,*virtual_nexus,exception);
2843 if (p == (const Quantum *) NULL)
2845 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2846 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2847 q+=length*cache_info->number_channels;
2848 if ((r != (void *) NULL) && (s != (const void *) NULL))
2850 (void) memcpy(s,r,(size_t) length);
2851 s+=length*cache_info->metacontent_extent;
2858 if (virtual_metacontent != (void *) NULL)
2859 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2860 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2869 + G e t V i r t u a l P i x e l C a c h e %
2873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2876 % cache as defined by the geometry parameters. A pointer to the pixels
2877 % is returned if the pixels are transferred, otherwise a NULL is returned.
2879 % The format of the GetVirtualPixelCache() method is:
2881 % const Quantum *GetVirtualPixelCache(const Image *image,
2882 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2883 % const ssize_t y,const size_t columns,const size_t rows,
2884 % ExceptionInfo *exception)
2886 % A description of each parameter follows:
2888 % o image: the image.
2890 % o virtual_pixel_method: the virtual pixel method.
2892 % o x,y,columns,rows: These values define the perimeter of a region of
2895 % o exception: return any errors or warnings in this structure.
2898 static const Quantum *GetVirtualPixelCache(const Image *image,
2899 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2900 const size_t columns,const size_t rows,ExceptionInfo *exception)
2903 *restrict cache_info;
2906 id = GetOpenMPThreadId();
2911 assert(image != (const Image *) NULL);
2912 assert(image->signature == MagickSignature);
2913 assert(image->cache != (Cache) NULL);
2914 cache_info=(CacheInfo *) image->cache;
2915 assert(cache_info->signature == MagickSignature);
2916 assert(id < (int) cache_info->number_threads);
2917 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2918 cache_info->nexus_info[id],exception);
2923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927 % G e t V i r t u a l P i x e l Q u e u e %
2931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2933 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2934 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2936 % The format of the GetVirtualPixelQueue() method is:
2938 % const Quantum *GetVirtualPixelQueue(const Image image)
2940 % A description of each parameter follows:
2942 % o image: the image.
2945 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2948 *restrict cache_info;
2951 id = GetOpenMPThreadId();
2953 assert(image != (const Image *) NULL);
2954 assert(image->signature == MagickSignature);
2955 assert(image->cache != (Cache) NULL);
2956 cache_info=(CacheInfo *) image->cache;
2957 assert(cache_info->signature == MagickSignature);
2958 if (cache_info->methods.get_virtual_pixels_handler !=
2959 (GetVirtualPixelsHandler) NULL)
2960 return(cache_info->methods.get_virtual_pixels_handler(image));
2961 assert(id < (int) cache_info->number_threads);
2962 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970 % G e t V i r t u a l P i x e l s %
2974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2976 % GetVirtualPixels() returns an immutable pixel region. If the
2977 % region is successfully accessed, a pointer to it is returned, otherwise
2978 % NULL is returned. The returned pointer may point to a temporary working
2979 % copy of the pixels or it may point to the original pixels in memory.
2980 % Performance is maximized if the selected region is part of one row, or one
2981 % or more full rows, since there is opportunity to access the pixels in-place
2982 % (without a copy) if the image is in memory, or in a memory-mapped file. The
2983 % returned pointer must *never* be deallocated by the user.
2985 % Pixels accessed via the returned pointer represent a simple array of type
2986 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
2987 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
2988 % access the meta-content (of type void) corresponding to the the
2991 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
2993 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
2994 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
2995 % GetCacheViewAuthenticPixels() instead.
2997 % The format of the GetVirtualPixels() method is:
2999 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3000 % const ssize_t y,const size_t columns,const size_t rows,
3001 % ExceptionInfo *exception)
3003 % A description of each parameter follows:
3005 % o image: the image.
3007 % o x,y,columns,rows: These values define the perimeter of a region of
3010 % o exception: return any errors or warnings in this structure.
3013 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3014 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3015 ExceptionInfo *exception)
3018 *restrict cache_info;
3021 id = GetOpenMPThreadId();
3026 assert(image != (const Image *) NULL);
3027 assert(image->signature == MagickSignature);
3028 assert(image->cache != (Cache) NULL);
3029 cache_info=(CacheInfo *) image->cache;
3030 assert(cache_info->signature == MagickSignature);
3031 if (cache_info->methods.get_virtual_pixel_handler !=
3032 (GetVirtualPixelHandler) NULL)
3033 return(cache_info->methods.get_virtual_pixel_handler(image,
3034 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3035 assert(id < (int) cache_info->number_threads);
3036 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3037 columns,rows,cache_info->nexus_info[id],exception);
3042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046 + 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 %
3050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3052 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3053 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3055 % The format of the GetVirtualPixelsCache() method is:
3057 % Quantum *GetVirtualPixelsCache(const Image *image)
3059 % A description of each parameter follows:
3061 % o image: the image.
3064 static const Quantum *GetVirtualPixelsCache(const Image *image)
3067 *restrict cache_info;
3070 id = GetOpenMPThreadId();
3072 assert(image != (const Image *) NULL);
3073 assert(image->signature == MagickSignature);
3074 assert(image->cache != (Cache) NULL);
3075 cache_info=(CacheInfo *) image->cache;
3076 assert(cache_info->signature == MagickSignature);
3077 assert(id < (int) cache_info->number_threads);
3078 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3086 + G e t V i r t u a l P i x e l s N e x u s %
3090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3092 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3095 % The format of the GetVirtualPixelsNexus() method is:
3097 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3098 % NexusInfo *nexus_info)
3100 % A description of each parameter follows:
3102 % o cache: the pixel cache.
3104 % o nexus_info: the cache nexus to return the colormap pixels.
3107 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3108 NexusInfo *restrict nexus_info)
3111 *restrict cache_info;
3113 assert(cache != (Cache) NULL);
3114 cache_info=(CacheInfo *) cache;
3115 assert(cache_info->signature == MagickSignature);
3116 if (cache_info->storage_class == UndefinedClass)
3117 return((Quantum *) NULL);
3118 return((const Quantum *) nexus_info->pixels);
3122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3126 + O p e n P i x e l C a c h e %
3130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3132 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3133 % dimensions, allocating space for the image pixels and optionally the
3134 % metacontent, and memory mapping the cache if it is disk based. The cache
3135 % nexus array is initialized as well.
3137 % The format of the OpenPixelCache() method is:
3139 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3140 % ExceptionInfo *exception)
3142 % A description of each parameter follows:
3144 % o image: the image.
3146 % o mode: ReadMode, WriteMode, or IOMode.
3148 % o exception: return any errors or warnings in this structure.
3152 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3154 cache_info->mapped=MagickFalse;
3155 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3156 (size_t) cache_info->length));
3157 if (cache_info->pixels == (Quantum *) NULL)
3159 cache_info->mapped=MagickTrue;
3160 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3161 cache_info->length);
3165 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3172 Open pixel cache on disk.
3174 if (cache_info->file != -1)
3175 return(MagickTrue); /* cache already open */
3176 if (*cache_info->cache_filename == '\0')
3177 file=AcquireUniqueFileResource(cache_info->cache_filename);
3183 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3188 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3189 O_BINARY | O_EXCL,S_MODE);
3191 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3197 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3200 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3205 return(MagickFalse);
3206 (void) AcquireMagickResource(FileResource,1);
3207 cache_info->file=file;
3208 cache_info->mode=mode;
3212 static inline MagickOffsetType WritePixelCacheRegion(
3213 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3214 const MagickSizeType length,const unsigned char *restrict buffer)
3216 register MagickOffsetType
3222 #if !defined(MAGICKCORE_HAVE_PWRITE)
3223 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3224 return((MagickOffsetType) -1);
3227 for (i=0; i < (MagickOffsetType) length; i+=count)
3229 #if !defined(MAGICKCORE_HAVE_PWRITE)
3230 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3231 (MagickSizeType) SSIZE_MAX));
3233 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3234 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3246 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3249 *restrict cache_info;
3256 cache_info=(CacheInfo *) image->cache;
3257 if (image->debug != MagickFalse)
3260 format[MaxTextExtent],
3261 message[MaxTextExtent];
3263 (void) FormatMagickSize(length,MagickFalse,format);
3264 (void) FormatLocaleString(message,MaxTextExtent,
3265 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3266 cache_info->cache_filename,cache_info->file,format);
3267 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3269 if (length != (MagickSizeType) ((MagickOffsetType) length))
3270 return(MagickFalse);
3271 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3273 return(MagickFalse);
3274 if ((MagickSizeType) offset >= length)
3276 extent=(MagickOffsetType) length-1;
3277 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3278 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3279 if (cache_info->synchronize != MagickFalse)
3284 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3286 return(MagickFalse);
3289 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3292 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3293 ExceptionInfo *exception)
3296 *restrict cache_info,
3300 format[MaxTextExtent],
3301 message[MaxTextExtent];
3317 assert(image != (const Image *) NULL);
3318 assert(image->signature == MagickSignature);
3319 assert(image->cache != (Cache) NULL);
3320 if (image->debug != MagickFalse)
3321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3322 if ((image->columns == 0) || (image->rows == 0))
3323 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3324 cache_info=(CacheInfo *) image->cache;
3325 assert(cache_info->signature == MagickSignature);
3326 source_info=(*cache_info);
3327 source_info.file=(-1);
3328 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3329 image->filename,(double) GetImageIndexInList(image));
3330 cache_info->storage_class=image->storage_class;
3331 cache_info->colorspace=image->colorspace;
3332 cache_info->alpha_trait=image->alpha_trait;
3333 cache_info->read_mask=image->read_mask;
3334 cache_info->write_mask=image->write_mask;
3335 cache_info->rows=image->rows;
3336 cache_info->columns=image->columns;
3337 InitializePixelChannelMap(image);
3338 cache_info->number_channels=GetPixelChannels(image);
3339 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3340 sizeof(*image->channel_map));
3341 cache_info->metacontent_extent=image->metacontent_extent;
3342 cache_info->mode=mode;
3343 if (image->ping != MagickFalse)
3345 cache_info->type=PingCache;
3346 cache_info->pixels=(Quantum *) NULL;
3347 cache_info->metacontent=(void *) NULL;
3348 cache_info->length=0;
3351 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3352 packet_size=cache_info->number_channels*sizeof(Quantum);
3353 if (image->metacontent_extent != 0)
3354 packet_size+=cache_info->metacontent_extent;
3355 length=number_pixels*packet_size;
3356 columns=(size_t) (length/cache_info->rows/packet_size);
3357 if (cache_info->columns != columns)
3358 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3360 cache_info->length=length;
3361 status=AcquireMagickResource(AreaResource,cache_info->length);
3362 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3363 cache_info->metacontent_extent);
3364 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3366 status=AcquireMagickResource(MemoryResource,cache_info->length);
3367 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3368 (cache_info->type == MemoryCache))
3370 AllocatePixelCachePixels(cache_info);
3371 if (cache_info->pixels == (Quantum *) NULL)
3372 cache_info->pixels=source_info.pixels;
3376 Create memory pixel cache.
3379 cache_info->type=MemoryCache;
3380 cache_info->metacontent=(void *) NULL;
3381 if (cache_info->metacontent_extent != 0)
3382 cache_info->metacontent=(void *) (cache_info->pixels+
3383 number_pixels*cache_info->number_channels);
3384 if ((source_info.storage_class != UndefinedClass) &&
3387 status=ClonePixelCacheRepository(cache_info,&source_info,
3389 RelinquishPixelCachePixels(&source_info);
3391 if (image->debug != MagickFalse)
3393 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3394 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3396 (void) FormatLocaleString(message,MaxTextExtent,
3397 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3398 cache_info->filename,cache_info->mapped != MagickFalse ?
3399 "Anonymous" : "Heap",type,(double) cache_info->columns,
3400 (double) cache_info->rows,(double)
3401 cache_info->number_channels,format);
3402 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3408 RelinquishMagickResource(MemoryResource,cache_info->length);
3411 Create pixel cache on disk.
3413 status=AcquireMagickResource(DiskResource,cache_info->length);
3414 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3419 if (cache_info->type == DistributedCache)
3420 RelinquishMagickResource(DiskResource,cache_info->length);
3421 server_info=AcquireDistributeCacheInfo(exception);
3422 if (server_info != (DistributeCacheInfo *) NULL)
3424 status=OpenDistributePixelCache(server_info,image);
3425 if (status == MagickFalse)
3427 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3428 GetDistributeCacheHostname(server_info));
3429 server_info=DestroyDistributeCacheInfo(server_info);
3434 Create a distributed pixel cache.
3436 cache_info->type=DistributedCache;
3437 cache_info->server_info=server_info;
3438 (void) FormatLocaleString(cache_info->cache_filename,
3439 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3440 (DistributeCacheInfo *) cache_info->server_info),
3441 GetDistributeCachePort((DistributeCacheInfo *)
3442 cache_info->server_info));
3443 if ((source_info.storage_class != UndefinedClass) &&
3446 status=ClonePixelCacheRepository(cache_info,&source_info,
3448 RelinquishPixelCachePixels(&source_info);
3450 if (image->debug != MagickFalse)
3452 (void) FormatMagickSize(cache_info->length,MagickFalse,
3454 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3456 (void) FormatLocaleString(message,MaxTextExtent,
3457 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3458 cache_info->filename,cache_info->cache_filename,
3459 GetDistributeCacheFile((DistributeCacheInfo *)
3460 cache_info->server_info),type,(double) cache_info->columns,
3461 (double) cache_info->rows,(double)
3462 cache_info->number_channels,format);
3463 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3469 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3470 "CacheResourcesExhausted","`%s'",image->filename);
3471 return(MagickFalse);
3473 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3475 (void) ClosePixelCacheOnDisk(cache_info);
3476 *cache_info->cache_filename='\0';
3478 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3480 RelinquishMagickResource(DiskResource,cache_info->length);
3481 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3483 return(MagickFalse);
3485 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3486 cache_info->length);
3487 if (status == MagickFalse)
3489 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3491 return(MagickFalse);
3493 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3494 cache_info->metacontent_extent);
3495 if (length != (MagickSizeType) ((size_t) length))
3496 cache_info->type=DiskCache;
3499 status=AcquireMagickResource(MapResource,cache_info->length);
3500 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3501 (cache_info->type != MemoryCache))
3502 cache_info->type=DiskCache;
3505 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3506 cache_info->offset,(size_t) cache_info->length);
3507 if (cache_info->pixels == (Quantum *) NULL)
3509 cache_info->type=DiskCache;
3510 cache_info->pixels=source_info.pixels;
3515 Create file-backed memory-mapped pixel cache.
3518 (void) ClosePixelCacheOnDisk(cache_info);
3519 cache_info->type=MapCache;
3520 cache_info->mapped=MagickTrue;
3521 cache_info->metacontent=(void *) NULL;
3522 if (cache_info->metacontent_extent != 0)
3523 cache_info->metacontent=(void *) (cache_info->pixels+
3524 number_pixels*cache_info->number_channels);
3525 if ((source_info.storage_class != UndefinedClass) &&
3528 status=ClonePixelCacheRepository(cache_info,&source_info,
3530 RelinquishPixelCachePixels(&source_info);
3532 if (image->debug != MagickFalse)
3534 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3535 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3537 (void) FormatLocaleString(message,MaxTextExtent,
3538 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3539 cache_info->filename,cache_info->cache_filename,
3540 cache_info->file,type,(double) cache_info->columns,(double)
3541 cache_info->rows,(double) cache_info->number_channels,
3543 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3549 RelinquishMagickResource(MapResource,cache_info->length);
3552 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3554 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3555 RelinquishPixelCachePixels(&source_info);
3557 if (image->debug != MagickFalse)
3559 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3560 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3562 (void) FormatLocaleString(message,MaxTextExtent,
3563 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3564 cache_info->cache_filename,cache_info->file,type,(double)
3565 cache_info->columns,(double) cache_info->rows,(double)
3566 cache_info->number_channels,format);
3567 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3577 + P e r s i s t P i x e l C a c h e %
3581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3583 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3584 % persistent pixel cache is one that resides on disk and is not destroyed
3585 % when the program exits.
3587 % The format of the PersistPixelCache() method is:
3589 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3590 % const MagickBooleanType attach,MagickOffsetType *offset,
3591 % ExceptionInfo *exception)
3593 % A description of each parameter follows:
3595 % o image: the image.
3597 % o filename: the persistent pixel cache filename.
3599 % o attach: A value other than zero initializes the persistent pixel cache.
3601 % o initialize: A value other than zero initializes the persistent pixel
3604 % o offset: the offset in the persistent cache to store pixels.
3606 % o exception: return any errors or warnings in this structure.
3609 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3610 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3611 ExceptionInfo *exception)
3614 *restrict cache_info,
3615 *restrict clone_info;
3626 assert(image != (Image *) NULL);
3627 assert(image->signature == MagickSignature);
3628 if (image->debug != MagickFalse)
3629 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3630 assert(image->cache != (void *) NULL);
3631 assert(filename != (const char *) NULL);
3632 assert(offset != (MagickOffsetType *) NULL);
3633 page_size=GetMagickPageSize();
3634 cache_info=(CacheInfo *) image->cache;
3635 assert(cache_info->signature == MagickSignature);
3636 if (attach != MagickFalse)
3639 Attach existing persistent pixel cache.
3641 if (image->debug != MagickFalse)
3642 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3643 "attach persistent cache");
3644 (void) CopyMagickString(cache_info->cache_filename,filename,
3646 cache_info->type=DiskCache;
3647 cache_info->offset=(*offset);
3648 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3649 return(MagickFalse);
3650 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3653 if ((cache_info->mode != ReadMode) &&
3654 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3655 (cache_info->reference_count == 1))
3657 LockSemaphoreInfo(cache_info->semaphore);
3658 if ((cache_info->mode != ReadMode) &&
3659 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3660 (cache_info->reference_count == 1))
3666 Usurp existing persistent pixel cache.
3668 status=rename_utf8(cache_info->cache_filename,filename);
3671 (void) CopyMagickString(cache_info->cache_filename,filename,
3673 *offset+=cache_info->length+page_size-(cache_info->length %
3675 UnlockSemaphoreInfo(cache_info->semaphore);
3676 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3677 if (image->debug != MagickFalse)
3678 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3679 "Usurp resident persistent cache");
3683 UnlockSemaphoreInfo(cache_info->semaphore);
3686 Clone persistent pixel cache.
3688 clone_image=(*image);
3689 clone_info=(CacheInfo *) clone_image.cache;
3690 image->cache=ClonePixelCache(cache_info);
3691 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3692 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3693 cache_info->type=DiskCache;
3694 cache_info->offset=(*offset);
3695 cache_info=(CacheInfo *) image->cache;
3696 status=OpenPixelCache(image,IOMode,exception);
3697 if (status != MagickFalse)
3698 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3699 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3700 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3709 + 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 %
3713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3715 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3716 % defined by the region rectangle and returns a pointer to the region. This
3717 % region is subsequently transferred from the pixel cache with
3718 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3719 % pixels are transferred, otherwise a NULL is returned.
3721 % The format of the QueueAuthenticPixelCacheNexus() method is:
3723 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3724 % const ssize_t y,const size_t columns,const size_t rows,
3725 % const MagickBooleanType clone,NexusInfo *nexus_info,
3726 % ExceptionInfo *exception)
3728 % A description of each parameter follows:
3730 % o image: the image.
3732 % o x,y,columns,rows: These values define the perimeter of a region of
3735 % o nexus_info: the cache nexus to set.
3737 % o clone: clone the pixel cache.
3739 % o exception: return any errors or warnings in this structure.
3742 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3743 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3744 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3747 *restrict cache_info;
3762 Validate pixel cache geometry.
3764 assert(image != (const Image *) NULL);
3765 assert(image->signature == MagickSignature);
3766 assert(image->cache != (Cache) NULL);
3767 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3768 if (cache_info == (Cache) NULL)
3769 return((Quantum *) NULL);
3770 assert(cache_info->signature == MagickSignature);
3771 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3772 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3773 (y >= (ssize_t) cache_info->rows))
3775 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3776 "PixelsAreNotAuthentic","`%s'",image->filename);
3777 return((Quantum *) NULL);
3779 offset=(MagickOffsetType) y*cache_info->columns+x;
3781 return((Quantum *) NULL);
3782 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3783 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3784 if ((MagickSizeType) offset >= number_pixels)
3785 return((Quantum *) NULL);
3791 region.width=columns;
3793 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803 + 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 %
3807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3809 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3810 % defined by the region rectangle and returns a pointer to the region. This
3811 % region is subsequently transferred from the pixel cache with
3812 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3813 % pixels are transferred, otherwise a NULL is returned.
3815 % The format of the QueueAuthenticPixelsCache() method is:
3817 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3818 % const ssize_t y,const size_t columns,const size_t rows,
3819 % ExceptionInfo *exception)
3821 % A description of each parameter follows:
3823 % o image: the image.
3825 % o x,y,columns,rows: These values define the perimeter of a region of
3828 % o exception: return any errors or warnings in this structure.
3831 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3832 const ssize_t y,const size_t columns,const size_t rows,
3833 ExceptionInfo *exception)
3836 *restrict cache_info;
3839 id = GetOpenMPThreadId();
3844 assert(image != (const Image *) NULL);
3845 assert(image->signature == MagickSignature);
3846 assert(image->cache != (Cache) NULL);
3847 cache_info=(CacheInfo *) image->cache;
3848 assert(cache_info->signature == MagickSignature);
3849 assert(id < (int) cache_info->number_threads);
3850 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3851 cache_info->nexus_info[id],exception);
3856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3860 % Q u e u e A u t h e n t i c P i x e l s %
3864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3866 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3867 % successfully initialized a pointer to a Quantum array representing the
3868 % region is returned, otherwise NULL is returned. The returned pointer may
3869 % point to a temporary working buffer for the pixels or it may point to the
3870 % final location of the pixels in memory.
3872 % Write-only access means that any existing pixel values corresponding to
3873 % the region are ignored. This is useful if the initial image is being
3874 % created from scratch, or if the existing pixel values are to be
3875 % completely replaced without need to refer to their pre-existing values.
3876 % The application is free to read and write the pixel buffer returned by
3877 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3878 % initialize the pixel array values. Initializing pixel array values is the
3879 % application's responsibility.
3881 % Performance is maximized if the selected region is part of one row, or
3882 % one or more full rows, since then there is opportunity to access the
3883 % pixels in-place (without a copy) if the image is in memory, or in a
3884 % memory-mapped file. The returned pointer must *never* be deallocated
3887 % Pixels accessed via the returned pointer represent a simple array of type
3888 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3889 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3890 % obtain the meta-content (of type void) corresponding to the region.
3891 % Once the Quantum (and/or Quantum) array has been updated, the
3892 % changes must be saved back to the underlying image using
3893 % SyncAuthenticPixels() or they may be lost.
3895 % The format of the QueueAuthenticPixels() method is:
3897 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3898 % const ssize_t y,const size_t columns,const size_t rows,
3899 % ExceptionInfo *exception)
3901 % A description of each parameter follows:
3903 % o image: the image.
3905 % o x,y,columns,rows: These values define the perimeter of a region of
3908 % o exception: return any errors or warnings in this structure.
3911 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3912 const ssize_t y,const size_t columns,const size_t rows,
3913 ExceptionInfo *exception)
3916 *restrict cache_info;
3919 id = GetOpenMPThreadId();
3924 assert(image != (Image *) NULL);
3925 assert(image->signature == MagickSignature);
3926 assert(image->cache != (Cache) NULL);
3927 cache_info=(CacheInfo *) image->cache;
3928 assert(cache_info->signature == MagickSignature);
3929 if (cache_info->methods.queue_authentic_pixels_handler !=
3930 (QueueAuthenticPixelsHandler) NULL)
3932 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3933 columns,rows,exception);
3936 assert(id < (int) cache_info->number_threads);
3937 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3938 cache_info->nexus_info[id],exception);
3943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3947 + 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 %
3951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3953 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3956 % The format of the ReadPixelCacheMetacontent() method is:
3958 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
3959 % NexusInfo *nexus_info,ExceptionInfo *exception)
3961 % A description of each parameter follows:
3963 % o cache_info: the pixel cache.
3965 % o nexus_info: the cache nexus to read the metacontent.
3967 % o exception: return any errors or warnings in this structure.
3971 static inline MagickOffsetType ReadPixelCacheRegion(
3972 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3973 const MagickSizeType length,unsigned char *restrict buffer)
3975 register MagickOffsetType
3981 #if !defined(MAGICKCORE_HAVE_PREAD)
3982 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3983 return((MagickOffsetType) -1);
3986 for (i=0; i < (MagickOffsetType) length; i+=count)
3988 #if !defined(MAGICKCORE_HAVE_PREAD)
3989 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3990 (MagickSizeType) SSIZE_MAX));
3992 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3993 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4005 static MagickBooleanType ReadPixelCacheMetacontent(
4006 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4007 ExceptionInfo *exception)
4020 register unsigned char
4026 if (cache_info->metacontent_extent == 0)
4027 return(MagickFalse);
4028 if (nexus_info->authentic_pixel_cache != MagickFalse)
4030 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4031 nexus_info->region.x;
4032 length=(MagickSizeType) nexus_info->region.width*
4033 cache_info->metacontent_extent;
4034 extent=length*nexus_info->region.height;
4035 rows=nexus_info->region.height;
4037 q=(unsigned char *) nexus_info->metacontent;
4038 switch (cache_info->type)
4043 register unsigned char
4047 Read meta-content from memory.
4049 if ((cache_info->columns == nexus_info->region.width) &&
4050 (extent == (MagickSizeType) ((size_t) extent)))
4055 p=(unsigned char *) cache_info->metacontent+offset*
4056 cache_info->metacontent_extent;
4057 for (y=0; y < (ssize_t) rows; y++)
4059 (void) memcpy(q,p,(size_t) length);
4060 p+=cache_info->metacontent_extent*cache_info->columns;
4061 q+=cache_info->metacontent_extent*nexus_info->region.width;
4068 Read meta content from disk.
4070 LockSemaphoreInfo(cache_info->file_semaphore);
4071 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4073 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4074 cache_info->cache_filename);
4075 UnlockSemaphoreInfo(cache_info->file_semaphore);
4076 return(MagickFalse);
4078 if ((cache_info->columns == nexus_info->region.width) &&
4079 (extent <= MagickMaxBufferExtent))
4084 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4085 for (y=0; y < (ssize_t) rows; y++)
4087 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4088 cache_info->number_channels*sizeof(Quantum)+offset*
4089 cache_info->metacontent_extent,length,(unsigned char *) q);
4090 if (count != (MagickOffsetType) length)
4092 offset+=cache_info->columns;
4093 q+=cache_info->metacontent_extent*nexus_info->region.width;
4095 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4096 (void) ClosePixelCacheOnDisk(cache_info);
4097 UnlockSemaphoreInfo(cache_info->file_semaphore);
4100 case DistributedCache:
4106 Read metacontent from distributed cache.
4108 LockSemaphoreInfo(cache_info->file_semaphore);
4109 region=nexus_info->region;
4110 if ((cache_info->columns != nexus_info->region.width) ||
4111 (extent > MagickMaxBufferExtent))
4118 for (y=0; y < (ssize_t) rows; y++)
4120 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4121 cache_info->server_info,®ion,length,(unsigned char *) q);
4122 if (count != (MagickOffsetType) length)
4124 q+=cache_info->metacontent_extent*nexus_info->region.width;
4127 UnlockSemaphoreInfo(cache_info->file_semaphore);
4133 if (y < (ssize_t) rows)
4135 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4136 cache_info->cache_filename);
4137 return(MagickFalse);
4139 if ((cache_info->debug != MagickFalse) &&
4140 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4141 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4142 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4143 nexus_info->region.width,(double) nexus_info->region.height,(double)
4144 nexus_info->region.x,(double) nexus_info->region.y);
4149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4153 + R e a d P i x e l C a c h e P i x e l s %
4157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4159 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4162 % The format of the ReadPixelCachePixels() method is:
4164 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4165 % NexusInfo *nexus_info,ExceptionInfo *exception)
4167 % A description of each parameter follows:
4169 % o cache_info: the pixel cache.
4171 % o nexus_info: the cache nexus to read the pixels.
4173 % o exception: return any errors or warnings in this structure.
4176 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4177 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4196 if (nexus_info->authentic_pixel_cache != MagickFalse)
4198 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4199 nexus_info->region.x;
4200 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4202 extent=length*nexus_info->region.height;
4203 rows=nexus_info->region.height;
4205 q=nexus_info->pixels;
4206 switch (cache_info->type)
4215 Read pixels from memory.
4217 if ((cache_info->columns == nexus_info->region.width) &&
4218 (extent == (MagickSizeType) ((size_t) extent)))
4223 p=cache_info->pixels+offset*cache_info->number_channels;
4224 for (y=0; y < (ssize_t) rows; y++)
4226 (void) memcpy(q,p,(size_t) length);
4227 p+=cache_info->number_channels*cache_info->columns;
4228 q+=cache_info->number_channels*nexus_info->region.width;
4235 Read pixels from disk.
4237 LockSemaphoreInfo(cache_info->file_semaphore);
4238 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4240 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4241 cache_info->cache_filename);
4242 UnlockSemaphoreInfo(cache_info->file_semaphore);
4243 return(MagickFalse);
4245 if ((cache_info->columns == nexus_info->region.width) &&
4246 (extent <= MagickMaxBufferExtent))
4251 for (y=0; y < (ssize_t) rows; y++)
4253 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4254 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4255 if (count != (MagickOffsetType) length)
4257 offset+=cache_info->columns;
4258 q+=cache_info->number_channels*nexus_info->region.width;
4260 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4261 (void) ClosePixelCacheOnDisk(cache_info);
4262 UnlockSemaphoreInfo(cache_info->file_semaphore);
4265 case DistributedCache:
4271 Read pixels from distributed cache.
4273 LockSemaphoreInfo(cache_info->file_semaphore);
4274 region=nexus_info->region;
4275 if ((cache_info->columns != nexus_info->region.width) ||
4276 (extent > MagickMaxBufferExtent))
4283 for (y=0; y < (ssize_t) rows; y++)
4285 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4286 cache_info->server_info,®ion,length,(unsigned char *) q);
4287 if (count != (MagickOffsetType) length)
4289 q+=cache_info->number_channels*nexus_info->region.width;
4292 UnlockSemaphoreInfo(cache_info->file_semaphore);
4298 if (y < (ssize_t) rows)
4300 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4301 cache_info->cache_filename);
4302 return(MagickFalse);
4304 if ((cache_info->debug != MagickFalse) &&
4305 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4306 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4307 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4308 nexus_info->region.width,(double) nexus_info->region.height,(double)
4309 nexus_info->region.x,(double) nexus_info->region.y);
4314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4318 + R e f e r e n c e P i x e l C a c h e %
4322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4324 % ReferencePixelCache() increments the reference count associated with the
4325 % pixel cache returning a pointer to the cache.
4327 % The format of the ReferencePixelCache method is:
4329 % Cache ReferencePixelCache(Cache cache_info)
4331 % A description of each parameter follows:
4333 % o cache_info: the pixel cache.
4336 MagickPrivate Cache ReferencePixelCache(Cache cache)
4339 *restrict cache_info;
4341 assert(cache != (Cache *) NULL);
4342 cache_info=(CacheInfo *) cache;
4343 assert(cache_info->signature == MagickSignature);
4344 LockSemaphoreInfo(cache_info->semaphore);
4345 cache_info->reference_count++;
4346 UnlockSemaphoreInfo(cache_info->semaphore);
4351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4355 + S e t P i x e l C a c h e M e t h o d s %
4359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4361 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4363 % The format of the SetPixelCacheMethods() method is:
4365 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4367 % A description of each parameter follows:
4369 % o cache: the pixel cache.
4371 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4374 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4377 *restrict cache_info;
4379 GetOneAuthenticPixelFromHandler
4380 get_one_authentic_pixel_from_handler;
4382 GetOneVirtualPixelFromHandler
4383 get_one_virtual_pixel_from_handler;
4386 Set cache pixel methods.
4388 assert(cache != (Cache) NULL);
4389 assert(cache_methods != (CacheMethods *) NULL);
4390 cache_info=(CacheInfo *) cache;
4391 assert(cache_info->signature == MagickSignature);
4392 if (cache_info->debug != MagickFalse)
4393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4394 cache_info->filename);
4395 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4396 cache_info->methods.get_virtual_pixel_handler=
4397 cache_methods->get_virtual_pixel_handler;
4398 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4399 cache_info->methods.destroy_pixel_handler=
4400 cache_methods->destroy_pixel_handler;
4401 if (cache_methods->get_virtual_metacontent_from_handler !=
4402 (GetVirtualMetacontentFromHandler) NULL)
4403 cache_info->methods.get_virtual_metacontent_from_handler=
4404 cache_methods->get_virtual_metacontent_from_handler;
4405 if (cache_methods->get_authentic_pixels_handler !=
4406 (GetAuthenticPixelsHandler) NULL)
4407 cache_info->methods.get_authentic_pixels_handler=
4408 cache_methods->get_authentic_pixels_handler;
4409 if (cache_methods->queue_authentic_pixels_handler !=
4410 (QueueAuthenticPixelsHandler) NULL)
4411 cache_info->methods.queue_authentic_pixels_handler=
4412 cache_methods->queue_authentic_pixels_handler;
4413 if (cache_methods->sync_authentic_pixels_handler !=
4414 (SyncAuthenticPixelsHandler) NULL)
4415 cache_info->methods.sync_authentic_pixels_handler=
4416 cache_methods->sync_authentic_pixels_handler;
4417 if (cache_methods->get_authentic_pixels_from_handler !=
4418 (GetAuthenticPixelsFromHandler) NULL)
4419 cache_info->methods.get_authentic_pixels_from_handler=
4420 cache_methods->get_authentic_pixels_from_handler;
4421 if (cache_methods->get_authentic_metacontent_from_handler !=
4422 (GetAuthenticMetacontentFromHandler) NULL)
4423 cache_info->methods.get_authentic_metacontent_from_handler=
4424 cache_methods->get_authentic_metacontent_from_handler;
4425 get_one_virtual_pixel_from_handler=
4426 cache_info->methods.get_one_virtual_pixel_from_handler;
4427 if (get_one_virtual_pixel_from_handler !=
4428 (GetOneVirtualPixelFromHandler) NULL)
4429 cache_info->methods.get_one_virtual_pixel_from_handler=
4430 cache_methods->get_one_virtual_pixel_from_handler;
4431 get_one_authentic_pixel_from_handler=
4432 cache_methods->get_one_authentic_pixel_from_handler;
4433 if (get_one_authentic_pixel_from_handler !=
4434 (GetOneAuthenticPixelFromHandler) NULL)
4435 cache_info->methods.get_one_authentic_pixel_from_handler=
4436 cache_methods->get_one_authentic_pixel_from_handler;
4440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4444 + S e t P i x e l C a c h e N e x u s P i x e l s %
4448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4450 % SetPixelCacheNexusPixels() defines the region of the cache for the
4451 % specified cache nexus.
4453 % The format of the SetPixelCacheNexusPixels() method is:
4455 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4456 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4457 % ExceptionInfo *exception)
4459 % A description of each parameter follows:
4461 % o cache_info: the pixel cache.
4463 % o mode: ReadMode, WriteMode, or IOMode.
4465 % o region: A pointer to the RectangleInfo structure that defines the
4466 % region of this particular cache nexus.
4468 % o nexus_info: the cache nexus to set.
4470 % o exception: return any errors or warnings in this structure.
4474 static inline MagickBooleanType AcquireCacheNexusPixels(
4475 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4476 ExceptionInfo *exception)
4478 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4479 return(MagickFalse);
4480 nexus_info->mapped=MagickFalse;
4481 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4482 (size_t) nexus_info->length));
4483 if (nexus_info->cache == (Quantum *) NULL)
4485 nexus_info->mapped=MagickTrue;
4486 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4487 nexus_info->length);
4489 if (nexus_info->cache == (Quantum *) NULL)
4491 (void) ThrowMagickException(exception,GetMagickModule(),
4492 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4493 cache_info->filename);
4494 return(MagickFalse);
4499 static inline MagickBooleanType IsPixelCacheAuthentic(
4500 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4509 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4511 if (cache_info->type == PingCache)
4513 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4514 nexus_info->region.x;
4515 status=nexus_info->pixels == (cache_info->pixels+offset*
4516 cache_info->number_channels) ? MagickTrue : MagickFalse;
4520 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4523 if (mode == ReadMode)
4525 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4528 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4531 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4532 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4533 ExceptionInfo *exception)
4542 assert(cache_info != (const CacheInfo *) NULL);
4543 assert(cache_info->signature == MagickSignature);
4544 if (cache_info->type == UndefinedCache)
4545 return((Quantum *) NULL);
4546 nexus_info->region=(*region);
4547 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4553 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4554 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4555 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4556 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4557 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4558 ((nexus_info->region.width == cache_info->columns) ||
4559 ((nexus_info->region.width % cache_info->columns) == 0)))))
4565 Pixels are accessed directly from memory.
4567 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4568 nexus_info->region.x;
4569 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4571 nexus_info->metacontent=(void *) NULL;
4572 if (cache_info->metacontent_extent != 0)
4573 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4574 offset*cache_info->metacontent_extent;
4575 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4576 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4578 return(nexus_info->pixels);
4582 Pixels are stored in a staging region until they are synced to the cache.
4584 number_pixels=(MagickSizeType) nexus_info->region.width*
4585 nexus_info->region.height;
4586 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4587 if (cache_info->metacontent_extent != 0)
4588 length+=number_pixels*cache_info->metacontent_extent;
4589 if (nexus_info->cache == (Quantum *) NULL)
4591 nexus_info->length=length;
4592 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4593 if (status == MagickFalse)
4595 nexus_info->length=0;
4596 return((Quantum *) NULL);
4600 if (nexus_info->length < length)
4602 RelinquishCacheNexusPixels(nexus_info);
4603 nexus_info->length=length;
4604 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4605 if (status == MagickFalse)
4607 nexus_info->length=0;
4608 return((Quantum *) NULL);
4611 nexus_info->pixels=nexus_info->cache;
4612 nexus_info->metacontent=(void *) NULL;
4613 if (cache_info->metacontent_extent != 0)
4614 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4615 cache_info->number_channels);
4616 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4617 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4619 return(nexus_info->pixels);
4623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4627 % 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 %
4631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4633 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4634 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4635 % access that is outside the boundaries of the image cache.
4637 % The format of the SetPixelCacheVirtualMethod() method is:
4639 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4640 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4642 % A description of each parameter follows:
4644 % o image: the image.
4646 % o virtual_pixel_method: choose the type of virtual pixel.
4648 % o exception: return any errors or warnings in this structure.
4652 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4653 ExceptionInfo *exception)
4656 *restrict cache_info;
4659 *restrict image_view;
4667 assert(image != (Image *) NULL);
4668 assert(image->signature == MagickSignature);
4669 if (image->debug != MagickFalse)
4670 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4671 assert(image->cache != (Cache) NULL);
4672 cache_info=(CacheInfo *) image->cache;
4673 assert(cache_info->signature == MagickSignature);
4674 image->alpha_trait=BlendPixelTrait;
4676 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4677 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4678 #pragma omp parallel for schedule(static,4) shared(status) \
4679 magick_threads(image,image,1,1)
4681 for (y=0; y < (ssize_t) image->rows; y++)
4689 if (status == MagickFalse)
4691 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4692 if (q == (Quantum *) NULL)
4697 for (x=0; x < (ssize_t) image->columns; x++)
4699 SetPixelAlpha(image,alpha,q);
4700 q+=GetPixelChannels(image);
4702 status=SyncCacheViewAuthenticPixels(image_view,exception);
4704 image_view=DestroyCacheView(image_view);
4708 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4709 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4712 *restrict cache_info;
4717 assert(image != (Image *) NULL);
4718 assert(image->signature == MagickSignature);
4719 if (image->debug != MagickFalse)
4720 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4721 assert(image->cache != (Cache) NULL);
4722 cache_info=(CacheInfo *) image->cache;
4723 assert(cache_info->signature == MagickSignature);
4724 method=cache_info->virtual_pixel_method;
4725 cache_info->virtual_pixel_method=virtual_pixel_method;
4726 if ((image->columns != 0) && (image->rows != 0))
4727 switch (virtual_pixel_method)
4729 case BackgroundVirtualPixelMethod:
4731 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4732 (image->alpha_trait != BlendPixelTrait))
4733 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4734 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4735 (IsGrayColorspace(image->colorspace) != MagickFalse))
4736 (void) SetImageColorspace(image,sRGBColorspace,exception);
4739 case TransparentVirtualPixelMethod:
4741 if (image->alpha_trait != BlendPixelTrait)
4742 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4756 + 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 %
4760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4762 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4763 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4764 % is synced, otherwise MagickFalse.
4766 % The format of the SyncAuthenticPixelCacheNexus() method is:
4768 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4769 % NexusInfo *nexus_info,ExceptionInfo *exception)
4771 % A description of each parameter follows:
4773 % o image: the image.
4775 % o nexus_info: the cache nexus to sync.
4777 % o exception: return any errors or warnings in this structure.
4780 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4781 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4784 *restrict cache_info;
4790 Transfer pixels to the cache.
4792 assert(image != (Image *) NULL);
4793 assert(image->signature == MagickSignature);
4794 if (image->cache == (Cache) NULL)
4795 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4796 cache_info=(CacheInfo *) image->cache;
4797 assert(cache_info->signature == MagickSignature);
4798 if (cache_info->type == UndefinedCache)
4799 return(MagickFalse);
4800 if (nexus_info->authentic_pixel_cache != MagickFalse)
4802 assert(cache_info->signature == MagickSignature);
4803 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4804 if ((cache_info->metacontent_extent != 0) &&
4805 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4806 return(MagickFalse);
4811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4815 + S y n c A u t h e n t i c P i x e l C a c h e %
4819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4821 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4822 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4823 % otherwise MagickFalse.
4825 % The format of the SyncAuthenticPixelsCache() method is:
4827 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4828 % ExceptionInfo *exception)
4830 % A description of each parameter follows:
4832 % o image: the image.
4834 % o exception: return any errors or warnings in this structure.
4837 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4838 ExceptionInfo *exception)
4841 *restrict cache_info;
4844 id = GetOpenMPThreadId();
4849 assert(image != (Image *) NULL);
4850 assert(image->signature == MagickSignature);
4851 assert(image->cache != (Cache) NULL);
4852 cache_info=(CacheInfo *) image->cache;
4853 assert(cache_info->signature == MagickSignature);
4854 assert(id < (int) cache_info->number_threads);
4855 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865 % S y n c A u t h e n t i c P i x e l s %
4869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4872 % The method returns MagickTrue if the pixel region is flushed, otherwise
4875 % The format of the SyncAuthenticPixels() method is:
4877 % MagickBooleanType SyncAuthenticPixels(Image *image,
4878 % ExceptionInfo *exception)
4880 % A description of each parameter follows:
4882 % o image: the image.
4884 % o exception: return any errors or warnings in this structure.
4887 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4888 ExceptionInfo *exception)
4891 *restrict cache_info;
4894 id = GetOpenMPThreadId();
4899 assert(image != (Image *) NULL);
4900 assert(image->signature == MagickSignature);
4901 assert(image->cache != (Cache) NULL);
4902 cache_info=(CacheInfo *) image->cache;
4903 assert(cache_info->signature == MagickSignature);
4904 if (cache_info->methods.sync_authentic_pixels_handler !=
4905 (SyncAuthenticPixelsHandler) NULL)
4907 status=cache_info->methods.sync_authentic_pixels_handler(image,
4911 assert(id < (int) cache_info->number_threads);
4912 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4922 + S y n c I m a g e P i x e l C a c h e %
4926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4928 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4929 % The method returns MagickTrue if the pixel region is flushed, otherwise
4932 % The format of the SyncImagePixelCache() method is:
4934 % MagickBooleanType SyncImagePixelCache(Image *image,
4935 % ExceptionInfo *exception)
4937 % A description of each parameter follows:
4939 % o image: the image.
4941 % o exception: return any errors or warnings in this structure.
4944 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4945 ExceptionInfo *exception)
4948 *restrict cache_info;
4950 assert(image != (Image *) NULL);
4951 assert(exception != (ExceptionInfo *) NULL);
4952 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4953 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4961 + 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 %
4965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4967 % WritePixelCacheMetacontent() writes the meta-content to the specified region
4968 % of the pixel cache.
4970 % The format of the WritePixelCacheMetacontent() method is:
4972 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4973 % NexusInfo *nexus_info,ExceptionInfo *exception)
4975 % A description of each parameter follows:
4977 % o cache_info: the pixel cache.
4979 % o nexus_info: the cache nexus to write the meta-content.
4981 % o exception: return any errors or warnings in this structure.
4984 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4985 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4995 register const unsigned char
5004 if (cache_info->metacontent_extent == 0)
5005 return(MagickFalse);
5006 if (nexus_info->authentic_pixel_cache != MagickFalse)
5008 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5009 nexus_info->region.x;
5010 length=(MagickSizeType) nexus_info->region.width*
5011 cache_info->metacontent_extent;
5012 extent=(MagickSizeType) length*nexus_info->region.height;
5013 rows=nexus_info->region.height;
5015 p=(unsigned char *) nexus_info->metacontent;
5016 switch (cache_info->type)
5021 register unsigned char
5025 Write associated pixels to memory.
5027 if ((cache_info->columns == nexus_info->region.width) &&
5028 (extent == (MagickSizeType) ((size_t) extent)))
5033 q=(unsigned char *) cache_info->metacontent+offset*
5034 cache_info->metacontent_extent;
5035 for (y=0; y < (ssize_t) rows; y++)
5037 (void) memcpy(q,p,(size_t) length);
5038 p+=nexus_info->region.width*cache_info->metacontent_extent;
5039 q+=cache_info->columns*cache_info->metacontent_extent;
5046 Write associated pixels to disk.
5048 LockSemaphoreInfo(cache_info->file_semaphore);
5049 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5051 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5052 cache_info->cache_filename);
5053 UnlockSemaphoreInfo(cache_info->file_semaphore);
5054 return(MagickFalse);
5056 if ((cache_info->columns == nexus_info->region.width) &&
5057 (extent <= MagickMaxBufferExtent))
5062 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5063 for (y=0; y < (ssize_t) rows; y++)
5065 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5066 cache_info->number_channels*sizeof(Quantum)+offset*
5067 cache_info->metacontent_extent,length,(const unsigned char *) p);
5068 if (count != (MagickOffsetType) length)
5070 p+=cache_info->metacontent_extent*nexus_info->region.width;
5071 offset+=cache_info->columns;
5073 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5074 (void) ClosePixelCacheOnDisk(cache_info);
5075 UnlockSemaphoreInfo(cache_info->file_semaphore);
5078 case DistributedCache:
5084 Write metacontent to distributed cache.
5086 LockSemaphoreInfo(cache_info->file_semaphore);
5087 region=nexus_info->region;
5088 if ((cache_info->columns != nexus_info->region.width) ||
5089 (extent > MagickMaxBufferExtent))
5096 for (y=0; y < (ssize_t) rows; y++)
5098 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5099 cache_info->server_info,®ion,length,(const unsigned char *) p);
5100 if (count != (MagickOffsetType) length)
5102 p+=cache_info->metacontent_extent*nexus_info->region.width;
5105 UnlockSemaphoreInfo(cache_info->file_semaphore);
5111 if (y < (ssize_t) rows)
5113 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5114 cache_info->cache_filename);
5115 return(MagickFalse);
5117 if ((cache_info->debug != MagickFalse) &&
5118 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5119 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5120 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5121 nexus_info->region.width,(double) nexus_info->region.height,(double)
5122 nexus_info->region.x,(double) nexus_info->region.y);
5127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5131 + W r i t e C a c h e P i x e l s %
5135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137 % WritePixelCachePixels() writes image pixels to the specified region of the
5140 % The format of the WritePixelCachePixels() method is:
5142 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5143 % NexusInfo *nexus_info,ExceptionInfo *exception)
5145 % A description of each parameter follows:
5147 % o cache_info: the pixel cache.
5149 % o nexus_info: the cache nexus to write the pixels.
5151 % o exception: return any errors or warnings in this structure.
5154 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5155 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5165 register const Quantum
5174 if (nexus_info->authentic_pixel_cache != MagickFalse)
5176 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5177 nexus_info->region.x;
5178 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5180 extent=length*nexus_info->region.height;
5181 rows=nexus_info->region.height;
5183 p=nexus_info->pixels;
5184 switch (cache_info->type)
5193 Write pixels to memory.
5195 if ((cache_info->columns == nexus_info->region.width) &&
5196 (extent == (MagickSizeType) ((size_t) extent)))
5201 q=cache_info->pixels+offset*cache_info->number_channels;
5202 for (y=0; y < (ssize_t) rows; y++)
5204 (void) memcpy(q,p,(size_t) length);
5205 p+=cache_info->number_channels*nexus_info->region.width;
5206 q+=cache_info->columns*cache_info->number_channels;
5213 Write pixels to disk.
5215 LockSemaphoreInfo(cache_info->file_semaphore);
5216 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5218 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5219 cache_info->cache_filename);
5220 UnlockSemaphoreInfo(cache_info->file_semaphore);
5221 return(MagickFalse);
5223 if ((cache_info->columns == nexus_info->region.width) &&
5224 (extent <= MagickMaxBufferExtent))
5229 for (y=0; y < (ssize_t) rows; y++)
5231 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5232 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5234 if (count != (MagickOffsetType) length)
5236 p+=cache_info->number_channels*nexus_info->region.width;
5237 offset+=cache_info->columns;
5239 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5240 (void) ClosePixelCacheOnDisk(cache_info);
5241 UnlockSemaphoreInfo(cache_info->file_semaphore);
5244 case DistributedCache:
5250 Write pixels to distributed cache.
5252 LockSemaphoreInfo(cache_info->file_semaphore);
5253 region=nexus_info->region;
5254 if ((cache_info->columns != nexus_info->region.width) ||
5255 (extent > MagickMaxBufferExtent))
5262 for (y=0; y < (ssize_t) rows; y++)
5264 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5265 cache_info->server_info,®ion,length,(const unsigned char *) p);
5266 if (count != (MagickOffsetType) length)
5268 p+=cache_info->number_channels*nexus_info->region.width;
5271 UnlockSemaphoreInfo(cache_info->file_semaphore);
5277 if (y < (ssize_t) rows)
5279 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5280 cache_info->cache_filename);
5281 return(MagickFalse);
5283 if ((cache_info->debug != MagickFalse) &&
5284 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5285 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5286 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5287 nexus_info->region.width,(double) nexus_info->region.height,(double)
5288 nexus_info->region.x,(double) nexus_info->region.y);