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=MagickSignature;
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=MagickSignature;
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 == MagickSignature);
298 assert(exception != (ExceptionInfo *) NULL);
299 assert(exception->signature == MagickSignature);
300 assert(image->cache != (Cache) NULL);
301 cache_info=(CacheInfo *) image->cache;
302 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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)
487 buffer[MagickMaxBufferExtent];
490 Clone pixel cache on disk with identifcal morphology.
492 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
493 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
495 #if defined(MAGICKCORE_HAVE_SENDFILE)
496 if (cache_info->length == (MagickSizeType) ((ssize_t) cache_info->length))
502 count=sendfile(clone_info->file,cache_info->file,&offset,(size_t)
504 if (count == (ssize_t) cache_info->length)
509 while ((count=read(cache_info->file,buffer,sizeof(buffer))) > 0)
514 number_bytes=write(clone_info->file,buffer,(size_t) count);
515 if (number_bytes != count)
517 extent+=number_bytes;
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) && (cache_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 == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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=(~MagickSignature);
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=(~MagickSignature);
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 == MagickSignature);
1046 assert(image->cache != (Cache) NULL);
1047 cache_info=(CacheInfo *) image->cache;
1048 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
1097 assert(image->cache != (Cache) NULL);
1098 cache_info=(CacheInfo *) image->cache;
1099 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
1203 assert(image->cache != (Cache) NULL);
1204 cache_info=(CacheInfo *) image->cache;
1205 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
1244 assert(image->cache != (Cache) NULL);
1245 cache_info=(CacheInfo *) image->cache;
1246 assert(cache_info->signature == MagickSignature);
1247 if (cache_info->methods.get_authentic_pixels_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 == MagickSignature);
1313 assert(image->cache != (Cache) NULL);
1314 cache_info=(CacheInfo *) image->cache;
1315 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
1621 assert(image->cache != (Cache) NULL);
1622 cache_info=(CacheInfo *) image->cache;
1623 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
1692 assert(image->cache != (Cache) NULL);
1693 cache_info=(CacheInfo *) image->cache;
1694 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
1749 assert(image->cache != (Cache) NULL);
1750 cache_info=(CacheInfo *) image->cache;
1751 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
1804 assert(image->cache != (Cache) NULL);
1805 cache_info=(CacheInfo *) image->cache;
1806 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
1867 assert(image->cache != (Cache) NULL);
1868 cache_info=(CacheInfo *) image->cache;
1869 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
1926 assert(image->cache != (Cache) NULL);
1927 cache_info=(CacheInfo *) image->cache;
1928 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
2095 assert(image->cache != (Cache) NULL);
2096 assert(length != (MagickSizeType *) NULL);
2097 assert(exception != (ExceptionInfo *) NULL);
2098 assert(exception->signature == MagickSignature);
2099 cache_info=(CacheInfo *) image->cache;
2100 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
2181 if (image->debug != MagickFalse)
2182 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2183 cache_info=(CacheInfo *) image->cache;
2184 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
2222 assert(image->cache != (Cache) NULL);
2223 cache_info=(CacheInfo *) image->cache;
2224 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
2264 assert(image->cache != (Cache) NULL);
2265 cache_info=(CacheInfo *) image->cache;
2266 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
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 == MagickSignature);
2350 assert(image->cache != (Cache) NULL);
2351 cache_info=(CacheInfo *) image->cache;
2352 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
2538 assert(image->cache != (Cache) NULL);
2539 cache_info=(CacheInfo *) image->cache;
2540 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
2929 assert(image->cache != (Cache) NULL);
2930 cache_info=(CacheInfo *) image->cache;
2931 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
2971 assert(image->cache != (Cache) NULL);
2972 cache_info=(CacheInfo *) image->cache;
2973 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
3044 assert(image->cache != (Cache) NULL);
3045 cache_info=(CacheInfo *) image->cache;
3046 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
3090 assert(image->cache != (Cache) NULL);
3091 cache_info=(CacheInfo *) image->cache;
3092 assert(cache_info->signature == MagickSignature);
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 == MagickSignature);
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 register MagickOffsetType
3255 #if !defined(MAGICKCORE_HAVE_PWRITE)
3256 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3257 return((MagickOffsetType) -1);
3260 for (i=0; i < (MagickOffsetType) length; i+=count)
3262 #if !defined(MAGICKCORE_HAVE_PWRITE)
3263 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3264 (MagickSizeType) SSIZE_MAX));
3266 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3267 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3279 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3282 *restrict cache_info;
3289 cache_info=(CacheInfo *) image->cache;
3290 if (image->debug != MagickFalse)
3293 format[MagickPathExtent],
3294 message[MagickPathExtent];
3296 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3297 (void) FormatLocaleString(message,MagickPathExtent,
3298 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3299 cache_info->cache_filename,cache_info->file,format);
3300 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3302 if (length != (MagickSizeType) ((MagickOffsetType) length))
3303 return(MagickFalse);
3304 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3306 return(MagickFalse);
3307 if ((MagickSizeType) offset >= length)
3309 extent=(MagickOffsetType) length-1;
3310 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3311 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3312 if (cache_info->synchronize != MagickFalse)
3313 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3316 (void) signal(SIGBUS,CacheSignalHandler);
3318 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3321 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3322 ExceptionInfo *exception)
3325 *restrict cache_info,
3329 format[MagickPathExtent],
3330 message[MagickPathExtent];
3346 assert(image != (const Image *) NULL);
3347 assert(image->signature == MagickSignature);
3348 assert(image->cache != (Cache) NULL);
3349 if (image->debug != MagickFalse)
3350 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3351 if ((image->columns == 0) || (image->rows == 0))
3352 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3353 cache_info=(CacheInfo *) image->cache;
3354 assert(cache_info->signature == MagickSignature);
3355 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3356 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3357 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3359 source_info=(*cache_info);
3360 source_info.file=(-1);
3361 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3362 image->filename,(double) GetImageIndexInList(image));
3363 cache_info->storage_class=image->storage_class;
3364 cache_info->colorspace=image->colorspace;
3365 cache_info->alpha_trait=image->alpha_trait;
3366 cache_info->read_mask=image->read_mask;
3367 cache_info->write_mask=image->write_mask;
3368 cache_info->rows=image->rows;
3369 cache_info->columns=image->columns;
3370 InitializePixelChannelMap(image);
3371 cache_info->number_channels=GetPixelChannels(image);
3372 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3373 sizeof(*image->channel_map));
3374 cache_info->metacontent_extent=image->metacontent_extent;
3375 cache_info->mode=mode;
3376 if (image->ping != MagickFalse)
3378 cache_info->storage_class=image->storage_class;
3379 cache_info->colorspace=image->colorspace;
3380 cache_info->type=PingCache;
3383 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3384 packet_size=cache_info->number_channels*sizeof(Quantum);
3385 if (image->metacontent_extent != 0)
3386 packet_size+=cache_info->metacontent_extent;
3387 length=number_pixels*packet_size;
3388 columns=(size_t) (length/cache_info->rows/packet_size);
3389 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3390 ((ssize_t) cache_info->rows < 0))
3391 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3393 cache_info->length=length;
3394 status=AcquireMagickResource(AreaResource,cache_info->length);
3395 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3396 cache_info->metacontent_extent);
3397 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3399 status=AcquireMagickResource(MemoryResource,cache_info->length);
3400 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3401 (cache_info->type == MemoryCache))
3403 AllocatePixelCachePixels(cache_info);
3404 if (cache_info->pixels == (Quantum *) NULL)
3405 cache_info->pixels=source_info.pixels;
3409 Create memory pixel cache.
3412 cache_info->type=MemoryCache;
3413 cache_info->metacontent=(void *) NULL;
3414 if (cache_info->metacontent_extent != 0)
3415 cache_info->metacontent=(void *) (cache_info->pixels+
3416 number_pixels*cache_info->number_channels);
3417 if ((source_info.storage_class != UndefinedClass) &&
3420 status=ClonePixelCacheRepository(cache_info,&source_info,
3422 RelinquishPixelCachePixels(&source_info);
3424 if (image->debug != MagickFalse)
3426 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3427 MagickPathExtent,format);
3428 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3430 (void) FormatLocaleString(message,MagickPathExtent,
3431 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3432 cache_info->filename,cache_info->mapped != MagickFalse ?
3433 "Anonymous" : "Heap",type,(double) cache_info->columns,
3434 (double) cache_info->rows,(double)
3435 cache_info->number_channels,format);
3436 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3442 RelinquishMagickResource(MemoryResource,cache_info->length);
3445 Create pixel cache on disk.
3447 status=AcquireMagickResource(DiskResource,cache_info->length);
3448 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3453 if (cache_info->type == DistributedCache)
3454 RelinquishMagickResource(DiskResource,cache_info->length);
3455 server_info=AcquireDistributeCacheInfo(exception);
3456 if (server_info != (DistributeCacheInfo *) NULL)
3458 status=OpenDistributePixelCache(server_info,image);
3459 if (status == MagickFalse)
3461 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3462 GetDistributeCacheHostname(server_info));
3463 server_info=DestroyDistributeCacheInfo(server_info);
3468 Create a distributed pixel cache.
3470 cache_info->type=DistributedCache;
3471 cache_info->server_info=server_info;
3472 (void) FormatLocaleString(cache_info->cache_filename,
3473 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3474 (DistributeCacheInfo *) cache_info->server_info),
3475 GetDistributeCachePort((DistributeCacheInfo *)
3476 cache_info->server_info));
3477 if ((source_info.storage_class != UndefinedClass) &&
3480 status=ClonePixelCacheRepository(cache_info,&source_info,
3482 RelinquishPixelCachePixels(&source_info);
3484 if (image->debug != MagickFalse)
3486 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3487 MagickPathExtent,format);
3488 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3490 (void) FormatLocaleString(message,MagickPathExtent,
3491 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3492 cache_info->filename,cache_info->cache_filename,
3493 GetDistributeCacheFile((DistributeCacheInfo *)
3494 cache_info->server_info),type,(double) cache_info->columns,
3495 (double) cache_info->rows,(double)
3496 cache_info->number_channels,format);
3497 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3503 RelinquishMagickResource(DiskResource,cache_info->length);
3504 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3505 "CacheResourcesExhausted","`%s'",image->filename);
3506 return(MagickFalse);
3508 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3510 (void) ClosePixelCacheOnDisk(cache_info);
3511 *cache_info->cache_filename='\0';
3513 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3515 RelinquishMagickResource(DiskResource,cache_info->length);
3516 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3518 return(MagickFalse);
3520 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3521 cache_info->length);
3522 if (status == MagickFalse)
3524 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3526 return(MagickFalse);
3528 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3529 cache_info->metacontent_extent);
3530 if (length != (MagickSizeType) ((size_t) length))
3531 cache_info->type=DiskCache;
3534 status=AcquireMagickResource(MapResource,cache_info->length);
3535 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3536 (cache_info->type != MemoryCache))
3537 cache_info->type=DiskCache;
3540 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3541 cache_info->offset,(size_t) cache_info->length);
3542 if (cache_info->pixels == (Quantum *) NULL)
3544 cache_info->type=DiskCache;
3545 cache_info->pixels=source_info.pixels;
3550 Create file-backed memory-mapped pixel cache.
3553 (void) ClosePixelCacheOnDisk(cache_info);
3554 cache_info->type=MapCache;
3555 cache_info->mapped=MagickTrue;
3556 cache_info->metacontent=(void *) NULL;
3557 if (cache_info->metacontent_extent != 0)
3558 cache_info->metacontent=(void *) (cache_info->pixels+
3559 number_pixels*cache_info->number_channels);
3560 if ((source_info.storage_class != UndefinedClass) &&
3563 status=ClonePixelCacheRepository(cache_info,&source_info,
3565 RelinquishPixelCachePixels(&source_info);
3567 if (image->debug != MagickFalse)
3569 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3570 MagickPathExtent,format);
3571 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3573 (void) FormatLocaleString(message,MagickPathExtent,
3574 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3575 cache_info->filename,cache_info->cache_filename,
3576 cache_info->file,type,(double) cache_info->columns,(double)
3577 cache_info->rows,(double) cache_info->number_channels,
3579 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3585 RelinquishMagickResource(MapResource,cache_info->length);
3588 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3590 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3591 RelinquishPixelCachePixels(&source_info);
3593 if (image->debug != MagickFalse)
3595 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",MagickPathExtent,
3597 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3599 (void) FormatLocaleString(message,MagickPathExtent,
3600 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3601 cache_info->cache_filename,cache_info->file,type,(double)
3602 cache_info->columns,(double) cache_info->rows,(double)
3603 cache_info->number_channels,format);
3604 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614 + P e r s i s t P i x e l C a c h e %
3618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3620 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3621 % persistent pixel cache is one that resides on disk and is not destroyed
3622 % when the program exits.
3624 % The format of the PersistPixelCache() method is:
3626 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3627 % const MagickBooleanType attach,MagickOffsetType *offset,
3628 % ExceptionInfo *exception)
3630 % A description of each parameter follows:
3632 % o image: the image.
3634 % o filename: the persistent pixel cache filename.
3636 % o attach: A value other than zero initializes the persistent pixel cache.
3638 % o initialize: A value other than zero initializes the persistent pixel
3641 % o offset: the offset in the persistent cache to store pixels.
3643 % o exception: return any errors or warnings in this structure.
3646 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3647 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3648 ExceptionInfo *exception)
3651 *restrict cache_info,
3652 *restrict clone_info;
3663 assert(image != (Image *) NULL);
3664 assert(image->signature == MagickSignature);
3665 if (image->debug != MagickFalse)
3666 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3667 assert(image->cache != (void *) NULL);
3668 assert(filename != (const char *) NULL);
3669 assert(offset != (MagickOffsetType *) NULL);
3670 page_size=GetMagickPageSize();
3671 cache_info=(CacheInfo *) image->cache;
3672 assert(cache_info->signature == MagickSignature);
3673 if (attach != MagickFalse)
3676 Attach existing persistent pixel cache.
3678 if (image->debug != MagickFalse)
3679 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3680 "attach persistent cache");
3681 (void) CopyMagickString(cache_info->cache_filename,filename,
3683 cache_info->type=DiskCache;
3684 cache_info->offset=(*offset);
3685 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3686 return(MagickFalse);
3687 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3690 if ((cache_info->mode != ReadMode) &&
3691 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3692 (cache_info->reference_count == 1))
3694 LockSemaphoreInfo(cache_info->semaphore);
3695 if ((cache_info->mode != ReadMode) &&
3696 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3697 (cache_info->reference_count == 1))
3703 Usurp existing persistent pixel cache.
3705 status=rename_utf8(cache_info->cache_filename,filename);
3708 (void) CopyMagickString(cache_info->cache_filename,filename,
3710 *offset+=cache_info->length+page_size-(cache_info->length %
3712 UnlockSemaphoreInfo(cache_info->semaphore);
3713 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3714 if (image->debug != MagickFalse)
3715 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3716 "Usurp resident persistent cache");
3720 UnlockSemaphoreInfo(cache_info->semaphore);
3723 Clone persistent pixel cache.
3725 clone_image=(*image);
3726 clone_info=(CacheInfo *) clone_image.cache;
3727 image->cache=ClonePixelCache(cache_info);
3728 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3729 (void) CopyMagickString(cache_info->cache_filename,filename,MagickPathExtent);
3730 cache_info->type=DiskCache;
3731 cache_info->offset=(*offset);
3732 cache_info=(CacheInfo *) image->cache;
3733 status=OpenPixelCache(image,IOMode,exception);
3734 if (status != MagickFalse)
3735 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3736 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3737 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3746 + 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 %
3750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3752 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3753 % defined by the region rectangle and returns a pointer to the region. This
3754 % region is subsequently transferred from the pixel cache with
3755 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3756 % pixels are transferred, otherwise a NULL is returned.
3758 % The format of the QueueAuthenticPixelCacheNexus() method is:
3760 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3761 % const ssize_t y,const size_t columns,const size_t rows,
3762 % const MagickBooleanType clone,NexusInfo *nexus_info,
3763 % ExceptionInfo *exception)
3765 % A description of each parameter follows:
3767 % o image: the image.
3769 % o x,y,columns,rows: These values define the perimeter of a region of
3772 % o nexus_info: the cache nexus to set.
3774 % o clone: clone the pixel cache.
3776 % o exception: return any errors or warnings in this structure.
3779 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3780 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3781 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3784 *restrict cache_info;
3799 Validate pixel cache geometry.
3801 assert(image != (const Image *) NULL);
3802 assert(image->signature == MagickSignature);
3803 assert(image->cache != (Cache) NULL);
3804 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3805 if (cache_info == (Cache) NULL)
3806 return((Quantum *) NULL);
3807 assert(cache_info->signature == MagickSignature);
3808 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3809 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3810 (y >= (ssize_t) cache_info->rows))
3812 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3813 "PixelsAreNotAuthentic","`%s'",image->filename);
3814 return((Quantum *) NULL);
3816 offset=(MagickOffsetType) y*cache_info->columns+x;
3818 return((Quantum *) NULL);
3819 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3820 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3821 if ((MagickSizeType) offset >= number_pixels)
3822 return((Quantum *) NULL);
3828 region.width=columns;
3830 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3840 + 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 %
3844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3846 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3847 % defined by the region rectangle and returns a pointer to the region. This
3848 % region is subsequently transferred from the pixel cache with
3849 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3850 % pixels are transferred, otherwise a NULL is returned.
3852 % The format of the QueueAuthenticPixelsCache() method is:
3854 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3855 % const ssize_t y,const size_t columns,const size_t rows,
3856 % ExceptionInfo *exception)
3858 % A description of each parameter follows:
3860 % o image: the image.
3862 % o x,y,columns,rows: These values define the perimeter of a region of
3865 % o exception: return any errors or warnings in this structure.
3868 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3869 const ssize_t y,const size_t columns,const size_t rows,
3870 ExceptionInfo *exception)
3873 *restrict cache_info;
3876 id = GetOpenMPThreadId();
3881 assert(image != (const Image *) NULL);
3882 assert(image->signature == MagickSignature);
3883 assert(image->cache != (Cache) NULL);
3884 cache_info=(CacheInfo *) image->cache;
3885 assert(cache_info->signature == MagickSignature);
3886 assert(id < (int) cache_info->number_threads);
3887 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3888 cache_info->nexus_info[id],exception);
3893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3897 % Q u e u e A u t h e n t i c P i x e l s %
3901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3903 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3904 % successfully initialized a pointer to a Quantum array representing the
3905 % region is returned, otherwise NULL is returned. The returned pointer may
3906 % point to a temporary working buffer for the pixels or it may point to the
3907 % final location of the pixels in memory.
3909 % Write-only access means that any existing pixel values corresponding to
3910 % the region are ignored. This is useful if the initial image is being
3911 % created from scratch, or if the existing pixel values are to be
3912 % completely replaced without need to refer to their pre-existing values.
3913 % The application is free to read and write the pixel buffer returned by
3914 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3915 % initialize the pixel array values. Initializing pixel array values is the
3916 % application's responsibility.
3918 % Performance is maximized if the selected region is part of one row, or
3919 % one or more full rows, since then there is opportunity to access the
3920 % pixels in-place (without a copy) if the image is in memory, or in a
3921 % memory-mapped file. The returned pointer must *never* be deallocated
3924 % Pixels accessed via the returned pointer represent a simple array of type
3925 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3926 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3927 % obtain the meta-content (of type void) corresponding to the region.
3928 % Once the Quantum (and/or Quantum) array has been updated, the
3929 % changes must be saved back to the underlying image using
3930 % SyncAuthenticPixels() or they may be lost.
3932 % The format of the QueueAuthenticPixels() method is:
3934 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3935 % const ssize_t y,const size_t columns,const size_t rows,
3936 % ExceptionInfo *exception)
3938 % A description of each parameter follows:
3940 % o image: the image.
3942 % o x,y,columns,rows: These values define the perimeter of a region of
3945 % o exception: return any errors or warnings in this structure.
3948 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3949 const ssize_t y,const size_t columns,const size_t rows,
3950 ExceptionInfo *exception)
3953 *restrict cache_info;
3956 id = GetOpenMPThreadId();
3961 assert(image != (Image *) NULL);
3962 assert(image->signature == MagickSignature);
3963 assert(image->cache != (Cache) NULL);
3964 cache_info=(CacheInfo *) image->cache;
3965 assert(cache_info->signature == MagickSignature);
3966 if (cache_info->methods.queue_authentic_pixels_handler !=
3967 (QueueAuthenticPixelsHandler) NULL)
3969 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3970 columns,rows,exception);
3973 assert(id < (int) cache_info->number_threads);
3974 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3975 cache_info->nexus_info[id],exception);
3980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3984 + 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 %
3988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3990 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3993 % The format of the ReadPixelCacheMetacontent() method is:
3995 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
3996 % NexusInfo *nexus_info,ExceptionInfo *exception)
3998 % A description of each parameter follows:
4000 % o cache_info: the pixel cache.
4002 % o nexus_info: the cache nexus to read the metacontent.
4004 % o exception: return any errors or warnings in this structure.
4008 static inline MagickOffsetType ReadPixelCacheRegion(
4009 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
4010 const MagickSizeType length,unsigned char *restrict buffer)
4012 register MagickOffsetType
4018 #if !defined(MAGICKCORE_HAVE_PREAD)
4019 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4020 return((MagickOffsetType) -1);
4023 for (i=0; i < (MagickOffsetType) length; i+=count)
4025 #if !defined(MAGICKCORE_HAVE_PREAD)
4026 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4027 (MagickSizeType) SSIZE_MAX));
4029 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
4030 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4042 static MagickBooleanType ReadPixelCacheMetacontent(
4043 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
4044 ExceptionInfo *exception)
4057 register unsigned char
4063 if (cache_info->metacontent_extent == 0)
4064 return(MagickFalse);
4065 if (nexus_info->authentic_pixel_cache != MagickFalse)
4067 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4068 nexus_info->region.x;
4069 length=(MagickSizeType) nexus_info->region.width*
4070 cache_info->metacontent_extent;
4071 extent=length*nexus_info->region.height;
4072 rows=nexus_info->region.height;
4074 q=(unsigned char *) nexus_info->metacontent;
4075 switch (cache_info->type)
4080 register unsigned char
4084 Read meta-content from memory.
4086 if ((cache_info->columns == nexus_info->region.width) &&
4087 (extent == (MagickSizeType) ((size_t) extent)))
4092 p=(unsigned char *) cache_info->metacontent+offset*
4093 cache_info->metacontent_extent;
4094 for (y=0; y < (ssize_t) rows; y++)
4096 (void) memcpy(q,p,(size_t) length);
4097 p+=cache_info->metacontent_extent*cache_info->columns;
4098 q+=cache_info->metacontent_extent*nexus_info->region.width;
4105 Read meta content from disk.
4107 LockSemaphoreInfo(cache_info->file_semaphore);
4108 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4110 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4111 cache_info->cache_filename);
4112 UnlockSemaphoreInfo(cache_info->file_semaphore);
4113 return(MagickFalse);
4115 if ((cache_info->columns == nexus_info->region.width) &&
4116 (extent <= MagickMaxBufferExtent))
4121 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4122 for (y=0; y < (ssize_t) rows; y++)
4124 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4125 cache_info->number_channels*sizeof(Quantum)+offset*
4126 cache_info->metacontent_extent,length,(unsigned char *) q);
4127 if (count != (MagickOffsetType) length)
4129 offset+=cache_info->columns;
4130 q+=cache_info->metacontent_extent*nexus_info->region.width;
4132 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4133 (void) ClosePixelCacheOnDisk(cache_info);
4134 UnlockSemaphoreInfo(cache_info->file_semaphore);
4137 case DistributedCache:
4143 Read metacontent from distributed cache.
4145 LockSemaphoreInfo(cache_info->file_semaphore);
4146 region=nexus_info->region;
4147 if ((cache_info->columns != nexus_info->region.width) ||
4148 (extent > MagickMaxBufferExtent))
4155 for (y=0; y < (ssize_t) rows; y++)
4157 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4158 cache_info->server_info,®ion,length,(unsigned char *) q);
4159 if (count != (MagickOffsetType) length)
4161 q+=cache_info->metacontent_extent*nexus_info->region.width;
4164 UnlockSemaphoreInfo(cache_info->file_semaphore);
4170 if (y < (ssize_t) rows)
4172 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4173 cache_info->cache_filename);
4174 return(MagickFalse);
4176 if ((cache_info->debug != MagickFalse) &&
4177 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4178 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4179 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4180 nexus_info->region.width,(double) nexus_info->region.height,(double)
4181 nexus_info->region.x,(double) nexus_info->region.y);
4186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4190 + R e a d P i x e l C a c h e P i x e l s %
4194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4196 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4199 % The format of the ReadPixelCachePixels() method is:
4201 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4202 % NexusInfo *nexus_info,ExceptionInfo *exception)
4204 % A description of each parameter follows:
4206 % o cache_info: the pixel cache.
4208 % o nexus_info: the cache nexus to read the pixels.
4210 % o exception: return any errors or warnings in this structure.
4213 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4214 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4233 if (nexus_info->authentic_pixel_cache != MagickFalse)
4235 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4236 nexus_info->region.x;
4237 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4239 extent=length*nexus_info->region.height;
4240 rows=nexus_info->region.height;
4242 q=nexus_info->pixels;
4243 switch (cache_info->type)
4252 Read pixels from memory.
4254 if ((cache_info->columns == nexus_info->region.width) &&
4255 (extent == (MagickSizeType) ((size_t) extent)))
4260 p=cache_info->pixels+offset*cache_info->number_channels;
4261 for (y=0; y < (ssize_t) rows; y++)
4263 (void) memcpy(q,p,(size_t) length);
4264 p+=cache_info->number_channels*cache_info->columns;
4265 q+=cache_info->number_channels*nexus_info->region.width;
4272 Read pixels from disk.
4274 LockSemaphoreInfo(cache_info->file_semaphore);
4275 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4277 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4278 cache_info->cache_filename);
4279 UnlockSemaphoreInfo(cache_info->file_semaphore);
4280 return(MagickFalse);
4282 if ((cache_info->columns == nexus_info->region.width) &&
4283 (extent <= MagickMaxBufferExtent))
4288 for (y=0; y < (ssize_t) rows; y++)
4290 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4291 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4292 if (count != (MagickOffsetType) length)
4294 offset+=cache_info->columns;
4295 q+=cache_info->number_channels*nexus_info->region.width;
4297 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4298 (void) ClosePixelCacheOnDisk(cache_info);
4299 UnlockSemaphoreInfo(cache_info->file_semaphore);
4302 case DistributedCache:
4308 Read pixels from distributed cache.
4310 LockSemaphoreInfo(cache_info->file_semaphore);
4311 region=nexus_info->region;
4312 if ((cache_info->columns != nexus_info->region.width) ||
4313 (extent > MagickMaxBufferExtent))
4320 for (y=0; y < (ssize_t) rows; y++)
4322 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4323 cache_info->server_info,®ion,length,(unsigned char *) q);
4324 if (count != (MagickOffsetType) length)
4326 q+=cache_info->number_channels*nexus_info->region.width;
4329 UnlockSemaphoreInfo(cache_info->file_semaphore);
4335 if (y < (ssize_t) rows)
4337 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4338 cache_info->cache_filename);
4339 return(MagickFalse);
4341 if ((cache_info->debug != MagickFalse) &&
4342 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4343 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4344 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4345 nexus_info->region.width,(double) nexus_info->region.height,(double)
4346 nexus_info->region.x,(double) nexus_info->region.y);
4351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4355 + R e f e r e n c e P i x e l C a c h e %
4359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4361 % ReferencePixelCache() increments the reference count associated with the
4362 % pixel cache returning a pointer to the cache.
4364 % The format of the ReferencePixelCache method is:
4366 % Cache ReferencePixelCache(Cache cache_info)
4368 % A description of each parameter follows:
4370 % o cache_info: the pixel cache.
4373 MagickPrivate Cache ReferencePixelCache(Cache cache)
4376 *restrict cache_info;
4378 assert(cache != (Cache *) NULL);
4379 cache_info=(CacheInfo *) cache;
4380 assert(cache_info->signature == MagickSignature);
4381 LockSemaphoreInfo(cache_info->semaphore);
4382 cache_info->reference_count++;
4383 UnlockSemaphoreInfo(cache_info->semaphore);
4388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4392 + S e t P i x e l C a c h e M e t h o d s %
4396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4398 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4400 % The format of the SetPixelCacheMethods() method is:
4402 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4404 % A description of each parameter follows:
4406 % o cache: the pixel cache.
4408 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4411 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4414 *restrict cache_info;
4416 GetOneAuthenticPixelFromHandler
4417 get_one_authentic_pixel_from_handler;
4419 GetOneVirtualPixelFromHandler
4420 get_one_virtual_pixel_from_handler;
4423 Set cache pixel methods.
4425 assert(cache != (Cache) NULL);
4426 assert(cache_methods != (CacheMethods *) NULL);
4427 cache_info=(CacheInfo *) cache;
4428 assert(cache_info->signature == MagickSignature);
4429 if (cache_info->debug != MagickFalse)
4430 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4431 cache_info->filename);
4432 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4433 cache_info->methods.get_virtual_pixel_handler=
4434 cache_methods->get_virtual_pixel_handler;
4435 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4436 cache_info->methods.destroy_pixel_handler=
4437 cache_methods->destroy_pixel_handler;
4438 if (cache_methods->get_virtual_metacontent_from_handler !=
4439 (GetVirtualMetacontentFromHandler) NULL)
4440 cache_info->methods.get_virtual_metacontent_from_handler=
4441 cache_methods->get_virtual_metacontent_from_handler;
4442 if (cache_methods->get_authentic_pixels_handler !=
4443 (GetAuthenticPixelsHandler) NULL)
4444 cache_info->methods.get_authentic_pixels_handler=
4445 cache_methods->get_authentic_pixels_handler;
4446 if (cache_methods->queue_authentic_pixels_handler !=
4447 (QueueAuthenticPixelsHandler) NULL)
4448 cache_info->methods.queue_authentic_pixels_handler=
4449 cache_methods->queue_authentic_pixels_handler;
4450 if (cache_methods->sync_authentic_pixels_handler !=
4451 (SyncAuthenticPixelsHandler) NULL)
4452 cache_info->methods.sync_authentic_pixels_handler=
4453 cache_methods->sync_authentic_pixels_handler;
4454 if (cache_methods->get_authentic_pixels_from_handler !=
4455 (GetAuthenticPixelsFromHandler) NULL)
4456 cache_info->methods.get_authentic_pixels_from_handler=
4457 cache_methods->get_authentic_pixels_from_handler;
4458 if (cache_methods->get_authentic_metacontent_from_handler !=
4459 (GetAuthenticMetacontentFromHandler) NULL)
4460 cache_info->methods.get_authentic_metacontent_from_handler=
4461 cache_methods->get_authentic_metacontent_from_handler;
4462 get_one_virtual_pixel_from_handler=
4463 cache_info->methods.get_one_virtual_pixel_from_handler;
4464 if (get_one_virtual_pixel_from_handler !=
4465 (GetOneVirtualPixelFromHandler) NULL)
4466 cache_info->methods.get_one_virtual_pixel_from_handler=
4467 cache_methods->get_one_virtual_pixel_from_handler;
4468 get_one_authentic_pixel_from_handler=
4469 cache_methods->get_one_authentic_pixel_from_handler;
4470 if (get_one_authentic_pixel_from_handler !=
4471 (GetOneAuthenticPixelFromHandler) NULL)
4472 cache_info->methods.get_one_authentic_pixel_from_handler=
4473 cache_methods->get_one_authentic_pixel_from_handler;
4477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4481 + S e t P i x e l C a c h e N e x u s P i x e l s %
4485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4487 % SetPixelCacheNexusPixels() defines the region of the cache for the
4488 % specified cache nexus.
4490 % The format of the SetPixelCacheNexusPixels() method is:
4492 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4493 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4494 % ExceptionInfo *exception)
4496 % A description of each parameter follows:
4498 % o cache_info: the pixel cache.
4500 % o mode: ReadMode, WriteMode, or IOMode.
4502 % o region: A pointer to the RectangleInfo structure that defines the
4503 % region of this particular cache nexus.
4505 % o nexus_info: the cache nexus to set.
4507 % o exception: return any errors or warnings in this structure.
4511 static inline MagickBooleanType AcquireCacheNexusPixels(
4512 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4513 ExceptionInfo *exception)
4515 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4516 return(MagickFalse);
4517 nexus_info->mapped=MagickFalse;
4518 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4519 (size_t) nexus_info->length));
4520 if (nexus_info->cache == (Quantum *) NULL)
4522 nexus_info->mapped=MagickTrue;
4523 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4524 nexus_info->length);
4526 if (nexus_info->cache == (Quantum *) NULL)
4528 (void) ThrowMagickException(exception,GetMagickModule(),
4529 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4530 cache_info->filename);
4531 return(MagickFalse);
4536 static inline MagickBooleanType IsPixelCacheAuthentic(
4537 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4546 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4548 if (cache_info->type == PingCache)
4550 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4551 nexus_info->region.x;
4552 status=nexus_info->pixels == (cache_info->pixels+offset*
4553 cache_info->number_channels) ? MagickTrue : MagickFalse;
4557 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4560 if (mode == ReadMode)
4562 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4565 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4568 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4569 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4570 ExceptionInfo *exception)
4579 assert(cache_info != (const CacheInfo *) NULL);
4580 assert(cache_info->signature == MagickSignature);
4581 if (cache_info->type == UndefinedCache)
4582 return((Quantum *) NULL);
4583 nexus_info->region=(*region);
4584 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4590 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4591 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4592 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4593 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4594 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4595 ((nexus_info->region.width == cache_info->columns) ||
4596 ((nexus_info->region.width % cache_info->columns) == 0)))))
4602 Pixels are accessed directly from memory.
4604 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4605 nexus_info->region.x;
4606 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4608 nexus_info->metacontent=(void *) NULL;
4609 if (cache_info->metacontent_extent != 0)
4610 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4611 offset*cache_info->metacontent_extent;
4612 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4613 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4615 return(nexus_info->pixels);
4619 Pixels are stored in a staging region until they are synced to the cache.
4621 number_pixels=(MagickSizeType) nexus_info->region.width*
4622 nexus_info->region.height;
4623 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4624 if (cache_info->metacontent_extent != 0)
4625 length+=number_pixels*cache_info->metacontent_extent;
4626 if (nexus_info->cache == (Quantum *) NULL)
4628 nexus_info->length=length;
4629 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4630 if (status == MagickFalse)
4632 nexus_info->length=0;
4633 return((Quantum *) NULL);
4637 if (nexus_info->length < length)
4639 RelinquishCacheNexusPixels(nexus_info);
4640 nexus_info->length=length;
4641 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4642 if (status == MagickFalse)
4644 nexus_info->length=0;
4645 return((Quantum *) NULL);
4648 nexus_info->pixels=nexus_info->cache;
4649 nexus_info->metacontent=(void *) NULL;
4650 if (cache_info->metacontent_extent != 0)
4651 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4652 cache_info->number_channels);
4653 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4654 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4656 return(nexus_info->pixels);
4660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4664 % 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 %
4668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4670 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4671 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4672 % access that is outside the boundaries of the image cache.
4674 % The format of the SetPixelCacheVirtualMethod() method is:
4676 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4677 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4679 % A description of each parameter follows:
4681 % o image: the image.
4683 % o virtual_pixel_method: choose the type of virtual pixel.
4685 % o exception: return any errors or warnings in this structure.
4689 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4690 ExceptionInfo *exception)
4693 *restrict cache_info;
4696 *restrict image_view;
4704 assert(image != (Image *) NULL);
4705 assert(image->signature == MagickSignature);
4706 if (image->debug != MagickFalse)
4707 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4708 assert(image->cache != (Cache) NULL);
4709 cache_info=(CacheInfo *) image->cache;
4710 assert(cache_info->signature == MagickSignature);
4711 image->alpha_trait=BlendPixelTrait;
4713 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4714 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4715 #pragma omp parallel for schedule(static,4) shared(status) \
4716 magick_threads(image,image,1,1)
4718 for (y=0; y < (ssize_t) image->rows; y++)
4726 if (status == MagickFalse)
4728 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4729 if (q == (Quantum *) NULL)
4734 for (x=0; x < (ssize_t) image->columns; x++)
4736 SetPixelAlpha(image,alpha,q);
4737 q+=GetPixelChannels(image);
4739 status=SyncCacheViewAuthenticPixels(image_view,exception);
4741 image_view=DestroyCacheView(image_view);
4745 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4746 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4749 *restrict cache_info;
4754 assert(image != (Image *) NULL);
4755 assert(image->signature == MagickSignature);
4756 if (image->debug != MagickFalse)
4757 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4758 assert(image->cache != (Cache) NULL);
4759 cache_info=(CacheInfo *) image->cache;
4760 assert(cache_info->signature == MagickSignature);
4761 method=cache_info->virtual_pixel_method;
4762 cache_info->virtual_pixel_method=virtual_pixel_method;
4763 if ((image->columns != 0) && (image->rows != 0))
4764 switch (virtual_pixel_method)
4766 case BackgroundVirtualPixelMethod:
4768 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4769 (image->alpha_trait == UndefinedPixelTrait))
4770 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4771 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4772 (IsGrayColorspace(image->colorspace) != MagickFalse))
4773 (void) SetImageColorspace(image,sRGBColorspace,exception);
4776 case TransparentVirtualPixelMethod:
4778 if (image->alpha_trait == UndefinedPixelTrait)
4779 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4793 + 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 %
4797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4799 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4800 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4801 % is synced, otherwise MagickFalse.
4803 % The format of the SyncAuthenticPixelCacheNexus() method is:
4805 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4806 % NexusInfo *nexus_info,ExceptionInfo *exception)
4808 % A description of each parameter follows:
4810 % o image: the image.
4812 % o nexus_info: the cache nexus to sync.
4814 % o exception: return any errors or warnings in this structure.
4817 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4818 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4821 *restrict cache_info;
4827 Transfer pixels to the cache.
4829 assert(image != (Image *) NULL);
4830 assert(image->signature == MagickSignature);
4831 if (image->cache == (Cache) NULL)
4832 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4833 cache_info=(CacheInfo *) image->cache;
4834 assert(cache_info->signature == MagickSignature);
4835 if (cache_info->type == UndefinedCache)
4836 return(MagickFalse);
4837 if (nexus_info->authentic_pixel_cache != MagickFalse)
4839 image->taint=MagickTrue;
4842 assert(cache_info->signature == MagickSignature);
4843 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4844 if ((cache_info->metacontent_extent != 0) &&
4845 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4846 return(MagickFalse);
4847 if (status != MagickFalse)
4848 image->taint=MagickTrue;
4853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4857 + S y n c A u t h e n t i c P i x e l C a c h e %
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4863 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4864 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4865 % otherwise MagickFalse.
4867 % The format of the SyncAuthenticPixelsCache() method is:
4869 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4870 % ExceptionInfo *exception)
4872 % A description of each parameter follows:
4874 % o image: the image.
4876 % o exception: return any errors or warnings in this structure.
4879 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4880 ExceptionInfo *exception)
4883 *restrict cache_info;
4886 id = GetOpenMPThreadId();
4891 assert(image != (Image *) NULL);
4892 assert(image->signature == MagickSignature);
4893 assert(image->cache != (Cache) NULL);
4894 cache_info=(CacheInfo *) image->cache;
4895 assert(cache_info->signature == MagickSignature);
4896 assert(id < (int) cache_info->number_threads);
4897 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4907 % S y n c A u t h e n t i c P i x e l s %
4911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4913 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4914 % The method returns MagickTrue if the pixel region is flushed, otherwise
4917 % The format of the SyncAuthenticPixels() method is:
4919 % MagickBooleanType SyncAuthenticPixels(Image *image,
4920 % ExceptionInfo *exception)
4922 % A description of each parameter follows:
4924 % o image: the image.
4926 % o exception: return any errors or warnings in this structure.
4929 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4930 ExceptionInfo *exception)
4933 *restrict cache_info;
4936 id = GetOpenMPThreadId();
4941 assert(image != (Image *) NULL);
4942 assert(image->signature == MagickSignature);
4943 assert(image->cache != (Cache) NULL);
4944 cache_info=(CacheInfo *) image->cache;
4945 assert(cache_info->signature == MagickSignature);
4946 if (cache_info->methods.sync_authentic_pixels_handler !=
4947 (SyncAuthenticPixelsHandler) NULL)
4949 status=cache_info->methods.sync_authentic_pixels_handler(image,
4953 assert(id < (int) cache_info->number_threads);
4954 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4964 + S y n c I m a g e P i x e l C a c h e %
4968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4970 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4971 % The method returns MagickTrue if the pixel region is flushed, otherwise
4974 % The format of the SyncImagePixelCache() method is:
4976 % MagickBooleanType SyncImagePixelCache(Image *image,
4977 % ExceptionInfo *exception)
4979 % A description of each parameter follows:
4981 % o image: the image.
4983 % o exception: return any errors or warnings in this structure.
4986 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4987 ExceptionInfo *exception)
4990 *restrict cache_info;
4992 assert(image != (Image *) NULL);
4993 assert(exception != (ExceptionInfo *) NULL);
4994 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4995 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5003 + 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 %
5007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5010 % of the pixel cache.
5012 % The format of the WritePixelCacheMetacontent() method is:
5014 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5015 % NexusInfo *nexus_info,ExceptionInfo *exception)
5017 % A description of each parameter follows:
5019 % o cache_info: the pixel cache.
5021 % o nexus_info: the cache nexus to write the meta-content.
5023 % o exception: return any errors or warnings in this structure.
5026 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5027 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5037 register const unsigned char
5046 if (cache_info->metacontent_extent == 0)
5047 return(MagickFalse);
5048 if (nexus_info->authentic_pixel_cache != MagickFalse)
5050 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5051 nexus_info->region.x;
5052 length=(MagickSizeType) nexus_info->region.width*
5053 cache_info->metacontent_extent;
5054 extent=(MagickSizeType) length*nexus_info->region.height;
5055 rows=nexus_info->region.height;
5057 p=(unsigned char *) nexus_info->metacontent;
5058 switch (cache_info->type)
5063 register unsigned char
5067 Write associated pixels to memory.
5069 if ((cache_info->columns == nexus_info->region.width) &&
5070 (extent == (MagickSizeType) ((size_t) extent)))
5075 q=(unsigned char *) cache_info->metacontent+offset*
5076 cache_info->metacontent_extent;
5077 for (y=0; y < (ssize_t) rows; y++)
5079 (void) memcpy(q,p,(size_t) length);
5080 p+=nexus_info->region.width*cache_info->metacontent_extent;
5081 q+=cache_info->columns*cache_info->metacontent_extent;
5088 Write associated pixels to disk.
5090 LockSemaphoreInfo(cache_info->file_semaphore);
5091 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5093 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5094 cache_info->cache_filename);
5095 UnlockSemaphoreInfo(cache_info->file_semaphore);
5096 return(MagickFalse);
5098 if ((cache_info->columns == nexus_info->region.width) &&
5099 (extent <= MagickMaxBufferExtent))
5104 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5105 for (y=0; y < (ssize_t) rows; y++)
5107 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5108 cache_info->number_channels*sizeof(Quantum)+offset*
5109 cache_info->metacontent_extent,length,(const unsigned char *) p);
5110 if (count != (MagickOffsetType) length)
5112 p+=cache_info->metacontent_extent*nexus_info->region.width;
5113 offset+=cache_info->columns;
5115 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5116 (void) ClosePixelCacheOnDisk(cache_info);
5117 UnlockSemaphoreInfo(cache_info->file_semaphore);
5120 case DistributedCache:
5126 Write metacontent to distributed cache.
5128 LockSemaphoreInfo(cache_info->file_semaphore);
5129 region=nexus_info->region;
5130 if ((cache_info->columns != nexus_info->region.width) ||
5131 (extent > MagickMaxBufferExtent))
5138 for (y=0; y < (ssize_t) rows; y++)
5140 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5141 cache_info->server_info,®ion,length,(const unsigned char *) p);
5142 if (count != (MagickOffsetType) length)
5144 p+=cache_info->metacontent_extent*nexus_info->region.width;
5147 UnlockSemaphoreInfo(cache_info->file_semaphore);
5153 if (y < (ssize_t) rows)
5155 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5156 cache_info->cache_filename);
5157 return(MagickFalse);
5159 if ((cache_info->debug != MagickFalse) &&
5160 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5161 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5162 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5163 nexus_info->region.width,(double) nexus_info->region.height,(double)
5164 nexus_info->region.x,(double) nexus_info->region.y);
5169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173 + W r i t e C a c h e P i x e l s %
5177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179 % WritePixelCachePixels() writes image pixels to the specified region of the
5182 % The format of the WritePixelCachePixels() method is:
5184 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5185 % NexusInfo *nexus_info,ExceptionInfo *exception)
5187 % A description of each parameter follows:
5189 % o cache_info: the pixel cache.
5191 % o nexus_info: the cache nexus to write the pixels.
5193 % o exception: return any errors or warnings in this structure.
5196 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5197 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5207 register const Quantum
5216 if (nexus_info->authentic_pixel_cache != MagickFalse)
5218 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5219 nexus_info->region.x;
5220 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5222 extent=length*nexus_info->region.height;
5223 rows=nexus_info->region.height;
5225 p=nexus_info->pixels;
5226 switch (cache_info->type)
5235 Write pixels to memory.
5237 if ((cache_info->columns == nexus_info->region.width) &&
5238 (extent == (MagickSizeType) ((size_t) extent)))
5243 q=cache_info->pixels+offset*cache_info->number_channels;
5244 for (y=0; y < (ssize_t) rows; y++)
5246 (void) memcpy(q,p,(size_t) length);
5247 p+=cache_info->number_channels*nexus_info->region.width;
5248 q+=cache_info->columns*cache_info->number_channels;
5255 Write pixels to disk.
5257 LockSemaphoreInfo(cache_info->file_semaphore);
5258 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5260 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5261 cache_info->cache_filename);
5262 UnlockSemaphoreInfo(cache_info->file_semaphore);
5263 return(MagickFalse);
5265 if ((cache_info->columns == nexus_info->region.width) &&
5266 (extent <= MagickMaxBufferExtent))
5271 for (y=0; y < (ssize_t) rows; y++)
5273 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5274 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5276 if (count != (MagickOffsetType) length)
5278 p+=cache_info->number_channels*nexus_info->region.width;
5279 offset+=cache_info->columns;
5281 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5282 (void) ClosePixelCacheOnDisk(cache_info);
5283 UnlockSemaphoreInfo(cache_info->file_semaphore);
5286 case DistributedCache:
5292 Write pixels to distributed cache.
5294 LockSemaphoreInfo(cache_info->file_semaphore);
5295 region=nexus_info->region;
5296 if ((cache_info->columns != nexus_info->region.width) ||
5297 (extent > MagickMaxBufferExtent))
5304 for (y=0; y < (ssize_t) rows; y++)
5306 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5307 cache_info->server_info,®ion,length,(const unsigned char *) p);
5308 if (count != (MagickOffsetType) length)
5310 p+=cache_info->number_channels*nexus_info->region.width;
5313 UnlockSemaphoreInfo(cache_info->file_semaphore);
5319 if (y < (ssize_t) rows)
5321 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5322 cache_info->cache_filename);
5323 return(MagickFalse);
5325 if ((cache_info->debug != MagickFalse) &&
5326 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5327 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5328 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5329 nexus_info->region.width,(double) nexus_info->region.height,(double)
5330 nexus_info->region.x,(double) nexus_info->region.y);