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-2015 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 OpenPixelCacheOnDisk(CacheInfo *,const MapMode),
123 ReadPixelCachePixels(CacheInfo *restrict,NexusInfo *restrict,ExceptionInfo *),
124 ReadPixelCacheMetacontent(CacheInfo *restrict,NexusInfo *restrict,
126 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
127 WritePixelCachePixels(CacheInfo *restrict,NexusInfo *restrict,
129 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *restrict,ExceptionInfo *);
132 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
133 const size_t,ExceptionInfo *),
134 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
135 const size_t,ExceptionInfo *),
136 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
137 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
139 #if defined(__cplusplus) || defined(c_plusplus)
146 static volatile MagickBooleanType
147 instantiate_cache = MagickFalse;
150 *cache_semaphore = (SemaphoreInfo *) NULL;
153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157 + A c q u i r e P i x e l C a c h e %
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163 % AcquirePixelCache() acquires a pixel cache.
165 % The format of the AcquirePixelCache() method is:
167 % Cache AcquirePixelCache(const size_t number_threads)
169 % A description of each parameter follows:
171 % o number_threads: the number of nexus threads.
174 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
177 *restrict cache_info;
182 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
183 if (cache_info == (CacheInfo *) NULL)
184 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
185 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
186 cache_info->type=UndefinedCache;
187 cache_info->mode=IOMode;
188 cache_info->colorspace=sRGBColorspace;
189 cache_info->file=(-1);
190 cache_info->id=GetMagickThreadId();
191 cache_info->number_threads=number_threads;
192 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
193 cache_info->number_threads=GetOpenMPMaximumThreads();
194 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
195 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
196 if (cache_info->number_threads == 0)
197 cache_info->number_threads=1;
198 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
199 if (cache_info->nexus_info == (NexusInfo **) NULL)
200 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
201 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
202 if (synchronize != (const char *) NULL)
204 cache_info->synchronize=IsStringTrue(synchronize);
205 synchronize=DestroyString(synchronize);
207 cache_info->semaphore=AcquireSemaphoreInfo();
208 cache_info->reference_count=1;
209 cache_info->file_semaphore=AcquireSemaphoreInfo();
210 cache_info->debug=IsEventLogging();
211 cache_info->signature=MagickCoreSignature;
212 return((Cache ) cache_info);
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 % A c q u i r e P i x e l C a c h e N e x u s %
224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
228 % The format of the AcquirePixelCacheNexus method is:
230 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
232 % A description of each parameter follows:
234 % o number_threads: the number of nexus threads.
237 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
240 **restrict nexus_info;
245 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
246 number_threads,sizeof(*nexus_info)));
247 if (nexus_info == (NexusInfo **) NULL)
248 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
249 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
250 sizeof(**nexus_info));
251 if (nexus_info[0] == (NexusInfo *) NULL)
252 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
253 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
254 for (i=0; i < (ssize_t) number_threads; i++)
256 nexus_info[i]=(&nexus_info[0][i]);
257 nexus_info[i]->signature=MagickCoreSignature;
263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267 + A c q u i r e P i x e l C a c h e P i x e l s %
271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273 % AcquirePixelCachePixels() returns the pixels associated with the specified
276 % The format of the AcquirePixelCachePixels() method is:
278 % const void *AcquirePixelCachePixels(const Image *image,
279 % MagickSizeType *length,ExceptionInfo *exception)
281 % A description of each parameter follows:
283 % o image: the image.
285 % o length: the pixel cache length.
287 % o exception: return any errors or warnings in this structure.
290 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
291 MagickSizeType *length,ExceptionInfo *exception)
294 *restrict cache_info;
296 assert(image != (const Image *) NULL);
297 assert(image->signature == MagickCoreSignature);
298 assert(exception != (ExceptionInfo *) NULL);
299 assert(exception->signature == MagickCoreSignature);
300 assert(image->cache != (Cache) NULL);
301 cache_info=(CacheInfo *) image->cache;
302 assert(cache_info->signature == MagickCoreSignature);
304 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
305 return((const void *) NULL);
306 *length=cache_info->length;
307 return((const void *) cache_info->pixels);
311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315 + C a c h e C o m p o n e n t G e n e s i s %
319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321 % CacheComponentGenesis() instantiates the cache component.
323 % The format of the CacheComponentGenesis method is:
325 % MagickBooleanType CacheComponentGenesis(void)
328 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
330 if (cache_semaphore == (SemaphoreInfo *) NULL)
331 cache_semaphore=AcquireSemaphoreInfo();
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 + C a c h e C o m p o n e n t T e r m i n u s %
344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 % CacheComponentTerminus() destroys the cache component.
348 % The format of the CacheComponentTerminus() method is:
350 % CacheComponentTerminus(void)
353 MagickPrivate void CacheComponentTerminus(void)
355 if (cache_semaphore == (SemaphoreInfo *) NULL)
356 ActivateSemaphoreInfo(&cache_semaphore);
357 LockSemaphoreInfo(cache_semaphore);
358 instantiate_cache=MagickFalse;
359 UnlockSemaphoreInfo(cache_semaphore);
360 RelinquishSemaphoreInfo(&cache_semaphore);
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
368 + C l o n e P i x e l C a c h e %
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 % ClonePixelCache() clones a pixel cache.
376 % The format of the ClonePixelCache() method is:
378 % Cache ClonePixelCache(const Cache cache)
380 % A description of each parameter follows:
382 % o cache: the pixel cache.
385 MagickPrivate Cache ClonePixelCache(const Cache cache)
388 *restrict clone_info;
391 *restrict cache_info;
393 assert(cache != NULL);
394 cache_info=(const CacheInfo *) cache;
395 assert(cache_info->signature == MagickCoreSignature);
396 if (cache_info->debug != MagickFalse)
397 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
398 cache_info->filename);
399 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
400 if (clone_info == (Cache) NULL)
401 return((Cache) NULL);
402 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
403 return((Cache ) clone_info);
407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 + C l o n e P i x e l C a c h e M e t h o d s %
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
420 % The format of the ClonePixelCacheMethods() method is:
422 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
424 % A description of each parameter follows:
426 % o clone: Specifies a pointer to a Cache structure.
428 % o cache: the pixel cache.
431 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
434 *restrict cache_info,
435 *restrict source_info;
437 assert(clone != (Cache) NULL);
438 source_info=(CacheInfo *) clone;
439 assert(source_info->signature == MagickCoreSignature);
440 if (source_info->debug != MagickFalse)
441 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
442 source_info->filename);
443 assert(cache != (Cache) NULL);
444 cache_info=(CacheInfo *) cache;
445 assert(cache_info->signature == MagickCoreSignature);
446 source_info->methods=cache_info->methods;
450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 + 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 %
458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
459 % ClonePixelCacheRepository() clones the source pixel cache to the destination
462 % The format of the ClonePixelCacheRepository() method is:
464 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
465 % CacheInfo *source_info,ExceptionInfo *exception)
467 % A description of each parameter follows:
469 % o cache_info: the pixel cache.
471 % o source_info: the source pixel cache.
473 % o exception: return any errors or warnings in this structure.
477 static MagickBooleanType ClonePixelCacheOnDisk(CacheInfo *restrict cache_info,
478 CacheInfo *restrict clone_info,ExceptionInfo *exception)
496 Clone pixel cache on disk with identifcal morphology.
498 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
499 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
501 quantum=(size_t) MagickMaxBufferExtent;
502 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
503 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
504 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
505 if (buffer == (unsigned char *) NULL)
506 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
508 while ((count=read(cache_info->file,buffer,quantum)) > 0)
513 number_bytes=write(clone_info->file,buffer,(size_t) count);
514 if (number_bytes != count)
516 extent+=number_bytes;
518 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
519 if (extent != cache_info->length)
524 static MagickBooleanType ClonePixelCacheRepository(
525 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
526 ExceptionInfo *exception)
528 #define MaxCacheThreads 2
529 #define cache_threads(source,destination,chunk) \
530 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
531 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
532 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
539 **restrict cache_nexus,
540 **restrict clone_nexus;
548 assert(cache_info != (CacheInfo *) NULL);
549 assert(clone_info != (CacheInfo *) NULL);
550 assert(exception != (ExceptionInfo *) NULL);
551 if (cache_info->type == PingCache)
553 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
554 if ((cache_info->columns == clone_info->columns) &&
555 (cache_info->rows == clone_info->rows) &&
556 (cache_info->number_channels == clone_info->number_channels) &&
557 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
558 (cache_info->metacontent_extent == clone_info->metacontent_extent))
561 Identical pixel cache morphology.
563 if (((cache_info->type == MemoryCache) ||
564 (cache_info->type == MapCache)) &&
565 ((clone_info->type == MemoryCache) ||
566 (clone_info->type == MapCache)))
568 (void) memcpy(clone_info->pixels,cache_info->pixels,
569 cache_info->columns*cache_info->number_channels*cache_info->rows*
570 sizeof(*cache_info->pixels));
571 if ((cache_info->metacontent_extent != 0) &&
572 (clone_info->metacontent_extent != 0))
573 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
574 cache_info->columns*cache_info->rows*
575 clone_info->metacontent_extent*sizeof(unsigned char));
578 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
579 return(ClonePixelCacheOnDisk(cache_info,clone_info,exception));
582 Mismatched pixel cache morphology.
584 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
585 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
586 if ((cache_nexus == (NexusInfo **) NULL) ||
587 (clone_nexus == (NexusInfo **) NULL))
588 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
589 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
590 optimize=(cache_info->number_channels == clone_info->number_channels) &&
591 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
592 MagickTrue : MagickFalse;
593 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
594 clone_info->columns*clone_info->number_channels);
596 #if defined(MAGICKCORE_OPENMP_SUPPORT)
597 #pragma omp parallel for schedule(static,4) shared(status) \
598 cache_threads(cache_info,clone_info,cache_info->rows)
600 for (y=0; y < (ssize_t) cache_info->rows; y++)
603 id = GetOpenMPThreadId();
614 if (status == MagickFalse)
616 if (y >= (ssize_t) clone_info->rows)
618 region.width=cache_info->columns;
622 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
624 if (pixels == (Quantum *) NULL)
626 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
627 if (status == MagickFalse)
629 region.width=clone_info->columns;
630 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
631 clone_nexus[id],exception);
632 if (pixels == (Quantum *) NULL)
634 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
635 clone_nexus[id]->length);
636 if (optimize != MagickFalse)
637 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
641 register const Quantum
648 Mismatched pixel channel map.
650 p=cache_nexus[id]->pixels;
651 q=clone_nexus[id]->pixels;
652 for (x=0; x < (ssize_t) cache_info->columns; x++)
657 if (x == (ssize_t) clone_info->columns)
659 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
667 channel=clone_info->channel_map[i].channel;
668 traits=cache_info->channel_map[channel].traits;
669 if (traits != UndefinedPixelTrait)
670 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
674 p+=cache_info->number_channels;
677 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
679 if ((cache_info->metacontent_extent != 0) &&
680 (clone_info->metacontent_extent != 0))
685 length=(size_t) MagickMin(cache_info->metacontent_extent,
686 clone_info->metacontent_extent);
687 #if defined(MAGICKCORE_OPENMP_SUPPORT)
688 #pragma omp parallel for schedule(static,4) shared(status) \
689 cache_threads(cache_info,clone_info,cache_info->rows)
691 for (y=0; y < (ssize_t) cache_info->rows; y++)
694 id = GetOpenMPThreadId();
702 if (status == MagickFalse)
704 if (y >= (ssize_t) clone_info->rows)
706 region.width=cache_info->columns;
710 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
711 cache_nexus[id],exception);
712 if (pixels == (Quantum *) NULL)
714 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
715 if (status == MagickFalse)
717 region.width=clone_info->columns;
718 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
719 clone_nexus[id],exception);
720 if (pixels == (Quantum *) NULL)
722 if ((clone_nexus[id]->metacontent != (void *) NULL) &&
723 (cache_nexus[id]->metacontent != (void *) NULL))
724 (void) memcpy(clone_nexus[id]->metacontent,
725 cache_nexus[id]->metacontent,length*sizeof(unsigned char));
726 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
729 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
730 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
731 if (cache_info->debug != MagickFalse)
734 message[MagickPathExtent];
736 (void) FormatLocaleString(message,MagickPathExtent,"%s => %s",
737 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
738 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
739 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
749 + D e s t r o y I m a g e P i x e l C a c h e %
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
757 % The format of the DestroyImagePixelCache() method is:
759 % void DestroyImagePixelCache(Image *image)
761 % A description of each parameter follows:
763 % o image: the image.
766 static void DestroyImagePixelCache(Image *image)
768 assert(image != (Image *) NULL);
769 assert(image->signature == MagickCoreSignature);
770 if (image->debug != MagickFalse)
771 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
772 if (image->cache == (void *) NULL)
774 image->cache=DestroyPixelCache(image->cache);
778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782 + D e s t r o y I m a g e P i x e l s %
786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788 % DestroyImagePixels() deallocates memory associated with the pixel cache.
790 % The format of the DestroyImagePixels() method is:
792 % void DestroyImagePixels(Image *image)
794 % A description of each parameter follows:
796 % o image: the image.
799 MagickExport void DestroyImagePixels(Image *image)
802 *restrict cache_info;
804 assert(image != (const Image *) NULL);
805 assert(image->signature == MagickCoreSignature);
806 if (image->debug != MagickFalse)
807 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
808 assert(image->cache != (Cache) NULL);
809 cache_info=(CacheInfo *) image->cache;
810 assert(cache_info->signature == MagickCoreSignature);
811 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
813 cache_info->methods.destroy_pixel_handler(image);
816 image->cache=DestroyPixelCache(image->cache);
820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824 + D e s t r o y P i x e l C a c h e %
828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
830 % DestroyPixelCache() deallocates memory associated with the pixel cache.
832 % The format of the DestroyPixelCache() method is:
834 % Cache DestroyPixelCache(Cache cache)
836 % A description of each parameter follows:
838 % o cache: the pixel cache.
842 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
848 if (cache_info->file != -1)
850 status=close(cache_info->file);
851 cache_info->file=(-1);
852 RelinquishMagickResource(FileResource,1);
854 return(status == -1 ? MagickFalse : MagickTrue);
857 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
859 switch (cache_info->type)
863 if (cache_info->mapped == MagickFalse)
864 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
868 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
869 cache_info->pixels=(Quantum *) NULL;
871 RelinquishMagickResource(MemoryResource,cache_info->length);
876 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
877 cache_info->pixels=(Quantum *) NULL;
878 if (cache_info->mode != ReadMode)
879 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
880 *cache_info->cache_filename='\0';
881 RelinquishMagickResource(MapResource,cache_info->length);
885 if (cache_info->file != -1)
886 (void) ClosePixelCacheOnDisk(cache_info);
887 if (cache_info->mode != ReadMode)
888 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
889 *cache_info->cache_filename='\0';
890 RelinquishMagickResource(DiskResource,cache_info->length);
893 case DistributedCache:
895 *cache_info->cache_filename='\0';
896 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
897 cache_info->server_info);
903 cache_info->type=UndefinedCache;
904 cache_info->mapped=MagickFalse;
905 cache_info->metacontent=(void *) NULL;
908 MagickPrivate Cache DestroyPixelCache(Cache cache)
911 *restrict cache_info;
913 assert(cache != (Cache) NULL);
914 cache_info=(CacheInfo *) cache;
915 assert(cache_info->signature == MagickCoreSignature);
916 if (cache_info->debug != MagickFalse)
917 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
918 cache_info->filename);
919 LockSemaphoreInfo(cache_info->semaphore);
920 cache_info->reference_count--;
921 if (cache_info->reference_count != 0)
923 UnlockSemaphoreInfo(cache_info->semaphore);
924 return((Cache) NULL);
926 UnlockSemaphoreInfo(cache_info->semaphore);
927 if (cache_info->debug != MagickFalse)
930 message[MagickPathExtent];
932 (void) FormatLocaleString(message,MagickPathExtent,"destroy %s",
933 cache_info->filename);
934 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
936 RelinquishPixelCachePixels(cache_info);
937 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
938 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
939 cache_info->server_info);
940 if (cache_info->nexus_info != (NexusInfo **) NULL)
941 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
942 cache_info->number_threads);
943 if (cache_info->random_info != (RandomInfo *) NULL)
944 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
945 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
946 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
947 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
948 RelinquishSemaphoreInfo(&cache_info->semaphore);
949 cache_info->signature=(~MagickCoreSignature);
950 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
960 + D e s t r o y P i x e l C a c h e N e x u s %
964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
968 % The format of the DestroyPixelCacheNexus() method is:
970 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
971 % const size_t number_threads)
973 % A description of each parameter follows:
975 % o nexus_info: the nexus to destroy.
977 % o number_threads: the number of nexus threads.
981 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
983 if (nexus_info->mapped == MagickFalse)
984 (void) RelinquishAlignedMemory(nexus_info->cache);
986 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
987 nexus_info->cache=(Quantum *) NULL;
988 nexus_info->pixels=(Quantum *) NULL;
989 nexus_info->metacontent=(void *) NULL;
990 nexus_info->length=0;
991 nexus_info->mapped=MagickFalse;
994 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
995 const size_t number_threads)
1000 assert(nexus_info != (NexusInfo **) NULL);
1001 for (i=0; i < (ssize_t) number_threads; i++)
1003 if (nexus_info[i]->cache != (Quantum *) NULL)
1004 RelinquishCacheNexusPixels(nexus_info[i]);
1005 nexus_info[i]->signature=(~MagickCoreSignature);
1007 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1008 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1017 % G e t A u t h e n t i c M e t a c o n t e n t %
1021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1023 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1024 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1025 % returned if the associated pixels are not available.
1027 % The format of the GetAuthenticMetacontent() method is:
1029 % void *GetAuthenticMetacontent(const Image *image)
1031 % A description of each parameter follows:
1033 % o image: the image.
1036 MagickExport void *GetAuthenticMetacontent(const Image *image)
1039 *restrict cache_info;
1042 id = GetOpenMPThreadId();
1044 assert(image != (const Image *) NULL);
1045 assert(image->signature == MagickCoreSignature);
1046 assert(image->cache != (Cache) NULL);
1047 cache_info=(CacheInfo *) image->cache;
1048 assert(cache_info->signature == MagickCoreSignature);
1049 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1050 (GetAuthenticMetacontentFromHandler) NULL)
1055 metacontent=cache_info->methods.
1056 get_authentic_metacontent_from_handler(image);
1057 return(metacontent);
1059 assert(id < (int) cache_info->number_threads);
1060 return(cache_info->nexus_info[id]->metacontent);
1064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1068 + 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 %
1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1074 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1075 % with the last call to QueueAuthenticPixelsCache() or
1076 % GetAuthenticPixelsCache().
1078 % The format of the GetAuthenticMetacontentFromCache() method is:
1080 % void *GetAuthenticMetacontentFromCache(const Image *image)
1082 % A description of each parameter follows:
1084 % o image: the image.
1087 static void *GetAuthenticMetacontentFromCache(const Image *image)
1090 *restrict cache_info;
1093 id = GetOpenMPThreadId();
1095 assert(image != (const Image *) NULL);
1096 assert(image->signature == MagickCoreSignature);
1097 assert(image->cache != (Cache) NULL);
1098 cache_info=(CacheInfo *) image->cache;
1099 assert(cache_info->signature == MagickCoreSignature);
1100 assert(id < (int) cache_info->number_threads);
1101 return(cache_info->nexus_info[id]->metacontent);
1105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109 + 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 %
1113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1116 % disk pixel cache as defined by the geometry parameters. A pointer to the
1117 % pixels is returned if the pixels are transferred, otherwise a NULL is
1120 % The format of the GetAuthenticPixelCacheNexus() method is:
1122 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1123 % const ssize_t y,const size_t columns,const size_t rows,
1124 % NexusInfo *nexus_info,ExceptionInfo *exception)
1126 % A description of each parameter follows:
1128 % o image: the image.
1130 % o x,y,columns,rows: These values define the perimeter of a region of
1133 % o nexus_info: the cache nexus to return.
1135 % o exception: return any errors or warnings in this structure.
1139 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1140 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1141 ExceptionInfo *exception)
1144 *restrict cache_info;
1150 Transfer pixels from the cache.
1152 assert(image != (Image *) NULL);
1153 assert(image->signature == MagickCoreSignature);
1154 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1155 nexus_info,exception);
1156 if (pixels == (Quantum *) NULL)
1157 return((Quantum *) NULL);
1158 cache_info=(CacheInfo *) image->cache;
1159 assert(cache_info->signature == MagickCoreSignature);
1160 if (nexus_info->authentic_pixel_cache != MagickFalse)
1162 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1163 return((Quantum *) NULL);
1164 if (cache_info->metacontent_extent != 0)
1165 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1166 return((Quantum *) NULL);
1171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1175 + 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 %
1179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1181 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1182 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1184 % The format of the GetAuthenticPixelsFromCache() method is:
1186 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1188 % A description of each parameter follows:
1190 % o image: the image.
1193 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1196 *restrict cache_info;
1199 id = GetOpenMPThreadId();
1201 assert(image != (const Image *) NULL);
1202 assert(image->signature == MagickCoreSignature);
1203 assert(image->cache != (Cache) NULL);
1204 cache_info=(CacheInfo *) image->cache;
1205 assert(cache_info->signature == MagickCoreSignature);
1206 assert(id < (int) cache_info->number_threads);
1207 return(cache_info->nexus_info[id]->pixels);
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215 % G e t A u t h e n t i c P i x e l Q u e u e %
1219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1221 % GetAuthenticPixelQueue() returns the authentic pixels associated
1222 % corresponding with the last call to QueueAuthenticPixels() or
1223 % GetAuthenticPixels().
1225 % The format of the GetAuthenticPixelQueue() method is:
1227 % Quantum *GetAuthenticPixelQueue(const Image image)
1229 % A description of each parameter follows:
1231 % o image: the image.
1234 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1237 *restrict cache_info;
1240 id = GetOpenMPThreadId();
1242 assert(image != (const Image *) NULL);
1243 assert(image->signature == MagickCoreSignature);
1244 assert(image->cache != (Cache) NULL);
1245 cache_info=(CacheInfo *) image->cache;
1246 assert(cache_info->signature == MagickCoreSignature);
1247 if (cache_info->methods.get_authentic_pixels_from_handler !=
1248 (GetAuthenticPixelsFromHandler) NULL)
1249 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1250 assert(id < (int) cache_info->number_threads);
1251 return(cache_info->nexus_info[id]->pixels);
1255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1259 % G e t A u t h e n t i c P i x e l s %
1262 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1265 % region is successfully accessed, a pointer to a Quantum array
1266 % representing the region is returned, otherwise NULL is returned.
1268 % The returned pointer may point to a temporary working copy of the pixels
1269 % or it may point to the original pixels in memory. Performance is maximized
1270 % if the selected region is part of one row, or one or more full rows, since
1271 % then there is opportunity to access the pixels in-place (without a copy)
1272 % if the image is in memory, or in a memory-mapped file. The returned pointer
1273 % must *never* be deallocated by the user.
1275 % Pixels accessed via the returned pointer represent a simple array of type
1276 % Quantum. If the image has corresponding metacontent,call
1277 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1278 % meta-content corresponding to the region. Once the Quantum array has
1279 % been updated, the changes must be saved back to the underlying image using
1280 % SyncAuthenticPixels() or they may be lost.
1282 % The format of the GetAuthenticPixels() method is:
1284 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1285 % const ssize_t y,const size_t columns,const size_t rows,
1286 % ExceptionInfo *exception)
1288 % A description of each parameter follows:
1290 % o image: the image.
1292 % o x,y,columns,rows: These values define the perimeter of a region of
1295 % o exception: return any errors or warnings in this structure.
1298 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1299 const ssize_t y,const size_t columns,const size_t rows,
1300 ExceptionInfo *exception)
1303 *restrict cache_info;
1306 id = GetOpenMPThreadId();
1311 assert(image != (Image *) NULL);
1312 assert(image->signature == MagickCoreSignature);
1313 assert(image->cache != (Cache) NULL);
1314 cache_info=(CacheInfo *) image->cache;
1315 assert(cache_info->signature == MagickCoreSignature);
1316 if (cache_info->methods.get_authentic_pixels_handler !=
1317 (GetAuthenticPixelsHandler) NULL)
1319 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1323 assert(id < (int) cache_info->number_threads);
1324 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1325 cache_info->nexus_info[id],exception);
1330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334 + G e t A u t h e n t i c P i x e l s C a c h e %
1338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1341 % as defined by the geometry parameters. A pointer to the pixels is returned
1342 % if the pixels are transferred, otherwise a NULL is returned.
1344 % The format of the GetAuthenticPixelsCache() method is:
1346 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1347 % const ssize_t y,const size_t columns,const size_t rows,
1348 % ExceptionInfo *exception)
1350 % A description of each parameter follows:
1352 % o image: the image.
1354 % o x,y,columns,rows: These values define the perimeter of a region of
1357 % o exception: return any errors or warnings in this structure.
1360 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1361 const ssize_t y,const size_t columns,const size_t rows,
1362 ExceptionInfo *exception)
1365 *restrict cache_info;
1368 id = GetOpenMPThreadId();
1373 assert(image != (const Image *) NULL);
1374 assert(image->signature == MagickCoreSignature);
1375 assert(image->cache != (Cache) NULL);
1376 cache_info=(CacheInfo *) image->cache;
1377 if (cache_info == (Cache) NULL)
1378 return((Quantum *) NULL);
1379 assert(cache_info->signature == MagickCoreSignature);
1380 assert(id < (int) cache_info->number_threads);
1381 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1382 cache_info->nexus_info[id],exception);
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391 + G e t I m a g e E x t e n t %
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1397 % GetImageExtent() returns the extent of the pixels associated corresponding
1398 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1400 % The format of the GetImageExtent() method is:
1402 % MagickSizeType GetImageExtent(const Image *image)
1404 % A description of each parameter follows:
1406 % o image: the image.
1409 MagickExport MagickSizeType GetImageExtent(const Image *image)
1412 *restrict cache_info;
1415 id = GetOpenMPThreadId();
1417 assert(image != (Image *) NULL);
1418 assert(image->signature == MagickCoreSignature);
1419 if (image->debug != MagickFalse)
1420 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1421 assert(image->cache != (Cache) NULL);
1422 cache_info=(CacheInfo *) image->cache;
1423 assert(cache_info->signature == MagickCoreSignature);
1424 assert(id < (int) cache_info->number_threads);
1425 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433 + G e t I m a g e P i x e l C a c h e %
1437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1439 % GetImagePixelCache() ensures that there is only a single reference to the
1440 % pixel cache to be modified, updating the provided cache pointer to point to
1441 % a clone of the original pixel cache if necessary.
1443 % The format of the GetImagePixelCache method is:
1445 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1446 % ExceptionInfo *exception)
1448 % A description of each parameter follows:
1450 % o image: the image.
1452 % o clone: any value other than MagickFalse clones the cache pixels.
1454 % o exception: return any errors or warnings in this structure.
1458 static inline MagickBooleanType ValidatePixelCacheMorphology(
1459 const Image *restrict image)
1462 *restrict cache_info;
1464 const PixelChannelMap
1469 Does the image match the pixel cache morphology?
1471 cache_info=(CacheInfo *) image->cache;
1472 p=image->channel_map;
1473 q=cache_info->channel_map;
1474 if ((image->storage_class != cache_info->storage_class) ||
1475 (image->colorspace != cache_info->colorspace) ||
1476 (image->alpha_trait != cache_info->alpha_trait) ||
1477 (image->read_mask != cache_info->read_mask) ||
1478 (image->write_mask != cache_info->write_mask) ||
1479 (image->columns != cache_info->columns) ||
1480 (image->rows != cache_info->rows) ||
1481 (image->number_channels != cache_info->number_channels) ||
1482 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1483 (image->metacontent_extent != cache_info->metacontent_extent) ||
1484 (cache_info->nexus_info == (NexusInfo **) NULL))
1485 return(MagickFalse);
1489 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1490 ExceptionInfo *exception)
1493 *restrict cache_info;
1499 static MagickSizeType
1500 cpu_throttle = MagickResourceInfinity,
1505 cache_timestamp = 0;
1508 if (cpu_throttle == MagickResourceInfinity)
1509 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1510 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1511 MagickDelay(cpu_throttle);
1512 if (time_limit == 0)
1515 Set the expire time in seconds.
1517 time_limit=GetMagickResourceLimit(TimeResource);
1518 cache_timestamp=time((time_t *) NULL);
1520 if ((time_limit != MagickResourceInfinity) &&
1521 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1523 #if defined(ECANCELED)
1526 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1528 LockSemaphoreInfo(image->semaphore);
1529 assert(image->cache != (Cache) NULL);
1530 cache_info=(CacheInfo *) image->cache;
1531 destroy=MagickFalse;
1532 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1534 LockSemaphoreInfo(cache_info->semaphore);
1535 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1546 clone_image=(*image);
1547 clone_image.semaphore=AcquireSemaphoreInfo();
1548 clone_image.reference_count=1;
1549 clone_image.cache=ClonePixelCache(cache_info);
1550 clone_info=(CacheInfo *) clone_image.cache;
1551 status=OpenPixelCache(&clone_image,IOMode,exception);
1552 if (status != MagickFalse)
1554 if (clone != MagickFalse)
1555 status=ClonePixelCacheRepository(clone_info,cache_info,
1557 if (status != MagickFalse)
1559 if (cache_info->reference_count == 1)
1560 cache_info->nexus_info=(NexusInfo **) NULL;
1562 image->cache=clone_image.cache;
1565 RelinquishSemaphoreInfo(&clone_image.semaphore);
1567 UnlockSemaphoreInfo(cache_info->semaphore);
1569 if (destroy != MagickFalse)
1570 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1571 if (status != MagickFalse)
1574 Ensure the image matches the pixel cache morphology.
1576 image->type=UndefinedType;
1577 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1579 status=OpenPixelCache(image,IOMode,exception);
1580 cache_info=(CacheInfo *) image->cache;
1581 if (cache_info->type == DiskCache)
1582 (void) ClosePixelCacheOnDisk(cache_info);
1585 UnlockSemaphoreInfo(image->semaphore);
1586 if (status == MagickFalse)
1587 return((Cache) NULL);
1588 return(image->cache);
1592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 + G e t I m a g e P i x e l C a c h e T y p e %
1600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1603 % DiskCache, MemoryCache, MapCache, or PingCache.
1605 % The format of the GetImagePixelCacheType() method is:
1607 % CacheType GetImagePixelCacheType(const Image *image)
1609 % A description of each parameter follows:
1611 % o image: the image.
1614 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1617 *restrict cache_info;
1619 assert(image != (Image *) NULL);
1620 assert(image->signature == MagickCoreSignature);
1621 assert(image->cache != (Cache) NULL);
1622 cache_info=(CacheInfo *) image->cache;
1623 assert(cache_info->signature == MagickCoreSignature);
1624 return(cache_info->type);
1628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632 % G e t O n e A u t h e n t i c P i x e l %
1636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1639 % location. The image background color is returned if an error occurs.
1641 % The format of the GetOneAuthenticPixel() method is:
1643 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1644 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1646 % A description of each parameter follows:
1648 % o image: the image.
1650 % o x,y: These values define the location of the pixel to return.
1652 % o pixel: return a pixel at the specified (x,y) location.
1654 % o exception: return any errors or warnings in this structure.
1658 static inline MagickBooleanType CopyPixel(const Image *image,const Quantum *source,
1659 Quantum *destination)
1664 if (source == (const Quantum *) NULL)
1666 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1667 destination[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1668 destination[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1669 destination[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1670 destination[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1671 return(MagickFalse);
1673 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1675 PixelChannel channel=GetPixelChannelChannel(image,i);
1676 destination[channel]=source[i];
1681 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1682 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1685 *restrict cache_info;
1690 assert(image != (Image *) NULL);
1691 assert(image->signature == MagickCoreSignature);
1692 assert(image->cache != (Cache) NULL);
1693 cache_info=(CacheInfo *) image->cache;
1694 assert(cache_info->signature == MagickCoreSignature);
1695 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1696 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1697 (GetOneAuthenticPixelFromHandler) NULL)
1698 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1700 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1701 return(CopyPixel(image,q,pixel));
1705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1709 + 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 %
1713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1716 % location. The image background color is returned if an error occurs.
1718 % The format of the GetOneAuthenticPixelFromCache() method is:
1720 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1721 % const ssize_t x,const ssize_t y,Quantum *pixel,
1722 % ExceptionInfo *exception)
1724 % A description of each parameter follows:
1726 % o image: the image.
1728 % o x,y: These values define the location of the pixel to return.
1730 % o pixel: return a pixel at the specified (x,y) location.
1732 % o exception: return any errors or warnings in this structure.
1735 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1736 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1739 *restrict cache_info;
1742 id = GetOpenMPThreadId();
1747 assert(image != (const Image *) NULL);
1748 assert(image->signature == MagickCoreSignature);
1749 assert(image->cache != (Cache) NULL);
1750 cache_info=(CacheInfo *) image->cache;
1751 assert(cache_info->signature == MagickCoreSignature);
1752 assert(id < (int) cache_info->number_threads);
1753 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1754 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1756 return(CopyPixel(image,q,pixel));
1760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764 % G e t O n e V i r t u a l P i x e l %
1768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1771 % (x,y) location. The image background color is returned if an error occurs.
1772 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1774 % The format of the GetOneVirtualPixel() method is:
1776 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1777 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1779 % A description of each parameter follows:
1781 % o image: the image.
1783 % o x,y: These values define the location of the pixel to return.
1785 % o pixel: return a pixel at the specified (x,y) location.
1787 % o exception: return any errors or warnings in this structure.
1790 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1791 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1794 *restrict cache_info;
1797 id = GetOpenMPThreadId();
1802 assert(image != (const Image *) NULL);
1803 assert(image->signature == MagickCoreSignature);
1804 assert(image->cache != (Cache) NULL);
1805 cache_info=(CacheInfo *) image->cache;
1806 assert(cache_info->signature == MagickCoreSignature);
1807 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1808 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1809 (GetOneVirtualPixelFromHandler) NULL)
1810 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1811 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1812 assert(id < (int) cache_info->number_threads);
1813 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1814 1UL,1UL,cache_info->nexus_info[id],exception);
1815 return(CopyPixel(image,p,pixel));
1819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1823 + 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 %
1827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1829 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1830 % specified (x,y) location. The image background color is returned if an
1833 % The format of the GetOneVirtualPixelFromCache() method is:
1835 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1836 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1837 % Quantum *pixel,ExceptionInfo *exception)
1839 % A description of each parameter follows:
1841 % o image: the image.
1843 % o virtual_pixel_method: the virtual pixel method.
1845 % o x,y: These values define the location of the pixel to return.
1847 % o pixel: return a pixel at the specified (x,y) location.
1849 % o exception: return any errors or warnings in this structure.
1852 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1853 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1854 Quantum *pixel,ExceptionInfo *exception)
1857 *restrict cache_info;
1860 id = GetOpenMPThreadId();
1865 assert(image != (const Image *) NULL);
1866 assert(image->signature == MagickCoreSignature);
1867 assert(image->cache != (Cache) NULL);
1868 cache_info=(CacheInfo *) image->cache;
1869 assert(cache_info->signature == MagickCoreSignature);
1870 assert(id < (int) cache_info->number_threads);
1871 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1872 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1873 cache_info->nexus_info[id],exception);
1874 return(CopyPixel(image,p,pixel));
1878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1882 % G e t O n e V i r t u a l P i x e l I n f o %
1886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1888 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1889 % location. The image background color is returned if an error occurs. If
1890 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1892 % The format of the GetOneVirtualPixelInfo() method is:
1894 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1895 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1896 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1898 % A description of each parameter follows:
1900 % o image: the image.
1902 % o virtual_pixel_method: the virtual pixel method.
1904 % o x,y: these values define the location of the pixel to return.
1906 % o pixel: return a pixel at the specified (x,y) location.
1908 % o exception: return any errors or warnings in this structure.
1911 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1912 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1913 PixelInfo *pixel,ExceptionInfo *exception)
1916 *restrict cache_info;
1919 id = GetOpenMPThreadId();
1921 register const Quantum
1924 assert(image != (const Image *) NULL);
1925 assert(image->signature == MagickCoreSignature);
1926 assert(image->cache != (Cache) NULL);
1927 cache_info=(CacheInfo *) image->cache;
1928 assert(cache_info->signature == MagickCoreSignature);
1929 assert(id < (int) cache_info->number_threads);
1930 GetPixelInfo(image,pixel);
1931 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1932 cache_info->nexus_info[id],exception);
1933 if (p == (const Quantum *) NULL)
1934 return(MagickFalse);
1935 GetPixelInfoPixel(image,p,pixel);
1940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1944 + G e t P i x e l C a c h e C o l o r s p a c e %
1948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1950 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1952 % The format of the GetPixelCacheColorspace() method is:
1954 % Colorspace GetPixelCacheColorspace(Cache cache)
1956 % A description of each parameter follows:
1958 % o cache: the pixel cache.
1961 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1964 *restrict cache_info;
1966 assert(cache != (Cache) NULL);
1967 cache_info=(CacheInfo *) cache;
1968 assert(cache_info->signature == MagickCoreSignature);
1969 if (cache_info->debug != MagickFalse)
1970 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1971 cache_info->filename);
1972 return(cache_info->colorspace);
1976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 + G e t P i x e l C a c h e M e t h o d s %
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986 % GetPixelCacheMethods() initializes the CacheMethods structure.
1988 % The format of the GetPixelCacheMethods() method is:
1990 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1992 % A description of each parameter follows:
1994 % o cache_methods: Specifies a pointer to a CacheMethods structure.
1997 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
1999 assert(cache_methods != (CacheMethods *) NULL);
2000 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2001 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2002 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2003 cache_methods->get_virtual_metacontent_from_handler=
2004 GetVirtualMetacontentFromCache;
2005 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2006 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2007 cache_methods->get_authentic_metacontent_from_handler=
2008 GetAuthenticMetacontentFromCache;
2009 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2010 cache_methods->get_one_authentic_pixel_from_handler=
2011 GetOneAuthenticPixelFromCache;
2012 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2013 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2014 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2022 + G e t P i x e l C a c h e N e x u s E x t e n t %
2026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2028 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2029 % corresponding with the last call to SetPixelCacheNexusPixels() or
2030 % GetPixelCacheNexusPixels().
2032 % The format of the GetPixelCacheNexusExtent() method is:
2034 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2035 % NexusInfo *nexus_info)
2037 % A description of each parameter follows:
2039 % o nexus_info: the nexus info.
2042 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2043 NexusInfo *restrict nexus_info)
2046 *restrict cache_info;
2051 assert(cache != NULL);
2052 cache_info=(CacheInfo *) cache;
2053 assert(cache_info->signature == MagickCoreSignature);
2054 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2056 return((MagickSizeType) cache_info->columns*cache_info->rows);
2061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2065 + G e t P i x e l C a c h e P i x e l s %
2069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071 % GetPixelCachePixels() returns the pixels associated with the specified image.
2073 % The format of the GetPixelCachePixels() method is:
2075 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2076 % ExceptionInfo *exception)
2078 % A description of each parameter follows:
2080 % o image: the image.
2082 % o length: the pixel cache length.
2084 % o exception: return any errors or warnings in this structure.
2087 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2088 ExceptionInfo *exception)
2091 *restrict cache_info;
2093 assert(image != (const Image *) NULL);
2094 assert(image->signature == MagickCoreSignature);
2095 assert(image->cache != (Cache) NULL);
2096 assert(length != (MagickSizeType *) NULL);
2097 assert(exception != (ExceptionInfo *) NULL);
2098 assert(exception->signature == MagickCoreSignature);
2099 cache_info=(CacheInfo *) image->cache;
2100 assert(cache_info->signature == MagickCoreSignature);
2102 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2103 return((void *) NULL);
2104 *length=cache_info->length;
2105 return((void *) cache_info->pixels);
2109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113 + 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 %
2117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2119 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2121 % The format of the GetPixelCacheStorageClass() method is:
2123 % ClassType GetPixelCacheStorageClass(Cache cache)
2125 % A description of each parameter follows:
2127 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2129 % o cache: the pixel cache.
2132 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2135 *restrict cache_info;
2137 assert(cache != (Cache) NULL);
2138 cache_info=(CacheInfo *) cache;
2139 assert(cache_info->signature == MagickCoreSignature);
2140 if (cache_info->debug != MagickFalse)
2141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2142 cache_info->filename);
2143 return(cache_info->storage_class);
2147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2151 + G e t P i x e l C a c h e T i l e S i z e %
2155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157 % GetPixelCacheTileSize() returns the pixel cache tile size.
2159 % The format of the GetPixelCacheTileSize() method is:
2161 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2164 % A description of each parameter follows:
2166 % o image: the image.
2168 % o width: the optimize cache tile width in pixels.
2170 % o height: the optimize cache tile height in pixels.
2173 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2177 *restrict cache_info;
2179 assert(image != (Image *) NULL);
2180 assert(image->signature == MagickCoreSignature);
2181 if (image->debug != MagickFalse)
2182 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2183 cache_info=(CacheInfo *) image->cache;
2184 assert(cache_info->signature == MagickCoreSignature);
2185 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2186 if (GetImagePixelCacheType(image) == DiskCache)
2187 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2196 + 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 %
2200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2202 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2203 % pixel cache. A virtual pixel is any pixel access that is outside the
2204 % boundaries of the image cache.
2206 % The format of the GetPixelCacheVirtualMethod() method is:
2208 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2210 % A description of each parameter follows:
2212 % o image: the image.
2215 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2218 *restrict cache_info;
2220 assert(image != (Image *) NULL);
2221 assert(image->signature == MagickCoreSignature);
2222 assert(image->cache != (Cache) NULL);
2223 cache_info=(CacheInfo *) image->cache;
2224 assert(cache_info->signature == MagickCoreSignature);
2225 return(cache_info->virtual_pixel_method);
2229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2233 + 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 %
2237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2239 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2240 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2242 % The format of the GetVirtualMetacontentFromCache() method is:
2244 % void *GetVirtualMetacontentFromCache(const Image *image)
2246 % A description of each parameter follows:
2248 % o image: the image.
2251 static const void *GetVirtualMetacontentFromCache(const Image *image)
2254 *restrict cache_info;
2257 id = GetOpenMPThreadId();
2260 *restrict metacontent;
2262 assert(image != (const Image *) NULL);
2263 assert(image->signature == MagickCoreSignature);
2264 assert(image->cache != (Cache) NULL);
2265 cache_info=(CacheInfo *) image->cache;
2266 assert(cache_info->signature == MagickCoreSignature);
2267 assert(id < (int) cache_info->number_threads);
2268 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2269 cache_info->nexus_info[id]);
2270 return(metacontent);
2274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 + 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 %
2282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2287 % The format of the GetVirtualMetacontentFromNexus() method is:
2289 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2290 % NexusInfo *nexus_info)
2292 % A description of each parameter follows:
2294 % o cache: the pixel cache.
2296 % o nexus_info: the cache nexus to return the meta-content.
2299 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2300 NexusInfo *restrict nexus_info)
2303 *restrict cache_info;
2305 assert(cache != (Cache) NULL);
2306 cache_info=(CacheInfo *) cache;
2307 assert(cache_info->signature == MagickCoreSignature);
2308 if (cache_info->storage_class == UndefinedClass)
2309 return((void *) NULL);
2310 return(nexus_info->metacontent);
2314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2318 % G e t V i r t u a l M e t a c o n t e n t %
2322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2324 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2325 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2326 % returned if the meta-content are not available.
2328 % The format of the GetVirtualMetacontent() method is:
2330 % const void *GetVirtualMetacontent(const Image *image)
2332 % A description of each parameter follows:
2334 % o image: the image.
2337 MagickExport const void *GetVirtualMetacontent(const Image *image)
2340 *restrict cache_info;
2343 id = GetOpenMPThreadId();
2346 *restrict metacontent;
2348 assert(image != (const Image *) NULL);
2349 assert(image->signature == MagickCoreSignature);
2350 assert(image->cache != (Cache) NULL);
2351 cache_info=(CacheInfo *) image->cache;
2352 assert(cache_info->signature == MagickCoreSignature);
2353 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2354 if (metacontent != (void *) NULL)
2355 return(metacontent);
2356 assert(id < (int) cache_info->number_threads);
2357 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2358 cache_info->nexus_info[id]);
2359 return(metacontent);
2363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367 + 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 %
2371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2373 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2374 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2375 % is returned if the pixels are transferred, otherwise a NULL is returned.
2377 % The format of the GetVirtualPixelsFromNexus() method is:
2379 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2380 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2381 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2382 % ExceptionInfo *exception)
2384 % A description of each parameter follows:
2386 % o image: the image.
2388 % o virtual_pixel_method: the virtual pixel method.
2390 % o x,y,columns,rows: These values define the perimeter of a region of
2393 % o nexus_info: the cache nexus to acquire.
2395 % o exception: return any errors or warnings in this structure.
2402 0, 48, 12, 60, 3, 51, 15, 63,
2403 32, 16, 44, 28, 35, 19, 47, 31,
2404 8, 56, 4, 52, 11, 59, 7, 55,
2405 40, 24, 36, 20, 43, 27, 39, 23,
2406 2, 50, 14, 62, 1, 49, 13, 61,
2407 34, 18, 46, 30, 33, 17, 45, 29,
2408 10, 58, 6, 54, 9, 57, 5, 53,
2409 42, 26, 38, 22, 41, 25, 37, 21
2412 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2417 index=x+DitherMatrix[x & 0x07]-32L;
2420 if (index >= (ssize_t) columns)
2421 return((ssize_t) columns-1L);
2425 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2430 index=y+DitherMatrix[y & 0x07]-32L;
2433 if (index >= (ssize_t) rows)
2434 return((ssize_t) rows-1L);
2438 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2442 if (x >= (ssize_t) columns)
2443 return((ssize_t) (columns-1));
2447 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2451 if (y >= (ssize_t) rows)
2452 return((ssize_t) (rows-1));
2456 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2458 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2461 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2463 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2466 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2467 const size_t extent)
2473 Compute the remainder of dividing offset by extent. It returns not only
2474 the quotient (tile the offset falls in) but also the positive remainer
2475 within that tile such that 0 <= remainder < extent. This method is
2476 essentially a ldiv() using a floored modulo division rather than the
2477 normal default truncated modulo division.
2479 modulo.quotient=offset/(ssize_t) extent;
2482 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2486 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2487 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2488 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2489 ExceptionInfo *exception)
2492 *restrict cache_info;
2502 **restrict virtual_nexus;
2506 virtual_pixel[MaxPixelChannels];
2511 register const Quantum
2524 register unsigned char
2531 *restrict virtual_metacontent;
2536 assert(image != (const Image *) NULL);
2537 assert(image->signature == MagickCoreSignature);
2538 assert(image->cache != (Cache) NULL);
2539 cache_info=(CacheInfo *) image->cache;
2540 assert(cache_info->signature == MagickCoreSignature);
2541 if (cache_info->type == UndefinedCache)
2542 return((const Quantum *) NULL);
2545 region.width=columns;
2547 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2549 if (pixels == (Quantum *) NULL)
2550 return((const Quantum *) NULL);
2552 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2553 nexus_info->region.x;
2554 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2555 nexus_info->region.width-1L;
2556 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2557 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2558 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2559 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2565 Pixel request is inside cache extents.
2567 if (nexus_info->authentic_pixel_cache != MagickFalse)
2569 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2570 if (status == MagickFalse)
2571 return((const Quantum *) NULL);
2572 if (cache_info->metacontent_extent != 0)
2574 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2575 if (status == MagickFalse)
2576 return((const Quantum *) NULL);
2581 Pixel request is outside cache extents.
2583 s=(unsigned char *) nexus_info->metacontent;
2584 virtual_nexus=AcquirePixelCacheNexus(1);
2585 if (virtual_nexus == (NexusInfo **) NULL)
2587 if (virtual_nexus != (NexusInfo **) NULL)
2588 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2589 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2590 "UnableToGetCacheNexus","`%s'",image->filename);
2591 return((const Quantum *) NULL);
2593 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2594 sizeof(*virtual_pixel));
2595 virtual_metacontent=(void *) NULL;
2596 switch (virtual_pixel_method)
2598 case BackgroundVirtualPixelMethod:
2599 case BlackVirtualPixelMethod:
2600 case GrayVirtualPixelMethod:
2601 case TransparentVirtualPixelMethod:
2602 case MaskVirtualPixelMethod:
2603 case WhiteVirtualPixelMethod:
2604 case EdgeVirtualPixelMethod:
2605 case CheckerTileVirtualPixelMethod:
2606 case HorizontalTileVirtualPixelMethod:
2607 case VerticalTileVirtualPixelMethod:
2609 if (cache_info->metacontent_extent != 0)
2612 Acquire a metacontent buffer.
2614 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2615 cache_info->metacontent_extent);
2616 if (virtual_metacontent == (void *) NULL)
2618 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2619 (void) ThrowMagickException(exception,GetMagickModule(),
2620 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2621 return((const Quantum *) NULL);
2623 (void) ResetMagickMemory(virtual_metacontent,0,
2624 cache_info->metacontent_extent);
2626 switch (virtual_pixel_method)
2628 case BlackVirtualPixelMethod:
2630 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2631 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2632 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2635 case GrayVirtualPixelMethod:
2637 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2638 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2640 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2643 case TransparentVirtualPixelMethod:
2645 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2646 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2647 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2650 case MaskVirtualPixelMethod:
2651 case WhiteVirtualPixelMethod:
2653 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2654 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2655 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2660 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2662 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2664 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2666 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2668 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2678 for (v=0; v < (ssize_t) rows; v++)
2684 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2685 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2686 y_offset=EdgeY(y_offset,cache_info->rows);
2687 for (u=0; u < (ssize_t) columns; u+=length)
2693 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2694 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2695 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2703 Transfer a single pixel.
2705 length=(MagickSizeType) 1;
2706 switch (virtual_pixel_method)
2708 case EdgeVirtualPixelMethod:
2711 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2712 EdgeX(x_offset,cache_info->columns),
2713 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2715 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2718 case RandomVirtualPixelMethod:
2720 if (cache_info->random_info == (RandomInfo *) NULL)
2721 cache_info->random_info=AcquireRandomInfo();
2722 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2723 RandomX(cache_info->random_info,cache_info->columns),
2724 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2725 *virtual_nexus,exception);
2726 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2729 case DitherVirtualPixelMethod:
2731 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2732 DitherX(x_offset,cache_info->columns),
2733 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2735 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2738 case TileVirtualPixelMethod:
2740 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2741 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
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 MirrorVirtualPixelMethod:
2750 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2751 if ((x_modulo.quotient & 0x01) == 1L)
2752 x_modulo.remainder=(ssize_t) cache_info->columns-
2753 x_modulo.remainder-1L;
2754 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2755 if ((y_modulo.quotient & 0x01) == 1L)
2756 y_modulo.remainder=(ssize_t) cache_info->rows-
2757 y_modulo.remainder-1L;
2758 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2759 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2761 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2764 case HorizontalTileEdgeVirtualPixelMethod:
2766 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2767 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2768 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2769 *virtual_nexus,exception);
2770 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2773 case VerticalTileEdgeVirtualPixelMethod:
2775 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2776 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2777 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2778 *virtual_nexus,exception);
2779 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2782 case BackgroundVirtualPixelMethod:
2783 case BlackVirtualPixelMethod:
2784 case GrayVirtualPixelMethod:
2785 case TransparentVirtualPixelMethod:
2786 case MaskVirtualPixelMethod:
2787 case WhiteVirtualPixelMethod:
2790 r=virtual_metacontent;
2793 case CheckerTileVirtualPixelMethod:
2795 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2796 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2797 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2800 r=virtual_metacontent;
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 HorizontalTileVirtualPixelMethod:
2811 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
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);
2825 case VerticalTileVirtualPixelMethod:
2827 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2830 r=virtual_metacontent;
2833 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2834 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2835 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2836 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2838 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2842 if (p == (const Quantum *) NULL)
2844 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2846 q+=cache_info->number_channels;
2847 if ((s != (void *) NULL) && (r != (const void *) NULL))
2849 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2850 s+=cache_info->metacontent_extent;
2855 Transfer a run of pixels.
2857 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2858 (size_t) length,1UL,*virtual_nexus,exception);
2859 if (p == (const Quantum *) NULL)
2861 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2862 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2863 q+=length*cache_info->number_channels;
2864 if ((r != (void *) NULL) && (s != (const void *) NULL))
2866 (void) memcpy(s,r,(size_t) length);
2867 s+=length*cache_info->metacontent_extent;
2874 if (virtual_metacontent != (void *) NULL)
2875 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2876 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885 + G e t V i r t u a l P i x e l C a c h e %
2889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2892 % cache as defined by the geometry parameters. A pointer to the pixels
2893 % is returned if the pixels are transferred, otherwise a NULL is returned.
2895 % The format of the GetVirtualPixelCache() method is:
2897 % const Quantum *GetVirtualPixelCache(const Image *image,
2898 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2899 % const ssize_t y,const size_t columns,const size_t rows,
2900 % ExceptionInfo *exception)
2902 % A description of each parameter follows:
2904 % o image: the image.
2906 % o virtual_pixel_method: the virtual pixel method.
2908 % o x,y,columns,rows: These values define the perimeter of a region of
2911 % o exception: return any errors or warnings in this structure.
2914 static const Quantum *GetVirtualPixelCache(const Image *image,
2915 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2916 const size_t columns,const size_t rows,ExceptionInfo *exception)
2919 *restrict cache_info;
2922 id = GetOpenMPThreadId();
2927 assert(image != (const Image *) NULL);
2928 assert(image->signature == MagickCoreSignature);
2929 assert(image->cache != (Cache) NULL);
2930 cache_info=(CacheInfo *) image->cache;
2931 assert(cache_info->signature == MagickCoreSignature);
2932 assert(id < (int) cache_info->number_threads);
2933 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2934 cache_info->nexus_info[id],exception);
2939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2943 % G e t V i r t u a l P i x e l Q u e u e %
2947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2949 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2950 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2952 % The format of the GetVirtualPixelQueue() method is:
2954 % const Quantum *GetVirtualPixelQueue(const Image image)
2956 % A description of each parameter follows:
2958 % o image: the image.
2961 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2964 *restrict cache_info;
2967 id = GetOpenMPThreadId();
2969 assert(image != (const Image *) NULL);
2970 assert(image->signature == MagickCoreSignature);
2971 assert(image->cache != (Cache) NULL);
2972 cache_info=(CacheInfo *) image->cache;
2973 assert(cache_info->signature == MagickCoreSignature);
2974 if (cache_info->methods.get_virtual_pixels_handler !=
2975 (GetVirtualPixelsHandler) NULL)
2976 return(cache_info->methods.get_virtual_pixels_handler(image));
2977 assert(id < (int) cache_info->number_threads);
2978 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2986 % G e t V i r t u a l P i x e l s %
2990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2992 % GetVirtualPixels() returns an immutable pixel region. If the
2993 % region is successfully accessed, a pointer to it is returned, otherwise
2994 % NULL is returned. The returned pointer may point to a temporary working
2995 % copy of the pixels or it may point to the original pixels in memory.
2996 % Performance is maximized if the selected region is part of one row, or one
2997 % or more full rows, since there is opportunity to access the pixels in-place
2998 % (without a copy) if the image is in memory, or in a memory-mapped file. The
2999 % returned pointer must *never* be deallocated by the user.
3001 % Pixels accessed via the returned pointer represent a simple array of type
3002 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3003 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3004 % access the meta-content (of type void) corresponding to the the
3007 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3009 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3010 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3011 % GetCacheViewAuthenticPixels() instead.
3013 % The format of the GetVirtualPixels() method is:
3015 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3016 % const ssize_t y,const size_t columns,const size_t rows,
3017 % ExceptionInfo *exception)
3019 % A description of each parameter follows:
3021 % o image: the image.
3023 % o x,y,columns,rows: These values define the perimeter of a region of
3026 % o exception: return any errors or warnings in this structure.
3029 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3030 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3031 ExceptionInfo *exception)
3034 *restrict cache_info;
3037 id = GetOpenMPThreadId();
3042 assert(image != (const Image *) NULL);
3043 assert(image->signature == MagickCoreSignature);
3044 assert(image->cache != (Cache) NULL);
3045 cache_info=(CacheInfo *) image->cache;
3046 assert(cache_info->signature == MagickCoreSignature);
3047 if (cache_info->methods.get_virtual_pixel_handler !=
3048 (GetVirtualPixelHandler) NULL)
3049 return(cache_info->methods.get_virtual_pixel_handler(image,
3050 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3051 assert(id < (int) cache_info->number_threads);
3052 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3053 columns,rows,cache_info->nexus_info[id],exception);
3058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3062 + 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 %
3066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3068 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3069 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3071 % The format of the GetVirtualPixelsCache() method is:
3073 % Quantum *GetVirtualPixelsCache(const Image *image)
3075 % A description of each parameter follows:
3077 % o image: the image.
3080 static const Quantum *GetVirtualPixelsCache(const Image *image)
3083 *restrict cache_info;
3086 id = GetOpenMPThreadId();
3088 assert(image != (const Image *) NULL);
3089 assert(image->signature == MagickCoreSignature);
3090 assert(image->cache != (Cache) NULL);
3091 cache_info=(CacheInfo *) image->cache;
3092 assert(cache_info->signature == MagickCoreSignature);
3093 assert(id < (int) cache_info->number_threads);
3094 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3102 + G e t V i r t u a l P i x e l s N e x u s %
3106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3108 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3111 % The format of the GetVirtualPixelsNexus() method is:
3113 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3114 % NexusInfo *nexus_info)
3116 % A description of each parameter follows:
3118 % o cache: the pixel cache.
3120 % o nexus_info: the cache nexus to return the colormap pixels.
3123 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3124 NexusInfo *restrict nexus_info)
3127 *restrict cache_info;
3129 assert(cache != (Cache) NULL);
3130 cache_info=(CacheInfo *) cache;
3131 assert(cache_info->signature == MagickCoreSignature);
3132 if (cache_info->storage_class == UndefinedClass)
3133 return((Quantum *) NULL);
3134 return((const Quantum *) nexus_info->pixels);
3138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3142 + O p e n P i x e l C a c h e %
3146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3148 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3149 % dimensions, allocating space for the image pixels and optionally the
3150 % metacontent, and memory mapping the cache if it is disk based. The cache
3151 % nexus array is initialized as well.
3153 % The format of the OpenPixelCache() method is:
3155 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3156 % ExceptionInfo *exception)
3158 % A description of each parameter follows:
3160 % o image: the image.
3162 % o mode: ReadMode, WriteMode, or IOMode.
3164 % o exception: return any errors or warnings in this structure.
3168 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3170 cache_info->mapped=MagickFalse;
3171 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3172 (size_t) cache_info->length));
3173 if (cache_info->pixels == (Quantum *) NULL)
3175 cache_info->mapped=MagickTrue;
3176 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3177 cache_info->length);
3181 #if defined(__cplusplus) || defined(c_plusplus)
3186 static void CacheSignalHandler(int status)
3188 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3192 #if defined(__cplusplus) || defined(c_plusplus)
3196 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3203 Open pixel cache on disk.
3205 if ((cache_info->file != -1) && (cache_info->mode == mode))
3206 return(MagickTrue); /* cache already open and in the proper mode */
3207 if (*cache_info->cache_filename == '\0')
3208 file=AcquireUniqueFileResource(cache_info->cache_filename);
3214 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3219 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3220 O_BINARY | O_EXCL,S_MODE);
3222 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3228 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3231 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3236 return(MagickFalse);
3237 (void) AcquireMagickResource(FileResource,1);
3238 if (cache_info->file != -1)
3239 (void) ClosePixelCacheOnDisk(cache_info);
3240 cache_info->file=file;
3241 cache_info->mode=mode;
3245 static inline MagickOffsetType WritePixelCacheRegion(
3246 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3247 const MagickSizeType length,const unsigned char *restrict buffer)
3249 #if !defined(MAGICKCORE_HAVE_PWRITE)
3254 register MagickOffsetType
3260 #if !defined(MAGICKCORE_HAVE_PWRITE)
3261 current_offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_CUR);
3262 if (current_offset < 0)
3263 return((MagickOffsetType) -1);
3264 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3265 return((MagickOffsetType) -1);
3268 for (i=0; i < (MagickOffsetType) length; i+=count)
3270 #if !defined(MAGICKCORE_HAVE_PWRITE)
3271 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3274 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3275 SSIZE_MAX),(off_t) (offset+i));
3284 #if !defined(MAGICKCORE_HAVE_PWRITE)
3285 if (lseek(cache_info->file,current_offset,SEEK_SET) < 0)
3286 return((MagickOffsetType) -1);
3291 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3294 *restrict cache_info;
3301 cache_info=(CacheInfo *) image->cache;
3302 if (image->debug != MagickFalse)
3305 format[MagickPathExtent],
3306 message[MagickPathExtent];
3308 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3309 (void) FormatLocaleString(message,MagickPathExtent,
3310 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3311 cache_info->cache_filename,cache_info->file,format);
3312 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3314 if (length != (MagickSizeType) ((MagickOffsetType) length))
3315 return(MagickFalse);
3316 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3318 return(MagickFalse);
3319 if ((MagickSizeType) offset >= length)
3320 count=(MagickOffsetType) 1;
3323 extent=(MagickOffsetType) length-1;
3324 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3326 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3327 if (cache_info->synchronize != MagickFalse)
3328 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3331 (void) signal(SIGBUS,CacheSignalHandler);
3334 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3336 return(MagickFalse);
3337 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3340 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3341 ExceptionInfo *exception)
3344 *restrict cache_info,
3348 format[MagickPathExtent],
3349 message[MagickPathExtent];
3365 assert(image != (const Image *) NULL);
3366 assert(image->signature == MagickCoreSignature);
3367 assert(image->cache != (Cache) NULL);
3368 if (image->debug != MagickFalse)
3369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3370 if ((image->columns == 0) || (image->rows == 0))
3371 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3372 cache_info=(CacheInfo *) image->cache;
3373 assert(cache_info->signature == MagickCoreSignature);
3374 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3375 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3376 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3378 source_info=(*cache_info);
3379 source_info.file=(-1);
3380 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3381 image->filename,(double) GetImageIndexInList(image));
3382 cache_info->storage_class=image->storage_class;
3383 cache_info->colorspace=image->colorspace;
3384 cache_info->alpha_trait=image->alpha_trait;
3385 cache_info->read_mask=image->read_mask;
3386 cache_info->write_mask=image->write_mask;
3387 cache_info->rows=image->rows;
3388 cache_info->columns=image->columns;
3389 InitializePixelChannelMap(image);
3390 cache_info->number_channels=GetPixelChannels(image);
3391 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3392 sizeof(*image->channel_map));
3393 cache_info->metacontent_extent=image->metacontent_extent;
3394 cache_info->mode=mode;
3395 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3396 packet_size=cache_info->number_channels*sizeof(Quantum);
3397 if (image->metacontent_extent != 0)
3398 packet_size+=cache_info->metacontent_extent;
3399 length=number_pixels*packet_size;
3400 columns=(size_t) (length/cache_info->rows/packet_size);
3401 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3402 ((ssize_t) cache_info->rows < 0))
3403 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3405 cache_info->length=length;
3406 if (image->ping != MagickFalse)
3408 cache_info->storage_class=image->storage_class;
3409 cache_info->colorspace=image->colorspace;
3410 cache_info->type=PingCache;
3413 status=AcquireMagickResource(AreaResource,cache_info->length);
3414 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3415 cache_info->metacontent_extent);
3416 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3418 status=AcquireMagickResource(MemoryResource,cache_info->length);
3419 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3420 (cache_info->type == MemoryCache))
3422 AllocatePixelCachePixels(cache_info);
3423 if (cache_info->pixels == (Quantum *) NULL)
3424 cache_info->pixels=source_info.pixels;
3428 Create memory pixel cache.
3431 cache_info->type=MemoryCache;
3432 cache_info->metacontent=(void *) NULL;
3433 if (cache_info->metacontent_extent != 0)
3434 cache_info->metacontent=(void *) (cache_info->pixels+
3435 number_pixels*cache_info->number_channels);
3436 if ((source_info.storage_class != UndefinedClass) &&
3439 status=ClonePixelCacheRepository(cache_info,&source_info,
3441 RelinquishPixelCachePixels(&source_info);
3443 if (image->debug != MagickFalse)
3445 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3446 MagickPathExtent,format);
3447 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3449 (void) FormatLocaleString(message,MagickPathExtent,
3450 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3451 cache_info->filename,cache_info->mapped != MagickFalse ?
3452 "Anonymous" : "Heap",type,(double) cache_info->columns,
3453 (double) cache_info->rows,(double)
3454 cache_info->number_channels,format);
3455 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3461 RelinquishMagickResource(MemoryResource,cache_info->length);
3464 Create pixel cache on disk.
3466 status=AcquireMagickResource(DiskResource,cache_info->length);
3467 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3472 if (cache_info->type == DistributedCache)
3473 RelinquishMagickResource(DiskResource,cache_info->length);
3474 server_info=AcquireDistributeCacheInfo(exception);
3475 if (server_info != (DistributeCacheInfo *) NULL)
3477 status=OpenDistributePixelCache(server_info,image);
3478 if (status == MagickFalse)
3480 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3481 GetDistributeCacheHostname(server_info));
3482 server_info=DestroyDistributeCacheInfo(server_info);
3487 Create a distributed pixel cache.
3489 cache_info->type=DistributedCache;
3490 cache_info->server_info=server_info;
3491 (void) FormatLocaleString(cache_info->cache_filename,
3492 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3493 (DistributeCacheInfo *) cache_info->server_info),
3494 GetDistributeCachePort((DistributeCacheInfo *)
3495 cache_info->server_info));
3496 if ((source_info.storage_class != UndefinedClass) &&
3499 status=ClonePixelCacheRepository(cache_info,&source_info,
3501 RelinquishPixelCachePixels(&source_info);
3503 if (image->debug != MagickFalse)
3505 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3506 MagickPathExtent,format);
3507 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3509 (void) FormatLocaleString(message,MagickPathExtent,
3510 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3511 cache_info->filename,cache_info->cache_filename,
3512 GetDistributeCacheFile((DistributeCacheInfo *)
3513 cache_info->server_info),type,(double) cache_info->columns,
3514 (double) cache_info->rows,(double)
3515 cache_info->number_channels,format);
3516 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3522 RelinquishMagickResource(DiskResource,cache_info->length);
3523 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3524 "CacheResourcesExhausted","`%s'",image->filename);
3525 return(MagickFalse);
3527 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3529 (void) ClosePixelCacheOnDisk(cache_info);
3530 *cache_info->cache_filename='\0';
3532 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3534 RelinquishMagickResource(DiskResource,cache_info->length);
3535 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3537 return(MagickFalse);
3539 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3540 cache_info->length);
3541 if (status == MagickFalse)
3543 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3545 return(MagickFalse);
3547 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3548 cache_info->metacontent_extent);
3549 if (length != (MagickSizeType) ((size_t) length))
3550 cache_info->type=DiskCache;
3553 status=AcquireMagickResource(MapResource,cache_info->length);
3554 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3555 (cache_info->type != MemoryCache))
3556 cache_info->type=DiskCache;
3559 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3560 cache_info->offset,(size_t) cache_info->length);
3561 if (cache_info->pixels == (Quantum *) NULL)
3563 cache_info->type=DiskCache;
3564 cache_info->pixels=source_info.pixels;
3569 Create file-backed memory-mapped pixel cache.
3572 (void) ClosePixelCacheOnDisk(cache_info);
3573 cache_info->type=MapCache;
3574 cache_info->mapped=MagickTrue;
3575 cache_info->metacontent=(void *) NULL;
3576 if (cache_info->metacontent_extent != 0)
3577 cache_info->metacontent=(void *) (cache_info->pixels+
3578 number_pixels*cache_info->number_channels);
3579 if ((source_info.storage_class != UndefinedClass) &&
3582 status=ClonePixelCacheRepository(cache_info,&source_info,
3584 RelinquishPixelCachePixels(&source_info);
3586 if (image->debug != MagickFalse)
3588 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3589 MagickPathExtent,format);
3590 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3592 (void) FormatLocaleString(message,MagickPathExtent,
3593 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3594 cache_info->filename,cache_info->cache_filename,
3595 cache_info->file,type,(double) cache_info->columns,(double)
3596 cache_info->rows,(double) cache_info->number_channels,
3598 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3604 RelinquishMagickResource(MapResource,cache_info->length);
3607 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3609 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3610 RelinquishPixelCachePixels(&source_info);
3612 if (image->debug != MagickFalse)
3614 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",MagickPathExtent,
3616 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3618 (void) FormatLocaleString(message,MagickPathExtent,
3619 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3620 cache_info->cache_filename,cache_info->file,type,(double)
3621 cache_info->columns,(double) cache_info->rows,(double)
3622 cache_info->number_channels,format);
3623 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3633 + P e r s i s t P i x e l C a c h e %
3637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3639 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3640 % persistent pixel cache is one that resides on disk and is not destroyed
3641 % when the program exits.
3643 % The format of the PersistPixelCache() method is:
3645 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3646 % const MagickBooleanType attach,MagickOffsetType *offset,
3647 % ExceptionInfo *exception)
3649 % A description of each parameter follows:
3651 % o image: the image.
3653 % o filename: the persistent pixel cache filename.
3655 % o attach: A value other than zero initializes the persistent pixel cache.
3657 % o initialize: A value other than zero initializes the persistent pixel
3660 % o offset: the offset in the persistent cache to store pixels.
3662 % o exception: return any errors or warnings in this structure.
3665 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3666 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3667 ExceptionInfo *exception)
3670 *restrict cache_info,
3671 *restrict clone_info;
3682 assert(image != (Image *) NULL);
3683 assert(image->signature == MagickCoreSignature);
3684 if (image->debug != MagickFalse)
3685 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3686 assert(image->cache != (void *) NULL);
3687 assert(filename != (const char *) NULL);
3688 assert(offset != (MagickOffsetType *) NULL);
3689 page_size=GetMagickPageSize();
3690 cache_info=(CacheInfo *) image->cache;
3691 assert(cache_info->signature == MagickCoreSignature);
3692 if (attach != MagickFalse)
3695 Attach existing persistent pixel cache.
3697 if (image->debug != MagickFalse)
3698 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3699 "attach persistent cache");
3700 (void) CopyMagickString(cache_info->cache_filename,filename,
3702 cache_info->type=DiskCache;
3703 cache_info->offset=(*offset);
3704 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3705 return(MagickFalse);
3706 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3709 if ((cache_info->mode != ReadMode) &&
3710 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3711 (cache_info->reference_count == 1))
3713 LockSemaphoreInfo(cache_info->semaphore);
3714 if ((cache_info->mode != ReadMode) &&
3715 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3716 (cache_info->reference_count == 1))
3719 Usurp existing persistent pixel cache.
3721 if (rename_utf8(cache_info->cache_filename, filename) == 0)
3723 (void) CopyMagickString(cache_info->cache_filename,filename,
3725 *offset+=cache_info->length+page_size-(cache_info->length %
3727 UnlockSemaphoreInfo(cache_info->semaphore);
3728 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3729 if (image->debug != MagickFalse)
3730 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3731 "Usurp resident persistent cache");
3735 UnlockSemaphoreInfo(cache_info->semaphore);
3738 Clone persistent pixel cache.
3740 clone_image=(*image);
3741 clone_info=(CacheInfo *) clone_image.cache;
3742 image->cache=ClonePixelCache(cache_info);
3743 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3744 (void) CopyMagickString(cache_info->cache_filename,filename,MagickPathExtent);
3745 cache_info->type=DiskCache;
3746 cache_info->offset=(*offset);
3747 cache_info=(CacheInfo *) image->cache;
3748 status=OpenPixelCache(image,IOMode,exception);
3749 if (status != MagickFalse)
3750 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3751 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3752 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3761 + 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 %
3765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3768 % defined by the region rectangle and returns a pointer to the region. This
3769 % region is subsequently transferred from the pixel cache with
3770 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3771 % pixels are transferred, otherwise a NULL is returned.
3773 % The format of the QueueAuthenticPixelCacheNexus() method is:
3775 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3776 % const ssize_t y,const size_t columns,const size_t rows,
3777 % const MagickBooleanType clone,NexusInfo *nexus_info,
3778 % ExceptionInfo *exception)
3780 % A description of each parameter follows:
3782 % o image: the image.
3784 % o x,y,columns,rows: These values define the perimeter of a region of
3787 % o nexus_info: the cache nexus to set.
3789 % o clone: clone the pixel cache.
3791 % o exception: return any errors or warnings in this structure.
3794 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3795 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3796 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3799 *restrict cache_info;
3814 Validate pixel cache geometry.
3816 assert(image != (const Image *) NULL);
3817 assert(image->signature == MagickCoreSignature);
3818 assert(image->cache != (Cache) NULL);
3819 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3820 if (cache_info == (Cache) NULL)
3821 return((Quantum *) NULL);
3822 assert(cache_info->signature == MagickCoreSignature);
3823 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3824 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3825 (y >= (ssize_t) cache_info->rows))
3827 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3828 "PixelsAreNotAuthentic","`%s'",image->filename);
3829 return((Quantum *) NULL);
3831 offset=(MagickOffsetType) y*cache_info->columns+x;
3833 return((Quantum *) NULL);
3834 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3835 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3836 if ((MagickSizeType) offset >= number_pixels)
3837 return((Quantum *) NULL);
3843 region.width=columns;
3845 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3855 + 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 %
3859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3861 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3862 % defined by the region rectangle and returns a pointer to the region. This
3863 % region is subsequently transferred from the pixel cache with
3864 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3865 % pixels are transferred, otherwise a NULL is returned.
3867 % The format of the QueueAuthenticPixelsCache() method is:
3869 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3870 % const ssize_t y,const size_t columns,const size_t rows,
3871 % ExceptionInfo *exception)
3873 % A description of each parameter follows:
3875 % o image: the image.
3877 % o x,y,columns,rows: These values define the perimeter of a region of
3880 % o exception: return any errors or warnings in this structure.
3883 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3884 const ssize_t y,const size_t columns,const size_t rows,
3885 ExceptionInfo *exception)
3888 *restrict cache_info;
3891 id = GetOpenMPThreadId();
3896 assert(image != (const Image *) NULL);
3897 assert(image->signature == MagickCoreSignature);
3898 assert(image->cache != (Cache) NULL);
3899 cache_info=(CacheInfo *) image->cache;
3900 assert(cache_info->signature == MagickCoreSignature);
3901 assert(id < (int) cache_info->number_threads);
3902 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3903 cache_info->nexus_info[id],exception);
3908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3912 % Q u e u e A u t h e n t i c P i x e l s %
3916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3918 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3919 % successfully initialized a pointer to a Quantum array representing the
3920 % region is returned, otherwise NULL is returned. The returned pointer may
3921 % point to a temporary working buffer for the pixels or it may point to the
3922 % final location of the pixels in memory.
3924 % Write-only access means that any existing pixel values corresponding to
3925 % the region are ignored. This is useful if the initial image is being
3926 % created from scratch, or if the existing pixel values are to be
3927 % completely replaced without need to refer to their pre-existing values.
3928 % The application is free to read and write the pixel buffer returned by
3929 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3930 % initialize the pixel array values. Initializing pixel array values is the
3931 % application's responsibility.
3933 % Performance is maximized if the selected region is part of one row, or
3934 % one or more full rows, since then there is opportunity to access the
3935 % pixels in-place (without a copy) if the image is in memory, or in a
3936 % memory-mapped file. The returned pointer must *never* be deallocated
3939 % Pixels accessed via the returned pointer represent a simple array of type
3940 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3941 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3942 % obtain the meta-content (of type void) corresponding to the region.
3943 % Once the Quantum (and/or Quantum) array has been updated, the
3944 % changes must be saved back to the underlying image using
3945 % SyncAuthenticPixels() or they may be lost.
3947 % The format of the QueueAuthenticPixels() method is:
3949 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3950 % const ssize_t y,const size_t columns,const size_t rows,
3951 % ExceptionInfo *exception)
3953 % A description of each parameter follows:
3955 % o image: the image.
3957 % o x,y,columns,rows: These values define the perimeter of a region of
3960 % o exception: return any errors or warnings in this structure.
3963 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3964 const ssize_t y,const size_t columns,const size_t rows,
3965 ExceptionInfo *exception)
3968 *restrict cache_info;
3971 id = GetOpenMPThreadId();
3976 assert(image != (Image *) NULL);
3977 assert(image->signature == MagickCoreSignature);
3978 assert(image->cache != (Cache) NULL);
3979 cache_info=(CacheInfo *) image->cache;
3980 assert(cache_info->signature == MagickCoreSignature);
3981 if (cache_info->methods.queue_authentic_pixels_handler !=
3982 (QueueAuthenticPixelsHandler) NULL)
3984 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3985 columns,rows,exception);
3988 assert(id < (int) cache_info->number_threads);
3989 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3990 cache_info->nexus_info[id],exception);
3995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3999 + 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 %
4003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4005 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4008 % The format of the ReadPixelCacheMetacontent() method is:
4010 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4011 % NexusInfo *nexus_info,ExceptionInfo *exception)
4013 % A description of each parameter follows:
4015 % o cache_info: the pixel cache.
4017 % o nexus_info: the cache nexus to read the metacontent.
4019 % o exception: return any errors or warnings in this structure.
4023 static inline MagickOffsetType ReadPixelCacheRegion(
4024 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4025 const MagickSizeType length,unsigned char *restrict buffer)
4027 #if !defined(MAGICKCORE_HAVE_PREAD)
4032 register MagickOffsetType
4038 #if !defined(MAGICKCORE_HAVE_PREAD)
4039 current_offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_CUR);
4040 if (current_offset < 0)
4041 return((MagickOffsetType) -1);
4042 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4043 return((MagickOffsetType) -1);
4046 for (i=0; i < (MagickOffsetType) length; i+=count)
4048 #if !defined(MAGICKCORE_HAVE_PREAD)
4049 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4052 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4053 SSIZE_MAX),(off_t) (offset+i));
4062 #if !defined(MAGICKCORE_HAVE_PREAD)
4063 if (lseek(cache_info->file,current_offset,SEEK_SET) < 0)
4064 return((MagickOffsetType) -1);
4069 static MagickBooleanType ReadPixelCacheMetacontent(
4070 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4071 ExceptionInfo *exception)
4084 register unsigned char
4090 if (cache_info->metacontent_extent == 0)
4091 return(MagickFalse);
4092 if (nexus_info->authentic_pixel_cache != MagickFalse)
4094 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4095 nexus_info->region.x;
4096 length=(MagickSizeType) nexus_info->region.width*
4097 cache_info->metacontent_extent;
4098 extent=length*nexus_info->region.height;
4099 rows=nexus_info->region.height;
4101 q=(unsigned char *) nexus_info->metacontent;
4102 switch (cache_info->type)
4107 register unsigned char
4111 Read meta-content from memory.
4113 if ((cache_info->columns == nexus_info->region.width) &&
4114 (extent == (MagickSizeType) ((size_t) extent)))
4119 p=(unsigned char *) cache_info->metacontent+offset*
4120 cache_info->metacontent_extent;
4121 for (y=0; y < (ssize_t) rows; y++)
4123 (void) memcpy(q,p,(size_t) length);
4124 p+=cache_info->metacontent_extent*cache_info->columns;
4125 q+=cache_info->metacontent_extent*nexus_info->region.width;
4132 Read meta content from disk.
4134 LockSemaphoreInfo(cache_info->file_semaphore);
4135 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4137 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4138 cache_info->cache_filename);
4139 UnlockSemaphoreInfo(cache_info->file_semaphore);
4140 return(MagickFalse);
4142 if ((cache_info->columns == nexus_info->region.width) &&
4143 (extent <= MagickMaxBufferExtent))
4148 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4149 for (y=0; y < (ssize_t) rows; y++)
4151 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4152 cache_info->number_channels*sizeof(Quantum)+offset*
4153 cache_info->metacontent_extent,length,(unsigned char *) q);
4154 if (count != (MagickOffsetType) length)
4156 offset+=cache_info->columns;
4157 q+=cache_info->metacontent_extent*nexus_info->region.width;
4159 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4160 (void) ClosePixelCacheOnDisk(cache_info);
4161 UnlockSemaphoreInfo(cache_info->file_semaphore);
4164 case DistributedCache:
4170 Read metacontent from distributed cache.
4172 LockSemaphoreInfo(cache_info->file_semaphore);
4173 region=nexus_info->region;
4174 if ((cache_info->columns != nexus_info->region.width) ||
4175 (extent > MagickMaxBufferExtent))
4182 for (y=0; y < (ssize_t) rows; y++)
4184 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4185 cache_info->server_info,®ion,length,(unsigned char *) q);
4186 if (count != (MagickOffsetType) length)
4188 q+=cache_info->metacontent_extent*nexus_info->region.width;
4191 UnlockSemaphoreInfo(cache_info->file_semaphore);
4197 if (y < (ssize_t) rows)
4199 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4200 cache_info->cache_filename);
4201 return(MagickFalse);
4203 if ((cache_info->debug != MagickFalse) &&
4204 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4205 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4206 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4207 nexus_info->region.width,(double) nexus_info->region.height,(double)
4208 nexus_info->region.x,(double) nexus_info->region.y);
4213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4217 + R e a d P i x e l C a c h e P i x e l s %
4221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4223 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4226 % The format of the ReadPixelCachePixels() method is:
4228 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4229 % NexusInfo *nexus_info,ExceptionInfo *exception)
4231 % A description of each parameter follows:
4233 % o cache_info: the pixel cache.
4235 % o nexus_info: the cache nexus to read the pixels.
4237 % o exception: return any errors or warnings in this structure.
4240 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4241 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4261 if (nexus_info->authentic_pixel_cache != MagickFalse)
4263 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4264 if ((offset/cache_info->columns) != (MagickOffsetType) nexus_info->region.y)
4265 return(MagickFalse);
4266 offset+=nexus_info->region.x;
4267 number_channels=cache_info->number_channels;
4268 length=(MagickSizeType) number_channels*nexus_info->region.width*
4270 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4271 return(MagickFalse);
4272 rows=nexus_info->region.height;
4274 if ((extent == 0) || ((extent/length) != rows))
4275 return(MagickFalse);
4277 q=nexus_info->pixels;
4278 switch (cache_info->type)
4287 Read pixels from memory.
4289 if ((cache_info->columns == nexus_info->region.width) &&
4290 (extent == (MagickSizeType) ((size_t) extent)))
4295 p=cache_info->pixels+offset*cache_info->number_channels;
4296 for (y=0; y < (ssize_t) rows; y++)
4298 (void) memcpy(q,p,(size_t) length);
4299 p+=cache_info->number_channels*cache_info->columns;
4300 q+=cache_info->number_channels*nexus_info->region.width;
4307 Read pixels from disk.
4309 LockSemaphoreInfo(cache_info->file_semaphore);
4310 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4312 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4313 cache_info->cache_filename);
4314 UnlockSemaphoreInfo(cache_info->file_semaphore);
4315 return(MagickFalse);
4317 if ((cache_info->columns == nexus_info->region.width) &&
4318 (extent <= MagickMaxBufferExtent))
4323 for (y=0; y < (ssize_t) rows; y++)
4325 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4326 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4327 if (count != (MagickOffsetType) length)
4329 offset+=cache_info->columns;
4330 q+=cache_info->number_channels*nexus_info->region.width;
4332 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4333 (void) ClosePixelCacheOnDisk(cache_info);
4334 UnlockSemaphoreInfo(cache_info->file_semaphore);
4337 case DistributedCache:
4343 Read pixels from distributed cache.
4345 LockSemaphoreInfo(cache_info->file_semaphore);
4346 region=nexus_info->region;
4347 if ((cache_info->columns != nexus_info->region.width) ||
4348 (extent > MagickMaxBufferExtent))
4355 for (y=0; y < (ssize_t) rows; y++)
4357 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4358 cache_info->server_info,®ion,length,(unsigned char *) q);
4359 if (count != (MagickOffsetType) length)
4361 q+=cache_info->number_channels*nexus_info->region.width;
4364 UnlockSemaphoreInfo(cache_info->file_semaphore);
4370 if (y < (ssize_t) rows)
4372 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4373 cache_info->cache_filename);
4374 return(MagickFalse);
4376 if ((cache_info->debug != MagickFalse) &&
4377 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4378 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4379 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4380 nexus_info->region.width,(double) nexus_info->region.height,(double)
4381 nexus_info->region.x,(double) nexus_info->region.y);
4386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4390 + R e f e r e n c e P i x e l C a c h e %
4394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4396 % ReferencePixelCache() increments the reference count associated with the
4397 % pixel cache returning a pointer to the cache.
4399 % The format of the ReferencePixelCache method is:
4401 % Cache ReferencePixelCache(Cache cache_info)
4403 % A description of each parameter follows:
4405 % o cache_info: the pixel cache.
4408 MagickPrivate Cache ReferencePixelCache(Cache cache)
4411 *restrict cache_info;
4413 assert(cache != (Cache *) NULL);
4414 cache_info=(CacheInfo *) cache;
4415 assert(cache_info->signature == MagickCoreSignature);
4416 LockSemaphoreInfo(cache_info->semaphore);
4417 cache_info->reference_count++;
4418 UnlockSemaphoreInfo(cache_info->semaphore);
4423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4427 + S e t P i x e l C a c h e M e t h o d s %
4431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4433 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4435 % The format of the SetPixelCacheMethods() method is:
4437 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4439 % A description of each parameter follows:
4441 % o cache: the pixel cache.
4443 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4446 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4449 *restrict cache_info;
4451 GetOneAuthenticPixelFromHandler
4452 get_one_authentic_pixel_from_handler;
4454 GetOneVirtualPixelFromHandler
4455 get_one_virtual_pixel_from_handler;
4458 Set cache pixel methods.
4460 assert(cache != (Cache) NULL);
4461 assert(cache_methods != (CacheMethods *) NULL);
4462 cache_info=(CacheInfo *) cache;
4463 assert(cache_info->signature == MagickCoreSignature);
4464 if (cache_info->debug != MagickFalse)
4465 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4466 cache_info->filename);
4467 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4468 cache_info->methods.get_virtual_pixel_handler=
4469 cache_methods->get_virtual_pixel_handler;
4470 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4471 cache_info->methods.destroy_pixel_handler=
4472 cache_methods->destroy_pixel_handler;
4473 if (cache_methods->get_virtual_metacontent_from_handler !=
4474 (GetVirtualMetacontentFromHandler) NULL)
4475 cache_info->methods.get_virtual_metacontent_from_handler=
4476 cache_methods->get_virtual_metacontent_from_handler;
4477 if (cache_methods->get_authentic_pixels_handler !=
4478 (GetAuthenticPixelsHandler) NULL)
4479 cache_info->methods.get_authentic_pixels_handler=
4480 cache_methods->get_authentic_pixels_handler;
4481 if (cache_methods->queue_authentic_pixels_handler !=
4482 (QueueAuthenticPixelsHandler) NULL)
4483 cache_info->methods.queue_authentic_pixels_handler=
4484 cache_methods->queue_authentic_pixels_handler;
4485 if (cache_methods->sync_authentic_pixels_handler !=
4486 (SyncAuthenticPixelsHandler) NULL)
4487 cache_info->methods.sync_authentic_pixels_handler=
4488 cache_methods->sync_authentic_pixels_handler;
4489 if (cache_methods->get_authentic_pixels_from_handler !=
4490 (GetAuthenticPixelsFromHandler) NULL)
4491 cache_info->methods.get_authentic_pixels_from_handler=
4492 cache_methods->get_authentic_pixels_from_handler;
4493 if (cache_methods->get_authentic_metacontent_from_handler !=
4494 (GetAuthenticMetacontentFromHandler) NULL)
4495 cache_info->methods.get_authentic_metacontent_from_handler=
4496 cache_methods->get_authentic_metacontent_from_handler;
4497 get_one_virtual_pixel_from_handler=
4498 cache_info->methods.get_one_virtual_pixel_from_handler;
4499 if (get_one_virtual_pixel_from_handler !=
4500 (GetOneVirtualPixelFromHandler) NULL)
4501 cache_info->methods.get_one_virtual_pixel_from_handler=
4502 cache_methods->get_one_virtual_pixel_from_handler;
4503 get_one_authentic_pixel_from_handler=
4504 cache_methods->get_one_authentic_pixel_from_handler;
4505 if (get_one_authentic_pixel_from_handler !=
4506 (GetOneAuthenticPixelFromHandler) NULL)
4507 cache_info->methods.get_one_authentic_pixel_from_handler=
4508 cache_methods->get_one_authentic_pixel_from_handler;
4512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4516 + S e t P i x e l C a c h e N e x u s P i x e l s %
4520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4522 % SetPixelCacheNexusPixels() defines the region of the cache for the
4523 % specified cache nexus.
4525 % The format of the SetPixelCacheNexusPixels() method is:
4527 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4528 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4529 % ExceptionInfo *exception)
4531 % A description of each parameter follows:
4533 % o cache_info: the pixel cache.
4535 % o mode: ReadMode, WriteMode, or IOMode.
4537 % o region: A pointer to the RectangleInfo structure that defines the
4538 % region of this particular cache nexus.
4540 % o nexus_info: the cache nexus to set.
4542 % o exception: return any errors or warnings in this structure.
4546 static inline MagickBooleanType AcquireCacheNexusPixels(
4547 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4548 ExceptionInfo *exception)
4550 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4551 return(MagickFalse);
4552 nexus_info->mapped=MagickFalse;
4553 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4554 (size_t) nexus_info->length));
4555 if (nexus_info->cache == (Quantum *) NULL)
4557 nexus_info->mapped=MagickTrue;
4558 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4559 nexus_info->length);
4561 if (nexus_info->cache == (Quantum *) NULL)
4563 (void) ThrowMagickException(exception,GetMagickModule(),
4564 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4565 cache_info->filename);
4566 return(MagickFalse);
4571 static inline MagickBooleanType IsPixelCacheAuthentic(
4572 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4581 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4583 if (cache_info->type == PingCache)
4585 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4586 nexus_info->region.x;
4587 status=nexus_info->pixels == (cache_info->pixels+offset*
4588 cache_info->number_channels) ? MagickTrue : MagickFalse;
4592 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4595 if (mode == ReadMode)
4597 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4600 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4603 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4604 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4605 ExceptionInfo *exception)
4614 assert(cache_info != (const CacheInfo *) NULL);
4615 assert(cache_info->signature == MagickCoreSignature);
4616 if (cache_info->type == UndefinedCache)
4617 return((Quantum *) NULL);
4618 nexus_info->region=(*region);
4619 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4625 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4626 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4627 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4628 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4629 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4630 ((nexus_info->region.width == cache_info->columns) ||
4631 ((nexus_info->region.width % cache_info->columns) == 0)))))
4637 Pixels are accessed directly from memory.
4639 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4640 nexus_info->region.x;
4641 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4643 nexus_info->metacontent=(void *) NULL;
4644 if (cache_info->metacontent_extent != 0)
4645 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4646 offset*cache_info->metacontent_extent;
4647 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4648 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4650 return(nexus_info->pixels);
4654 Pixels are stored in a staging region until they are synced to the cache.
4656 number_pixels=(MagickSizeType) nexus_info->region.width*
4657 nexus_info->region.height;
4658 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4659 if (cache_info->metacontent_extent != 0)
4660 length+=number_pixels*cache_info->metacontent_extent;
4661 if (nexus_info->cache == (Quantum *) NULL)
4663 nexus_info->length=length;
4664 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4665 if (status == MagickFalse)
4667 nexus_info->length=0;
4668 return((Quantum *) NULL);
4672 if (nexus_info->length < length)
4674 RelinquishCacheNexusPixels(nexus_info);
4675 nexus_info->length=length;
4676 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4677 if (status == MagickFalse)
4679 nexus_info->length=0;
4680 return((Quantum *) NULL);
4683 nexus_info->pixels=nexus_info->cache;
4684 nexus_info->metacontent=(void *) NULL;
4685 if (cache_info->metacontent_extent != 0)
4686 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4687 cache_info->number_channels);
4688 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4689 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4691 return(nexus_info->pixels);
4695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4699 % S e t P i x e l C a c h e V i r t u a l M e t h o d %
4703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4705 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4706 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4707 % access that is outside the boundaries of the image cache.
4709 % The format of the SetPixelCacheVirtualMethod() method is:
4711 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4712 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4714 % A description of each parameter follows:
4716 % o image: the image.
4718 % o virtual_pixel_method: choose the type of virtual pixel.
4720 % o exception: return any errors or warnings in this structure.
4724 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4725 ExceptionInfo *exception)
4728 *restrict cache_info;
4731 *restrict image_view;
4739 assert(image != (Image *) NULL);
4740 assert(image->signature == MagickCoreSignature);
4741 if (image->debug != MagickFalse)
4742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4743 assert(image->cache != (Cache) NULL);
4744 cache_info=(CacheInfo *) image->cache;
4745 assert(cache_info->signature == MagickCoreSignature);
4746 image->alpha_trait=BlendPixelTrait;
4748 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4749 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4750 #pragma omp parallel for schedule(static,4) shared(status) \
4751 magick_threads(image,image,1,1)
4753 for (y=0; y < (ssize_t) image->rows; y++)
4761 if (status == MagickFalse)
4763 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4764 if (q == (Quantum *) NULL)
4769 for (x=0; x < (ssize_t) image->columns; x++)
4771 SetPixelAlpha(image,alpha,q);
4772 q+=GetPixelChannels(image);
4774 status=SyncCacheViewAuthenticPixels(image_view,exception);
4776 image_view=DestroyCacheView(image_view);
4780 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4781 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4784 *restrict cache_info;
4789 assert(image != (Image *) NULL);
4790 assert(image->signature == MagickCoreSignature);
4791 if (image->debug != MagickFalse)
4792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4793 assert(image->cache != (Cache) NULL);
4794 cache_info=(CacheInfo *) image->cache;
4795 assert(cache_info->signature == MagickCoreSignature);
4796 method=cache_info->virtual_pixel_method;
4797 cache_info->virtual_pixel_method=virtual_pixel_method;
4798 if ((image->columns != 0) && (image->rows != 0))
4799 switch (virtual_pixel_method)
4801 case BackgroundVirtualPixelMethod:
4803 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4804 (image->alpha_trait == UndefinedPixelTrait))
4805 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4806 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4807 (IsGrayColorspace(image->colorspace) != MagickFalse))
4808 (void) SetImageColorspace(image,sRGBColorspace,exception);
4811 case TransparentVirtualPixelMethod:
4813 if (image->alpha_trait == UndefinedPixelTrait)
4814 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4828 + S y n c A u t h e n t i c P i x e l C a c h e N e x u s %
4832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4834 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4835 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4836 % is synced, otherwise MagickFalse.
4838 % The format of the SyncAuthenticPixelCacheNexus() method is:
4840 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4841 % NexusInfo *nexus_info,ExceptionInfo *exception)
4843 % A description of each parameter follows:
4845 % o image: the image.
4847 % o nexus_info: the cache nexus to sync.
4849 % o exception: return any errors or warnings in this structure.
4852 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4853 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4856 *restrict cache_info;
4862 Transfer pixels to the cache.
4864 assert(image != (Image *) NULL);
4865 assert(image->signature == MagickCoreSignature);
4866 if (image->cache == (Cache) NULL)
4867 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4868 cache_info=(CacheInfo *) image->cache;
4869 assert(cache_info->signature == MagickCoreSignature);
4870 if (cache_info->type == UndefinedCache)
4871 return(MagickFalse);
4872 if (nexus_info->authentic_pixel_cache != MagickFalse)
4874 image->taint=MagickTrue;
4877 assert(cache_info->signature == MagickCoreSignature);
4878 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4879 if ((cache_info->metacontent_extent != 0) &&
4880 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4881 return(MagickFalse);
4882 if (status != MagickFalse)
4883 image->taint=MagickTrue;
4888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4892 + S y n c A u t h e n t i c P i x e l C a c h e %
4896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4898 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4899 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4900 % otherwise MagickFalse.
4902 % The format of the SyncAuthenticPixelsCache() method is:
4904 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4905 % ExceptionInfo *exception)
4907 % A description of each parameter follows:
4909 % o image: the image.
4911 % o exception: return any errors or warnings in this structure.
4914 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4915 ExceptionInfo *exception)
4918 *restrict cache_info;
4921 id = GetOpenMPThreadId();
4926 assert(image != (Image *) NULL);
4927 assert(image->signature == MagickCoreSignature);
4928 assert(image->cache != (Cache) NULL);
4929 cache_info=(CacheInfo *) image->cache;
4930 assert(cache_info->signature == MagickCoreSignature);
4931 assert(id < (int) cache_info->number_threads);
4932 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4942 % S y n c A u t h e n t i c P i x e l s %
4946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4948 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4949 % The method returns MagickTrue if the pixel region is flushed, otherwise
4952 % The format of the SyncAuthenticPixels() method is:
4954 % MagickBooleanType SyncAuthenticPixels(Image *image,
4955 % ExceptionInfo *exception)
4957 % A description of each parameter follows:
4959 % o image: the image.
4961 % o exception: return any errors or warnings in this structure.
4964 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4965 ExceptionInfo *exception)
4968 *restrict cache_info;
4971 id = GetOpenMPThreadId();
4976 assert(image != (Image *) NULL);
4977 assert(image->signature == MagickCoreSignature);
4978 assert(image->cache != (Cache) NULL);
4979 cache_info=(CacheInfo *) image->cache;
4980 assert(cache_info->signature == MagickCoreSignature);
4981 if (cache_info->methods.sync_authentic_pixels_handler !=
4982 (SyncAuthenticPixelsHandler) NULL)
4984 status=cache_info->methods.sync_authentic_pixels_handler(image,
4988 assert(id < (int) cache_info->number_threads);
4989 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4999 + S y n c I m a g e P i x e l C a c h e %
5003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5005 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5006 % The method returns MagickTrue if the pixel region is flushed, otherwise
5009 % The format of the SyncImagePixelCache() method is:
5011 % MagickBooleanType SyncImagePixelCache(Image *image,
5012 % ExceptionInfo *exception)
5014 % A description of each parameter follows:
5016 % o image: the image.
5018 % o exception: return any errors or warnings in this structure.
5021 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5022 ExceptionInfo *exception)
5025 *restrict cache_info;
5027 assert(image != (Image *) NULL);
5028 assert(exception != (ExceptionInfo *) NULL);
5029 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5030 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5038 + 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 %
5042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5044 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5045 % of the pixel cache.
5047 % The format of the WritePixelCacheMetacontent() method is:
5049 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5050 % NexusInfo *nexus_info,ExceptionInfo *exception)
5052 % A description of each parameter follows:
5054 % o cache_info: the pixel cache.
5056 % o nexus_info: the cache nexus to write the meta-content.
5058 % o exception: return any errors or warnings in this structure.
5061 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5062 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5072 register const unsigned char
5081 if (cache_info->metacontent_extent == 0)
5082 return(MagickFalse);
5083 if (nexus_info->authentic_pixel_cache != MagickFalse)
5085 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5086 nexus_info->region.x;
5087 length=(MagickSizeType) nexus_info->region.width*
5088 cache_info->metacontent_extent;
5089 extent=(MagickSizeType) length*nexus_info->region.height;
5090 rows=nexus_info->region.height;
5092 p=(unsigned char *) nexus_info->metacontent;
5093 switch (cache_info->type)
5098 register unsigned char
5102 Write associated pixels to memory.
5104 if ((cache_info->columns == nexus_info->region.width) &&
5105 (extent == (MagickSizeType) ((size_t) extent)))
5110 q=(unsigned char *) cache_info->metacontent+offset*
5111 cache_info->metacontent_extent;
5112 for (y=0; y < (ssize_t) rows; y++)
5114 (void) memcpy(q,p,(size_t) length);
5115 p+=nexus_info->region.width*cache_info->metacontent_extent;
5116 q+=cache_info->columns*cache_info->metacontent_extent;
5123 Write associated pixels to disk.
5125 LockSemaphoreInfo(cache_info->file_semaphore);
5126 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5128 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5129 cache_info->cache_filename);
5130 UnlockSemaphoreInfo(cache_info->file_semaphore);
5131 return(MagickFalse);
5133 if ((cache_info->columns == nexus_info->region.width) &&
5134 (extent <= MagickMaxBufferExtent))
5139 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5140 for (y=0; y < (ssize_t) rows; y++)
5142 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5143 cache_info->number_channels*sizeof(Quantum)+offset*
5144 cache_info->metacontent_extent,length,(const unsigned char *) p);
5145 if (count != (MagickOffsetType) length)
5147 p+=cache_info->metacontent_extent*nexus_info->region.width;
5148 offset+=cache_info->columns;
5150 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5151 (void) ClosePixelCacheOnDisk(cache_info);
5152 UnlockSemaphoreInfo(cache_info->file_semaphore);
5155 case DistributedCache:
5161 Write metacontent to distributed cache.
5163 LockSemaphoreInfo(cache_info->file_semaphore);
5164 region=nexus_info->region;
5165 if ((cache_info->columns != nexus_info->region.width) ||
5166 (extent > MagickMaxBufferExtent))
5173 for (y=0; y < (ssize_t) rows; y++)
5175 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5176 cache_info->server_info,®ion,length,(const unsigned char *) p);
5177 if (count != (MagickOffsetType) length)
5179 p+=cache_info->metacontent_extent*nexus_info->region.width;
5182 UnlockSemaphoreInfo(cache_info->file_semaphore);
5188 if (y < (ssize_t) rows)
5190 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5191 cache_info->cache_filename);
5192 return(MagickFalse);
5194 if ((cache_info->debug != MagickFalse) &&
5195 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5196 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5197 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5198 nexus_info->region.width,(double) nexus_info->region.height,(double)
5199 nexus_info->region.x,(double) nexus_info->region.y);
5204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5208 + W r i t e C a c h e P i x e l s %
5212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5214 % WritePixelCachePixels() writes image pixels to the specified region of the
5217 % The format of the WritePixelCachePixels() method is:
5219 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5220 % NexusInfo *nexus_info,ExceptionInfo *exception)
5222 % A description of each parameter follows:
5224 % o cache_info: the pixel cache.
5226 % o nexus_info: the cache nexus to write the pixels.
5228 % o exception: return any errors or warnings in this structure.
5231 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5232 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5242 register const Quantum
5251 if (nexus_info->authentic_pixel_cache != MagickFalse)
5253 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5254 nexus_info->region.x;
5255 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5257 extent=length*nexus_info->region.height;
5258 rows=nexus_info->region.height;
5260 p=nexus_info->pixels;
5261 switch (cache_info->type)
5270 Write pixels to memory.
5272 if ((cache_info->columns == nexus_info->region.width) &&
5273 (extent == (MagickSizeType) ((size_t) extent)))
5278 q=cache_info->pixels+offset*cache_info->number_channels;
5279 for (y=0; y < (ssize_t) rows; y++)
5281 (void) memcpy(q,p,(size_t) length);
5282 p+=cache_info->number_channels*nexus_info->region.width;
5283 q+=cache_info->columns*cache_info->number_channels;
5290 Write pixels to disk.
5292 LockSemaphoreInfo(cache_info->file_semaphore);
5293 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5295 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5296 cache_info->cache_filename);
5297 UnlockSemaphoreInfo(cache_info->file_semaphore);
5298 return(MagickFalse);
5300 if ((cache_info->columns == nexus_info->region.width) &&
5301 (extent <= MagickMaxBufferExtent))
5306 for (y=0; y < (ssize_t) rows; y++)
5308 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5309 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5311 if (count != (MagickOffsetType) length)
5313 p+=cache_info->number_channels*nexus_info->region.width;
5314 offset+=cache_info->columns;
5316 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5317 (void) ClosePixelCacheOnDisk(cache_info);
5318 UnlockSemaphoreInfo(cache_info->file_semaphore);
5321 case DistributedCache:
5327 Write pixels to distributed cache.
5329 LockSemaphoreInfo(cache_info->file_semaphore);
5330 region=nexus_info->region;
5331 if ((cache_info->columns != nexus_info->region.width) ||
5332 (extent > MagickMaxBufferExtent))
5339 for (y=0; y < (ssize_t) rows; y++)
5341 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5342 cache_info->server_info,®ion,length,(const unsigned char *) p);
5343 if (count != (MagickOffsetType) length)
5345 p+=cache_info->number_channels*nexus_info->region.width;
5348 UnlockSemaphoreInfo(cache_info->file_semaphore);
5354 if (y < (ssize_t) rows)
5356 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5357 cache_info->cache_filename);
5358 return(MagickFalse);
5360 if ((cache_info->debug != MagickFalse) &&
5361 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5362 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5363 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5364 nexus_info->region.width,(double) nexus_info->region.height,(double)
5365 nexus_info->region.x,(double) nexus_info->region.y);