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 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
123 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
124 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
125 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
129 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
130 const size_t,ExceptionInfo *),
131 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
132 const size_t,ExceptionInfo *),
133 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
134 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
136 #if defined(__cplusplus) || defined(c_plusplus)
143 static volatile MagickBooleanType
144 instantiate_cache = MagickFalse;
147 *cache_semaphore = (SemaphoreInfo *) NULL;
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 + A c q u i r e P i x e l C a c h e %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % AcquirePixelCache() acquires a pixel cache.
162 % The format of the AcquirePixelCache() method is:
164 % Cache AcquirePixelCache(const size_t number_threads)
166 % A description of each parameter follows:
168 % o number_threads: the number of nexus threads.
171 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
174 *restrict cache_info;
179 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
180 if (cache_info == (CacheInfo *) NULL)
181 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
182 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
183 cache_info->type=UndefinedCache;
184 cache_info->mode=IOMode;
185 cache_info->colorspace=sRGBColorspace;
186 cache_info->file=(-1);
187 cache_info->id=GetMagickThreadId();
188 cache_info->number_threads=number_threads;
189 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
190 cache_info->number_threads=GetOpenMPMaximumThreads();
191 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
192 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
193 if (cache_info->number_threads == 0)
194 cache_info->number_threads=1;
195 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
196 if (cache_info->nexus_info == (NexusInfo **) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
199 if (synchronize != (const char *) NULL)
201 cache_info->synchronize=IsStringTrue(synchronize);
202 synchronize=DestroyString(synchronize);
204 cache_info->semaphore=AcquireSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->file_semaphore=AcquireSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 return((Cache ) cache_info);
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % A c q u i r e P i x e l C a c h e N e x u s %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
225 % The format of the AcquirePixelCacheNexus method is:
227 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
229 % A description of each parameter follows:
231 % o number_threads: the number of nexus threads.
234 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
237 **restrict nexus_info;
242 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
243 number_threads,sizeof(*nexus_info)));
244 if (nexus_info == (NexusInfo **) NULL)
245 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
246 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
247 sizeof(**nexus_info));
248 if (nexus_info[0] == (NexusInfo *) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
251 for (i=0; i < (ssize_t) number_threads; i++)
253 nexus_info[i]=(&nexus_info[0][i]);
254 nexus_info[i]->signature=MagickSignature;
260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264 + A c q u i r e P i x e l C a c h e P i x e l s %
268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 % AcquirePixelCachePixels() returns the pixels associated with the specified
273 % The format of the AcquirePixelCachePixels() method is:
275 % const void *AcquirePixelCachePixels(const Image *image,
276 % MagickSizeType *length,ExceptionInfo *exception)
278 % A description of each parameter follows:
280 % o image: the image.
282 % o length: the pixel cache length.
284 % o exception: return any errors or warnings in this structure.
287 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
288 MagickSizeType *length,ExceptionInfo *exception)
291 *restrict cache_info;
293 assert(image != (const Image *) NULL);
294 assert(image->signature == MagickSignature);
295 assert(exception != (ExceptionInfo *) NULL);
296 assert(exception->signature == MagickSignature);
297 assert(image->cache != (Cache) NULL);
298 cache_info=(CacheInfo *) image->cache;
299 assert(cache_info->signature == MagickSignature);
301 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
302 return((const void *) NULL);
303 *length=cache_info->length;
304 return((const void *) cache_info->pixels);
308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 + C a c h e C o m p o n e n t G e n e s i s %
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 % CacheComponentGenesis() instantiates the cache component.
320 % The format of the CacheComponentGenesis method is:
322 % MagickBooleanType CacheComponentGenesis(void)
325 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
327 if (cache_semaphore == (SemaphoreInfo *) NULL)
328 cache_semaphore=AcquireSemaphoreInfo();
333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337 + C a c h e C o m p o n e n t T e r m i n u s %
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 % CacheComponentTerminus() destroys the cache component.
345 % The format of the CacheComponentTerminus() method is:
347 % CacheComponentTerminus(void)
350 MagickPrivate void CacheComponentTerminus(void)
352 if (cache_semaphore == (SemaphoreInfo *) NULL)
353 ActivateSemaphoreInfo(&cache_semaphore);
354 LockSemaphoreInfo(cache_semaphore);
355 instantiate_cache=MagickFalse;
356 UnlockSemaphoreInfo(cache_semaphore);
357 RelinquishSemaphoreInfo(&cache_semaphore);
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 + C l o n e P i x e l C a c h e %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371 % ClonePixelCache() clones a pixel cache.
373 % The format of the ClonePixelCache() method is:
375 % Cache ClonePixelCache(const Cache cache)
377 % A description of each parameter follows:
379 % o cache: the pixel cache.
382 MagickPrivate Cache ClonePixelCache(const Cache cache)
385 *restrict clone_info;
388 *restrict cache_info;
390 assert(cache != NULL);
391 cache_info=(const CacheInfo *) cache;
392 assert(cache_info->signature == MagickSignature);
393 if (cache_info->debug != MagickFalse)
394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
395 cache_info->filename);
396 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
397 if (clone_info == (Cache) NULL)
398 return((Cache) NULL);
399 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
400 return((Cache ) clone_info);
404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408 + C l o n e P i x e l C a c h e M e t h o d s %
412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
417 % The format of the ClonePixelCacheMethods() method is:
419 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
421 % A description of each parameter follows:
423 % o clone: Specifies a pointer to a Cache structure.
425 % o cache: the pixel cache.
428 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
431 *restrict cache_info,
432 *restrict source_info;
434 assert(clone != (Cache) NULL);
435 source_info=(CacheInfo *) clone;
436 assert(source_info->signature == MagickSignature);
437 if (source_info->debug != MagickFalse)
438 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
439 source_info->filename);
440 assert(cache != (Cache) NULL);
441 cache_info=(CacheInfo *) cache;
442 assert(cache_info->signature == MagickSignature);
443 source_info->methods=cache_info->methods;
447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451 + 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 %
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
456 % ClonePixelCacheRepository() clones the source pixel cache to the destination
459 % The format of the ClonePixelCacheRepository() method is:
461 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
462 % CacheInfo *source_info,ExceptionInfo *exception)
464 % A description of each parameter follows:
466 % o cache_info: the pixel cache.
468 % o source_info: the source pixel cache.
470 % o exception: return any errors or warnings in this structure.
474 static MagickBooleanType ClonePixelCacheRepository(
475 CacheInfo *restrict clone_info,CacheInfo *restrict cache_info,
476 ExceptionInfo *exception)
478 #define MaxCacheThreads 2
479 #define cache_threads(source,destination,chunk) \
480 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
481 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
482 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
489 **restrict cache_nexus,
490 **restrict clone_nexus;
498 assert(cache_info != (CacheInfo *) NULL);
499 assert(clone_info != (CacheInfo *) NULL);
500 assert(exception != (ExceptionInfo *) NULL);
501 if (cache_info->type == PingCache)
503 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
504 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
505 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
506 (cache_info->columns == clone_info->columns) &&
507 (cache_info->rows == clone_info->rows) &&
508 (cache_info->number_channels == clone_info->number_channels) &&
509 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
510 (cache_info->metacontent_extent == clone_info->metacontent_extent))
512 (void) memcpy(clone_info->pixels,cache_info->pixels,cache_info->columns*
513 cache_info->number_channels*cache_info->rows*
514 sizeof(*cache_info->pixels));
515 if ((cache_info->metacontent_extent != 0) &&
516 (clone_info->metacontent_extent != 0))
517 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
518 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
519 sizeof(unsigned char));
523 Mismatched pixel cache morphology.
525 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
526 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
527 if ((cache_nexus == (NexusInfo **) NULL) ||
528 (clone_nexus == (NexusInfo **) NULL))
529 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
530 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
531 optimize=(cache_info->number_channels == clone_info->number_channels) &&
532 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
533 MagickTrue : MagickFalse;
534 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
535 clone_info->columns*clone_info->number_channels);
537 #if defined(MAGICKCORE_OPENMP_SUPPORT)
538 #pragma omp parallel for schedule(static,4) shared(status) \
539 cache_threads(cache_info,clone_info,cache_info->rows)
541 for (y=0; y < (ssize_t) cache_info->rows; y++)
544 id = GetOpenMPThreadId();
555 if (status == MagickFalse)
557 if (y >= (ssize_t) clone_info->rows)
559 region.width=cache_info->columns;
563 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
565 if (pixels == (Quantum *) NULL)
567 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
568 if (status == MagickFalse)
570 region.width=clone_info->columns;
571 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
572 clone_nexus[id],exception);
573 if (pixels == (Quantum *) NULL)
575 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
576 clone_nexus[id]->length);
577 if (optimize != MagickFalse)
578 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
582 register const Quantum
589 Mismatched pixel channel map.
591 p=cache_nexus[id]->pixels;
592 q=clone_nexus[id]->pixels;
593 for (x=0; x < (ssize_t) cache_info->columns; x++)
598 if (x == (ssize_t) clone_info->columns)
600 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
608 channel=clone_info->channel_map[i].channel;
609 traits=cache_info->channel_map[channel].traits;
610 if (traits != UndefinedPixelTrait)
611 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
615 p+=cache_info->number_channels;
618 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
620 if ((cache_info->metacontent_extent != 0) &&
621 (clone_info->metacontent_extent != 0))
626 length=(size_t) MagickMin(cache_info->metacontent_extent,
627 clone_info->metacontent_extent);
628 #if defined(MAGICKCORE_OPENMP_SUPPORT)
629 #pragma omp parallel for schedule(static,4) shared(status) \
630 cache_threads(cache_info,clone_info,cache_info->rows)
632 for (y=0; y < (ssize_t) cache_info->rows; y++)
635 id = GetOpenMPThreadId();
643 if (status == MagickFalse)
645 if (y >= (ssize_t) clone_info->rows)
647 region.width=cache_info->columns;
651 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
652 cache_nexus[id],exception);
653 if (pixels == (Quantum *) NULL)
655 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
656 if (status == MagickFalse)
658 region.width=clone_info->columns;
659 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
660 clone_nexus[id],exception);
661 if (pixels == (Quantum *) NULL)
663 if ((clone_nexus[id]->metacontent != (void *) NULL) &&
664 (cache_nexus[id]->metacontent != (void *) NULL))
665 (void) memcpy(clone_nexus[id]->metacontent,
666 cache_nexus[id]->metacontent,length*sizeof(unsigned char));
667 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
670 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
671 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
672 if (cache_info->debug != MagickFalse)
675 message[MaxTextExtent];
677 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
678 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
679 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
680 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
690 + D e s t r o y I m a g e P i x e l C a c h e %
694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
698 % The format of the DestroyImagePixelCache() method is:
700 % void DestroyImagePixelCache(Image *image)
702 % A description of each parameter follows:
704 % o image: the image.
707 static void DestroyImagePixelCache(Image *image)
709 assert(image != (Image *) NULL);
710 assert(image->signature == MagickSignature);
711 if (image->debug != MagickFalse)
712 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
713 if (image->cache == (void *) NULL)
715 image->cache=DestroyPixelCache(image->cache);
719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 + D e s t r o y I m a g e P i x e l s %
727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729 % DestroyImagePixels() deallocates memory associated with the pixel cache.
731 % The format of the DestroyImagePixels() method is:
733 % void DestroyImagePixels(Image *image)
735 % A description of each parameter follows:
737 % o image: the image.
740 MagickExport void DestroyImagePixels(Image *image)
743 *restrict cache_info;
745 assert(image != (const Image *) NULL);
746 assert(image->signature == MagickSignature);
747 if (image->debug != MagickFalse)
748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
749 assert(image->cache != (Cache) NULL);
750 cache_info=(CacheInfo *) image->cache;
751 assert(cache_info->signature == MagickSignature);
752 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
754 cache_info->methods.destroy_pixel_handler(image);
757 image->cache=DestroyPixelCache(image->cache);
761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765 + D e s t r o y P i x e l C a c h e %
769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771 % DestroyPixelCache() deallocates memory associated with the pixel cache.
773 % The format of the DestroyPixelCache() method is:
775 % Cache DestroyPixelCache(Cache cache)
777 % A description of each parameter follows:
779 % o cache: the pixel cache.
783 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
789 if (cache_info->file != -1)
791 status=close(cache_info->file);
792 cache_info->file=(-1);
793 RelinquishMagickResource(FileResource,1);
795 return(status == -1 ? MagickFalse : MagickTrue);
798 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
800 switch (cache_info->type)
804 if (cache_info->mapped == MagickFalse)
805 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
809 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
810 cache_info->pixels=(Quantum *) NULL;
812 RelinquishMagickResource(MemoryResource,cache_info->length);
817 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
818 cache_info->pixels=(Quantum *) NULL;
819 if (cache_info->mode != ReadMode)
820 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
821 *cache_info->cache_filename='\0';
822 RelinquishMagickResource(MapResource,cache_info->length);
826 if (cache_info->file != -1)
827 (void) ClosePixelCacheOnDisk(cache_info);
828 if (cache_info->mode != ReadMode)
829 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
830 *cache_info->cache_filename='\0';
831 RelinquishMagickResource(DiskResource,cache_info->length);
834 case DistributedCache:
836 *cache_info->cache_filename='\0';
837 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
838 cache_info->server_info);
844 cache_info->type=UndefinedCache;
845 cache_info->mapped=MagickFalse;
846 cache_info->metacontent=(void *) NULL;
849 MagickPrivate Cache DestroyPixelCache(Cache cache)
852 *restrict cache_info;
854 assert(cache != (Cache) NULL);
855 cache_info=(CacheInfo *) cache;
856 assert(cache_info->signature == MagickSignature);
857 if (cache_info->debug != MagickFalse)
858 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
859 cache_info->filename);
860 LockSemaphoreInfo(cache_info->semaphore);
861 cache_info->reference_count--;
862 if (cache_info->reference_count != 0)
864 UnlockSemaphoreInfo(cache_info->semaphore);
865 return((Cache) NULL);
867 UnlockSemaphoreInfo(cache_info->semaphore);
868 if (cache_info->debug != MagickFalse)
871 message[MaxTextExtent];
873 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
874 cache_info->filename);
875 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
877 RelinquishPixelCachePixels(cache_info);
878 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
879 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
880 cache_info->server_info);
881 if (cache_info->nexus_info != (NexusInfo **) NULL)
882 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
883 cache_info->number_threads);
884 if (cache_info->random_info != (RandomInfo *) NULL)
885 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
886 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
887 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
888 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
889 RelinquishSemaphoreInfo(&cache_info->semaphore);
890 cache_info->signature=(~MagickSignature);
891 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901 + D e s t r o y P i x e l C a c h e N e x u s %
905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
909 % The format of the DestroyPixelCacheNexus() method is:
911 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
912 % const size_t number_threads)
914 % A description of each parameter follows:
916 % o nexus_info: the nexus to destroy.
918 % o number_threads: the number of nexus threads.
922 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
924 if (nexus_info->mapped == MagickFalse)
925 (void) RelinquishAlignedMemory(nexus_info->cache);
927 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
928 nexus_info->cache=(Quantum *) NULL;
929 nexus_info->pixels=(Quantum *) NULL;
930 nexus_info->metacontent=(void *) NULL;
931 nexus_info->length=0;
932 nexus_info->mapped=MagickFalse;
935 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
936 const size_t number_threads)
941 assert(nexus_info != (NexusInfo **) NULL);
942 for (i=0; i < (ssize_t) number_threads; i++)
944 if (nexus_info[i]->cache != (Quantum *) NULL)
945 RelinquishCacheNexusPixels(nexus_info[i]);
946 nexus_info[i]->signature=(~MagickSignature);
948 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
949 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958 % G e t A u t h e n t i c M e t a c o n t e n t %
962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
964 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
965 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
966 % returned if the associated pixels are not available.
968 % The format of the GetAuthenticMetacontent() method is:
970 % void *GetAuthenticMetacontent(const Image *image)
972 % A description of each parameter follows:
974 % o image: the image.
977 MagickExport void *GetAuthenticMetacontent(const Image *image)
980 *restrict cache_info;
983 id = GetOpenMPThreadId();
985 assert(image != (const Image *) NULL);
986 assert(image->signature == MagickSignature);
987 assert(image->cache != (Cache) NULL);
988 cache_info=(CacheInfo *) image->cache;
989 assert(cache_info->signature == MagickSignature);
990 if (cache_info->methods.get_authentic_metacontent_from_handler !=
991 (GetAuthenticMetacontentFromHandler) NULL)
996 metacontent=cache_info->methods.
997 get_authentic_metacontent_from_handler(image);
1000 assert(id < (int) cache_info->number_threads);
1001 return(cache_info->nexus_info[id]->metacontent);
1005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009 + 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 %
1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1016 % with the last call to QueueAuthenticPixelsCache() or
1017 % GetAuthenticPixelsCache().
1019 % The format of the GetAuthenticMetacontentFromCache() method is:
1021 % void *GetAuthenticMetacontentFromCache(const Image *image)
1023 % A description of each parameter follows:
1025 % o image: the image.
1028 static void *GetAuthenticMetacontentFromCache(const Image *image)
1031 *restrict cache_info;
1034 id = GetOpenMPThreadId();
1036 assert(image != (const Image *) NULL);
1037 assert(image->signature == MagickSignature);
1038 assert(image->cache != (Cache) NULL);
1039 cache_info=(CacheInfo *) image->cache;
1040 assert(cache_info->signature == MagickSignature);
1041 assert(id < (int) cache_info->number_threads);
1042 return(cache_info->nexus_info[id]->metacontent);
1046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050 + 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 %
1054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1056 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1057 % disk pixel cache as defined by the geometry parameters. A pointer to the
1058 % pixels is returned if the pixels are transferred, otherwise a NULL is
1061 % The format of the GetAuthenticPixelCacheNexus() method is:
1063 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1064 % const ssize_t y,const size_t columns,const size_t rows,
1065 % NexusInfo *nexus_info,ExceptionInfo *exception)
1067 % A description of each parameter follows:
1069 % o image: the image.
1071 % o x,y,columns,rows: These values define the perimeter of a region of
1074 % o nexus_info: the cache nexus to return.
1076 % o exception: return any errors or warnings in this structure.
1080 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1081 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1082 ExceptionInfo *exception)
1085 *restrict cache_info;
1091 Transfer pixels from the cache.
1093 assert(image != (Image *) NULL);
1094 assert(image->signature == MagickSignature);
1095 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1096 nexus_info,exception);
1097 if (pixels == (Quantum *) NULL)
1098 return((Quantum *) NULL);
1099 cache_info=(CacheInfo *) image->cache;
1100 assert(cache_info->signature == MagickSignature);
1101 if (nexus_info->authentic_pixel_cache != MagickFalse)
1103 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1104 return((Quantum *) NULL);
1105 if (cache_info->metacontent_extent != 0)
1106 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1107 return((Quantum *) NULL);
1112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 + 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 %
1120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1123 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1125 % The format of the GetAuthenticPixelsFromCache() method is:
1127 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1129 % A description of each parameter follows:
1131 % o image: the image.
1134 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1137 *restrict cache_info;
1140 id = GetOpenMPThreadId();
1142 assert(image != (const Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 assert(image->cache != (Cache) NULL);
1145 cache_info=(CacheInfo *) image->cache;
1146 assert(cache_info->signature == MagickSignature);
1147 assert(id < (int) cache_info->number_threads);
1148 return(cache_info->nexus_info[id]->pixels);
1152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156 % G e t A u t h e n t i c P i x e l Q u e u e %
1160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162 % GetAuthenticPixelQueue() returns the authentic pixels associated
1163 % corresponding with the last call to QueueAuthenticPixels() or
1164 % GetAuthenticPixels().
1166 % The format of the GetAuthenticPixelQueue() method is:
1168 % Quantum *GetAuthenticPixelQueue(const Image image)
1170 % A description of each parameter follows:
1172 % o image: the image.
1175 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1178 *restrict cache_info;
1181 id = GetOpenMPThreadId();
1183 assert(image != (const Image *) NULL);
1184 assert(image->signature == MagickSignature);
1185 assert(image->cache != (Cache) NULL);
1186 cache_info=(CacheInfo *) image->cache;
1187 assert(cache_info->signature == MagickSignature);
1188 if (cache_info->methods.get_authentic_pixels_from_handler !=
1189 (GetAuthenticPixelsFromHandler) NULL)
1190 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1191 assert(id < (int) cache_info->number_threads);
1192 return(cache_info->nexus_info[id]->pixels);
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200 % G e t A u t h e n t i c P i x e l s %
1203 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1206 % region is successfully accessed, a pointer to a Quantum array
1207 % representing the region is returned, otherwise NULL is returned.
1209 % The returned pointer may point to a temporary working copy of the pixels
1210 % or it may point to the original pixels in memory. Performance is maximized
1211 % if the selected region is part of one row, or one or more full rows, since
1212 % then there is opportunity to access the pixels in-place (without a copy)
1213 % if the image is in memory, or in a memory-mapped file. The returned pointer
1214 % must *never* be deallocated by the user.
1216 % Pixels accessed via the returned pointer represent a simple array of type
1217 % Quantum. If the image has corresponding metacontent,call
1218 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1219 % meta-content corresponding to the region. Once the Quantum array has
1220 % been updated, the changes must be saved back to the underlying image using
1221 % SyncAuthenticPixels() or they may be lost.
1223 % The format of the GetAuthenticPixels() method is:
1225 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1226 % const ssize_t y,const size_t columns,const size_t rows,
1227 % ExceptionInfo *exception)
1229 % A description of each parameter follows:
1231 % o image: the image.
1233 % o x,y,columns,rows: These values define the perimeter of a region of
1236 % o exception: return any errors or warnings in this structure.
1239 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1240 const ssize_t y,const size_t columns,const size_t rows,
1241 ExceptionInfo *exception)
1244 *restrict cache_info;
1247 id = GetOpenMPThreadId();
1252 assert(image != (Image *) NULL);
1253 assert(image->signature == MagickSignature);
1254 assert(image->cache != (Cache) NULL);
1255 cache_info=(CacheInfo *) image->cache;
1256 assert(cache_info->signature == MagickSignature);
1257 if (cache_info->methods.get_authentic_pixels_handler !=
1258 (GetAuthenticPixelsHandler) NULL)
1260 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1264 assert(id < (int) cache_info->number_threads);
1265 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1266 cache_info->nexus_info[id],exception);
1271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1275 + G e t A u t h e n t i c P i x e l s C a c h e %
1279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1281 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1282 % as defined by the geometry parameters. A pointer to the pixels is returned
1283 % if the pixels are transferred, otherwise a NULL is returned.
1285 % The format of the GetAuthenticPixelsCache() method is:
1287 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1288 % const ssize_t y,const size_t columns,const size_t rows,
1289 % ExceptionInfo *exception)
1291 % A description of each parameter follows:
1293 % o image: the image.
1295 % o x,y,columns,rows: These values define the perimeter of a region of
1298 % o exception: return any errors or warnings in this structure.
1301 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1302 const ssize_t y,const size_t columns,const size_t rows,
1303 ExceptionInfo *exception)
1306 *restrict cache_info;
1309 id = GetOpenMPThreadId();
1314 assert(image != (const Image *) NULL);
1315 assert(image->signature == MagickSignature);
1316 assert(image->cache != (Cache) NULL);
1317 cache_info=(CacheInfo *) image->cache;
1318 if (cache_info == (Cache) NULL)
1319 return((Quantum *) NULL);
1320 assert(cache_info->signature == MagickSignature);
1321 assert(id < (int) cache_info->number_threads);
1322 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1323 cache_info->nexus_info[id],exception);
1328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332 + G e t I m a g e E x t e n t %
1336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1338 % GetImageExtent() returns the extent of the pixels associated corresponding
1339 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1341 % The format of the GetImageExtent() method is:
1343 % MagickSizeType GetImageExtent(const Image *image)
1345 % A description of each parameter follows:
1347 % o image: the image.
1350 MagickExport MagickSizeType GetImageExtent(const Image *image)
1353 *restrict cache_info;
1356 id = GetOpenMPThreadId();
1358 assert(image != (Image *) NULL);
1359 assert(image->signature == MagickSignature);
1360 if (image->debug != MagickFalse)
1361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1362 assert(image->cache != (Cache) NULL);
1363 cache_info=(CacheInfo *) image->cache;
1364 assert(cache_info->signature == MagickSignature);
1365 assert(id < (int) cache_info->number_threads);
1366 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1374 + G e t I m a g e P i x e l C a c h e %
1378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380 % GetImagePixelCache() ensures that there is only a single reference to the
1381 % pixel cache to be modified, updating the provided cache pointer to point to
1382 % a clone of the original pixel cache if necessary.
1384 % The format of the GetImagePixelCache method is:
1386 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1387 % ExceptionInfo *exception)
1389 % A description of each parameter follows:
1391 % o image: the image.
1393 % o clone: any value other than MagickFalse clones the cache pixels.
1395 % o exception: return any errors or warnings in this structure.
1399 static inline MagickBooleanType ValidatePixelCacheMorphology(
1400 const Image *restrict image)
1403 *restrict cache_info;
1405 const PixelChannelMap
1410 Does the image match the pixel cache morphology?
1412 cache_info=(CacheInfo *) image->cache;
1413 p=image->channel_map;
1414 q=cache_info->channel_map;
1415 if ((image->storage_class != cache_info->storage_class) ||
1416 (image->colorspace != cache_info->colorspace) ||
1417 (image->alpha_trait != cache_info->alpha_trait) ||
1418 (image->read_mask != cache_info->read_mask) ||
1419 (image->write_mask != cache_info->write_mask) ||
1420 (image->columns != cache_info->columns) ||
1421 (image->rows != cache_info->rows) ||
1422 (image->number_channels != cache_info->number_channels) ||
1423 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1424 (image->metacontent_extent != cache_info->metacontent_extent) ||
1425 (cache_info->nexus_info == (NexusInfo **) NULL))
1426 return(MagickFalse);
1430 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1431 ExceptionInfo *exception)
1434 *restrict cache_info;
1440 static MagickSizeType
1441 cpu_throttle = MagickResourceInfinity,
1446 cache_timestamp = 0;
1449 if (cpu_throttle == MagickResourceInfinity)
1450 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1451 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1452 MagickDelay(cpu_throttle);
1453 if (time_limit == 0)
1456 Set the expire time in seconds.
1458 time_limit=GetMagickResourceLimit(TimeResource);
1459 cache_timestamp=time((time_t *) NULL);
1461 if ((time_limit != MagickResourceInfinity) &&
1462 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1464 #if defined(ECANCELED)
1467 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1469 LockSemaphoreInfo(image->semaphore);
1470 assert(image->cache != (Cache) NULL);
1471 cache_info=(CacheInfo *) image->cache;
1472 destroy=MagickFalse;
1473 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1475 LockSemaphoreInfo(cache_info->semaphore);
1476 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1487 clone_image=(*image);
1488 clone_image.semaphore=AcquireSemaphoreInfo();
1489 clone_image.reference_count=1;
1490 clone_image.cache=ClonePixelCache(cache_info);
1491 clone_info=(CacheInfo *) clone_image.cache;
1492 status=OpenPixelCache(&clone_image,IOMode,exception);
1493 if (status != MagickFalse)
1495 if (clone != MagickFalse)
1496 status=ClonePixelCacheRepository(clone_info,cache_info,
1498 if (status != MagickFalse)
1500 if (cache_info->reference_count == 1)
1501 cache_info->nexus_info=(NexusInfo **) NULL;
1503 image->cache=clone_image.cache;
1506 RelinquishSemaphoreInfo(&clone_image.semaphore);
1508 UnlockSemaphoreInfo(cache_info->semaphore);
1510 if (destroy != MagickFalse)
1511 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1512 if (status != MagickFalse)
1515 Ensure the image matches the pixel cache morphology.
1517 image->type=UndefinedType;
1518 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1520 status=OpenPixelCache(image,IOMode,exception);
1521 cache_info=(CacheInfo *) image->cache;
1522 if (cache_info->type == DiskCache)
1523 (void) ClosePixelCacheOnDisk(cache_info);
1526 UnlockSemaphoreInfo(image->semaphore);
1527 if (status == MagickFalse)
1528 return((Cache) NULL);
1529 return(image->cache);
1533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1537 + G e t I m a g e P i x e l C a c h e T y p e %
1541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1544 % DiskCache, MemoryCache, MapCache, or PingCache.
1546 % The format of the GetImagePixelCacheType() method is:
1548 % CacheType GetImagePixelCacheType(const Image *image)
1550 % A description of each parameter follows:
1552 % o image: the image.
1555 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1558 *restrict cache_info;
1560 assert(image != (Image *) NULL);
1561 assert(image->signature == MagickSignature);
1562 assert(image->cache != (Cache) NULL);
1563 cache_info=(CacheInfo *) image->cache;
1564 assert(cache_info->signature == MagickSignature);
1565 return(cache_info->type);
1569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573 % G e t O n e A u t h e n t i c P i x e l %
1577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1580 % location. The image background color is returned if an error occurs.
1582 % The format of the GetOneAuthenticPixel() method is:
1584 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1585 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1587 % A description of each parameter follows:
1589 % o image: the image.
1591 % o x,y: These values define the location of the pixel to return.
1593 % o pixel: return a pixel at the specified (x,y) location.
1595 % o exception: return any errors or warnings in this structure.
1599 static inline MagickBooleanType CopyPixel(const Image *image,const Quantum *source,
1600 Quantum *destination)
1605 if (source == (const Quantum *) NULL)
1607 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1608 destination[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1609 destination[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1610 destination[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1611 destination[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1612 return(MagickFalse);
1614 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1616 PixelChannel channel=GetPixelChannelChannel(image,i);
1617 destination[channel]=source[i];
1622 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1623 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1626 *restrict cache_info;
1631 assert(image != (Image *) NULL);
1632 assert(image->signature == MagickSignature);
1633 assert(image->cache != (Cache) NULL);
1634 cache_info=(CacheInfo *) image->cache;
1635 assert(cache_info->signature == MagickSignature);
1636 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1637 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1638 (GetOneAuthenticPixelFromHandler) NULL)
1639 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1641 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1642 return(CopyPixel(image,q,pixel));
1646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1650 + 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 %
1654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1656 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1657 % location. The image background color is returned if an error occurs.
1659 % The format of the GetOneAuthenticPixelFromCache() method is:
1661 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1662 % const ssize_t x,const ssize_t y,Quantum *pixel,
1663 % ExceptionInfo *exception)
1665 % A description of each parameter follows:
1667 % o image: the image.
1669 % o x,y: These values define the location of the pixel to return.
1671 % o pixel: return a pixel at the specified (x,y) location.
1673 % o exception: return any errors or warnings in this structure.
1676 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1677 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1680 *restrict cache_info;
1683 id = GetOpenMPThreadId();
1688 assert(image != (const Image *) NULL);
1689 assert(image->signature == MagickSignature);
1690 assert(image->cache != (Cache) NULL);
1691 cache_info=(CacheInfo *) image->cache;
1692 assert(cache_info->signature == MagickSignature);
1693 assert(id < (int) cache_info->number_threads);
1694 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1695 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1697 return(CopyPixel(image,q,pixel));
1701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1705 % G e t O n e V i r t u a l P i x e l %
1709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1711 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1712 % (x,y) location. The image background color is returned if an error occurs.
1713 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1715 % The format of the GetOneVirtualPixel() method is:
1717 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1718 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1720 % A description of each parameter follows:
1722 % o image: the image.
1724 % o x,y: These values define the location of the pixel to return.
1726 % o pixel: return a pixel at the specified (x,y) location.
1728 % o exception: return any errors or warnings in this structure.
1731 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1732 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1735 *restrict cache_info;
1738 id = GetOpenMPThreadId();
1743 assert(image != (const Image *) NULL);
1744 assert(image->signature == MagickSignature);
1745 assert(image->cache != (Cache) NULL);
1746 cache_info=(CacheInfo *) image->cache;
1747 assert(cache_info->signature == MagickSignature);
1748 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1749 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1750 (GetOneVirtualPixelFromHandler) NULL)
1751 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1752 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1753 assert(id < (int) cache_info->number_threads);
1754 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1755 1UL,1UL,cache_info->nexus_info[id],exception);
1756 return(CopyPixel(image,p,pixel));
1760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764 + 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 %
1768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1771 % specified (x,y) location. The image background color is returned if an
1774 % The format of the GetOneVirtualPixelFromCache() method is:
1776 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1777 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1778 % Quantum *pixel,ExceptionInfo *exception)
1780 % A description of each parameter follows:
1782 % o image: the image.
1784 % o virtual_pixel_method: the virtual pixel method.
1786 % o x,y: These values define the location of the pixel to return.
1788 % o pixel: return a pixel at the specified (x,y) location.
1790 % o exception: return any errors or warnings in this structure.
1793 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1794 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1795 Quantum *pixel,ExceptionInfo *exception)
1798 *restrict cache_info;
1801 id = GetOpenMPThreadId();
1806 assert(image != (const Image *) NULL);
1807 assert(image->signature == MagickSignature);
1808 assert(image->cache != (Cache) NULL);
1809 cache_info=(CacheInfo *) image->cache;
1810 assert(cache_info->signature == MagickSignature);
1811 assert(id < (int) cache_info->number_threads);
1812 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1813 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1814 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 I n f o %
1827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1829 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1830 % location. The image background color is returned if an error occurs. If
1831 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1833 % The format of the GetOneVirtualPixelInfo() method is:
1835 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1836 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1837 % const ssize_t y,PixelInfo *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 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1853 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1854 PixelInfo *pixel,ExceptionInfo *exception)
1857 *restrict cache_info;
1860 id = GetOpenMPThreadId();
1862 register const Quantum
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 GetPixelInfo(image,pixel);
1872 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1873 cache_info->nexus_info[id],exception);
1874 if (p == (const Quantum *) NULL)
1875 return(MagickFalse);
1876 GetPixelInfoPixel(image,p,pixel);
1881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1885 + G e t P i x e l C a c h e C o l o r s p a c e %
1889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1891 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1893 % The format of the GetPixelCacheColorspace() method is:
1895 % Colorspace GetPixelCacheColorspace(Cache cache)
1897 % A description of each parameter follows:
1899 % o cache: the pixel cache.
1902 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1905 *restrict cache_info;
1907 assert(cache != (Cache) NULL);
1908 cache_info=(CacheInfo *) cache;
1909 assert(cache_info->signature == MagickSignature);
1910 if (cache_info->debug != MagickFalse)
1911 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1912 cache_info->filename);
1913 return(cache_info->colorspace);
1917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1921 + G e t P i x e l C a c h e M e t h o d s %
1925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1927 % GetPixelCacheMethods() initializes the CacheMethods structure.
1929 % The format of the GetPixelCacheMethods() method is:
1931 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1933 % A description of each parameter follows:
1935 % o cache_methods: Specifies a pointer to a CacheMethods structure.
1938 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
1940 assert(cache_methods != (CacheMethods *) NULL);
1941 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
1942 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
1943 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
1944 cache_methods->get_virtual_metacontent_from_handler=
1945 GetVirtualMetacontentFromCache;
1946 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
1947 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
1948 cache_methods->get_authentic_metacontent_from_handler=
1949 GetAuthenticMetacontentFromCache;
1950 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
1951 cache_methods->get_one_authentic_pixel_from_handler=
1952 GetOneAuthenticPixelFromCache;
1953 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
1954 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
1955 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
1959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1963 + G e t P i x e l C a c h e N e x u s E x t e n t %
1967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1969 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
1970 % corresponding with the last call to SetPixelCacheNexusPixels() or
1971 % GetPixelCacheNexusPixels().
1973 % The format of the GetPixelCacheNexusExtent() method is:
1975 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
1976 % NexusInfo *nexus_info)
1978 % A description of each parameter follows:
1980 % o nexus_info: the nexus info.
1983 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
1984 NexusInfo *restrict nexus_info)
1987 *restrict cache_info;
1992 assert(cache != NULL);
1993 cache_info=(CacheInfo *) cache;
1994 assert(cache_info->signature == MagickSignature);
1995 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
1997 return((MagickSizeType) cache_info->columns*cache_info->rows);
2002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2006 + G e t P i x e l C a c h e P i x e l s %
2010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012 % GetPixelCachePixels() returns the pixels associated with the specified image.
2014 % The format of the GetPixelCachePixels() method is:
2016 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2017 % ExceptionInfo *exception)
2019 % A description of each parameter follows:
2021 % o image: the image.
2023 % o length: the pixel cache length.
2025 % o exception: return any errors or warnings in this structure.
2028 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2029 ExceptionInfo *exception)
2032 *restrict cache_info;
2034 assert(image != (const Image *) NULL);
2035 assert(image->signature == MagickSignature);
2036 assert(image->cache != (Cache) NULL);
2037 assert(length != (MagickSizeType *) NULL);
2038 assert(exception != (ExceptionInfo *) NULL);
2039 assert(exception->signature == MagickSignature);
2040 cache_info=(CacheInfo *) image->cache;
2041 assert(cache_info->signature == MagickSignature);
2043 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2044 return((void *) NULL);
2045 *length=cache_info->length;
2046 return((void *) cache_info->pixels);
2050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2054 + 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 %
2058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2060 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2062 % The format of the GetPixelCacheStorageClass() method is:
2064 % ClassType GetPixelCacheStorageClass(Cache cache)
2066 % A description of each parameter follows:
2068 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2070 % o cache: the pixel cache.
2073 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2076 *restrict cache_info;
2078 assert(cache != (Cache) NULL);
2079 cache_info=(CacheInfo *) cache;
2080 assert(cache_info->signature == MagickSignature);
2081 if (cache_info->debug != MagickFalse)
2082 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2083 cache_info->filename);
2084 return(cache_info->storage_class);
2088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2092 + G e t P i x e l C a c h e T i l e S i z e %
2096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2098 % GetPixelCacheTileSize() returns the pixel cache tile size.
2100 % The format of the GetPixelCacheTileSize() method is:
2102 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2105 % A description of each parameter follows:
2107 % o image: the image.
2109 % o width: the optimize cache tile width in pixels.
2111 % o height: the optimize cache tile height in pixels.
2114 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2118 *restrict cache_info;
2120 assert(image != (Image *) NULL);
2121 assert(image->signature == MagickSignature);
2122 if (image->debug != MagickFalse)
2123 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2124 cache_info=(CacheInfo *) image->cache;
2125 assert(cache_info->signature == MagickSignature);
2126 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2127 if (GetImagePixelCacheType(image) == DiskCache)
2128 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2137 + 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 %
2141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2143 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2144 % pixel cache. A virtual pixel is any pixel access that is outside the
2145 % boundaries of the image cache.
2147 % The format of the GetPixelCacheVirtualMethod() method is:
2149 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2151 % A description of each parameter follows:
2153 % o image: the image.
2156 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2159 *restrict cache_info;
2161 assert(image != (Image *) NULL);
2162 assert(image->signature == MagickSignature);
2163 assert(image->cache != (Cache) NULL);
2164 cache_info=(CacheInfo *) image->cache;
2165 assert(cache_info->signature == MagickSignature);
2166 return(cache_info->virtual_pixel_method);
2170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2174 + 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 %
2178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2180 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2181 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2183 % The format of the GetVirtualMetacontentFromCache() method is:
2185 % void *GetVirtualMetacontentFromCache(const Image *image)
2187 % A description of each parameter follows:
2189 % o image: the image.
2192 static const void *GetVirtualMetacontentFromCache(const Image *image)
2195 *restrict cache_info;
2198 id = GetOpenMPThreadId();
2201 *restrict metacontent;
2203 assert(image != (const Image *) NULL);
2204 assert(image->signature == MagickSignature);
2205 assert(image->cache != (Cache) NULL);
2206 cache_info=(CacheInfo *) image->cache;
2207 assert(cache_info->signature == MagickSignature);
2208 assert(id < (int) cache_info->number_threads);
2209 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2210 cache_info->nexus_info[id]);
2211 return(metacontent);
2215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2219 + 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 %
2223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2228 % The format of the GetVirtualMetacontentFromNexus() method is:
2230 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2231 % NexusInfo *nexus_info)
2233 % A description of each parameter follows:
2235 % o cache: the pixel cache.
2237 % o nexus_info: the cache nexus to return the meta-content.
2240 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2241 NexusInfo *restrict nexus_info)
2244 *restrict cache_info;
2246 assert(cache != (Cache) NULL);
2247 cache_info=(CacheInfo *) cache;
2248 assert(cache_info->signature == MagickSignature);
2249 if (cache_info->storage_class == UndefinedClass)
2250 return((void *) NULL);
2251 return(nexus_info->metacontent);
2255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2259 % G e t V i r t u a l M e t a c o n t e n t %
2263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2265 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2266 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2267 % returned if the meta-content are not available.
2269 % The format of the GetVirtualMetacontent() method is:
2271 % const void *GetVirtualMetacontent(const Image *image)
2273 % A description of each parameter follows:
2275 % o image: the image.
2278 MagickExport const void *GetVirtualMetacontent(const Image *image)
2281 *restrict cache_info;
2284 id = GetOpenMPThreadId();
2287 *restrict metacontent;
2289 assert(image != (const Image *) NULL);
2290 assert(image->signature == MagickSignature);
2291 assert(image->cache != (Cache) NULL);
2292 cache_info=(CacheInfo *) image->cache;
2293 assert(cache_info->signature == MagickSignature);
2294 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2295 if (metacontent != (void *) NULL)
2296 return(metacontent);
2297 assert(id < (int) cache_info->number_threads);
2298 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2299 cache_info->nexus_info[id]);
2300 return(metacontent);
2304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2308 + 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 %
2312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2314 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2315 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2316 % is returned if the pixels are transferred, otherwise a NULL is returned.
2318 % The format of the GetVirtualPixelsFromNexus() method is:
2320 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2321 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2322 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2323 % ExceptionInfo *exception)
2325 % A description of each parameter follows:
2327 % o image: the image.
2329 % o virtual_pixel_method: the virtual pixel method.
2331 % o x,y,columns,rows: These values define the perimeter of a region of
2334 % o nexus_info: the cache nexus to acquire.
2336 % o exception: return any errors or warnings in this structure.
2343 0, 48, 12, 60, 3, 51, 15, 63,
2344 32, 16, 44, 28, 35, 19, 47, 31,
2345 8, 56, 4, 52, 11, 59, 7, 55,
2346 40, 24, 36, 20, 43, 27, 39, 23,
2347 2, 50, 14, 62, 1, 49, 13, 61,
2348 34, 18, 46, 30, 33, 17, 45, 29,
2349 10, 58, 6, 54, 9, 57, 5, 53,
2350 42, 26, 38, 22, 41, 25, 37, 21
2353 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2358 index=x+DitherMatrix[x & 0x07]-32L;
2361 if (index >= (ssize_t) columns)
2362 return((ssize_t) columns-1L);
2366 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2371 index=y+DitherMatrix[y & 0x07]-32L;
2374 if (index >= (ssize_t) rows)
2375 return((ssize_t) rows-1L);
2379 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2383 if (x >= (ssize_t) columns)
2384 return((ssize_t) (columns-1));
2388 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2392 if (y >= (ssize_t) rows)
2393 return((ssize_t) (rows-1));
2397 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2399 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2402 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2404 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2407 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2408 const size_t extent)
2414 Compute the remainder of dividing offset by extent. It returns not only
2415 the quotient (tile the offset falls in) but also the positive remainer
2416 within that tile such that 0 <= remainder < extent. This method is
2417 essentially a ldiv() using a floored modulo division rather than the
2418 normal default truncated modulo division.
2420 modulo.quotient=offset/(ssize_t) extent;
2423 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2427 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2428 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2429 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2430 ExceptionInfo *exception)
2433 *restrict cache_info;
2443 **restrict virtual_nexus;
2447 virtual_pixel[MaxPixelChannels];
2452 register const Quantum
2465 register unsigned char
2472 *restrict virtual_metacontent;
2477 assert(image != (const Image *) NULL);
2478 assert(image->signature == MagickSignature);
2479 assert(image->cache != (Cache) NULL);
2480 cache_info=(CacheInfo *) image->cache;
2481 assert(cache_info->signature == MagickSignature);
2482 if (cache_info->type == UndefinedCache)
2483 return((const Quantum *) NULL);
2486 region.width=columns;
2488 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2490 if (pixels == (Quantum *) NULL)
2491 return((const Quantum *) NULL);
2493 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2494 nexus_info->region.x;
2495 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2496 nexus_info->region.width-1L;
2497 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2498 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2499 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2500 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2506 Pixel request is inside cache extents.
2508 if (nexus_info->authentic_pixel_cache != MagickFalse)
2510 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2511 if (status == MagickFalse)
2512 return((const Quantum *) NULL);
2513 if (cache_info->metacontent_extent != 0)
2515 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2516 if (status == MagickFalse)
2517 return((const Quantum *) NULL);
2522 Pixel request is outside cache extents.
2524 s=(unsigned char *) nexus_info->metacontent;
2525 virtual_nexus=AcquirePixelCacheNexus(1);
2526 if (virtual_nexus == (NexusInfo **) NULL)
2528 if (virtual_nexus != (NexusInfo **) NULL)
2529 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2530 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2531 "UnableToGetCacheNexus","`%s'",image->filename);
2532 return((const Quantum *) NULL);
2534 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2535 sizeof(*virtual_pixel));
2536 virtual_metacontent=(void *) NULL;
2537 switch (virtual_pixel_method)
2539 case BackgroundVirtualPixelMethod:
2540 case BlackVirtualPixelMethod:
2541 case GrayVirtualPixelMethod:
2542 case TransparentVirtualPixelMethod:
2543 case MaskVirtualPixelMethod:
2544 case WhiteVirtualPixelMethod:
2545 case EdgeVirtualPixelMethod:
2546 case CheckerTileVirtualPixelMethod:
2547 case HorizontalTileVirtualPixelMethod:
2548 case VerticalTileVirtualPixelMethod:
2550 if (cache_info->metacontent_extent != 0)
2553 Acquire a metacontent buffer.
2555 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2556 cache_info->metacontent_extent);
2557 if (virtual_metacontent == (void *) NULL)
2559 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2560 (void) ThrowMagickException(exception,GetMagickModule(),
2561 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2562 return((const Quantum *) NULL);
2564 (void) ResetMagickMemory(virtual_metacontent,0,
2565 cache_info->metacontent_extent);
2567 switch (virtual_pixel_method)
2569 case BlackVirtualPixelMethod:
2571 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2572 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2573 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2576 case GrayVirtualPixelMethod:
2578 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2579 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2581 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2584 case TransparentVirtualPixelMethod:
2586 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2587 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2588 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2591 case MaskVirtualPixelMethod:
2592 case WhiteVirtualPixelMethod:
2594 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2595 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2596 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2601 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2603 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2605 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2607 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2609 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2619 for (v=0; v < (ssize_t) rows; v++)
2625 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2626 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2627 y_offset=EdgeY(y_offset,cache_info->rows);
2628 for (u=0; u < (ssize_t) columns; u+=length)
2634 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2635 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2636 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2644 Transfer a single pixel.
2646 length=(MagickSizeType) 1;
2647 switch (virtual_pixel_method)
2649 case EdgeVirtualPixelMethod:
2652 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2653 EdgeX(x_offset,cache_info->columns),
2654 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2656 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2659 case RandomVirtualPixelMethod:
2661 if (cache_info->random_info == (RandomInfo *) NULL)
2662 cache_info->random_info=AcquireRandomInfo();
2663 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2664 RandomX(cache_info->random_info,cache_info->columns),
2665 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2666 *virtual_nexus,exception);
2667 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2670 case DitherVirtualPixelMethod:
2672 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2673 DitherX(x_offset,cache_info->columns),
2674 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2676 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2679 case TileVirtualPixelMethod:
2681 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2682 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2683 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2684 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2686 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2689 case MirrorVirtualPixelMethod:
2691 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2692 if ((x_modulo.quotient & 0x01) == 1L)
2693 x_modulo.remainder=(ssize_t) cache_info->columns-
2694 x_modulo.remainder-1L;
2695 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2696 if ((y_modulo.quotient & 0x01) == 1L)
2697 y_modulo.remainder=(ssize_t) cache_info->rows-
2698 y_modulo.remainder-1L;
2699 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2700 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2702 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2705 case HorizontalTileEdgeVirtualPixelMethod:
2707 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2708 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2709 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2710 *virtual_nexus,exception);
2711 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2714 case VerticalTileEdgeVirtualPixelMethod:
2716 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2717 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2718 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2719 *virtual_nexus,exception);
2720 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2723 case BackgroundVirtualPixelMethod:
2724 case BlackVirtualPixelMethod:
2725 case GrayVirtualPixelMethod:
2726 case TransparentVirtualPixelMethod:
2727 case MaskVirtualPixelMethod:
2728 case WhiteVirtualPixelMethod:
2731 r=virtual_metacontent;
2734 case CheckerTileVirtualPixelMethod:
2736 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2737 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2738 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2741 r=virtual_metacontent;
2744 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2745 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2747 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2750 case HorizontalTileVirtualPixelMethod:
2752 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2755 r=virtual_metacontent;
2758 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2759 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2760 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2761 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2763 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2766 case VerticalTileVirtualPixelMethod:
2768 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2771 r=virtual_metacontent;
2774 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2775 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2776 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2777 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2779 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2783 if (p == (const Quantum *) NULL)
2785 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2787 q+=cache_info->number_channels;
2788 if ((s != (void *) NULL) && (r != (const void *) NULL))
2790 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2791 s+=cache_info->metacontent_extent;
2796 Transfer a run of pixels.
2798 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2799 (size_t) length,1UL,*virtual_nexus,exception);
2800 if (p == (const Quantum *) NULL)
2802 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2803 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2804 q+=length*cache_info->number_channels;
2805 if ((r != (void *) NULL) && (s != (const void *) NULL))
2807 (void) memcpy(s,r,(size_t) length);
2808 s+=length*cache_info->metacontent_extent;
2815 if (virtual_metacontent != (void *) NULL)
2816 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2817 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2826 + G e t V i r t u a l P i x e l C a c h e %
2830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2833 % cache as defined by the geometry parameters. A pointer to the pixels
2834 % is returned if the pixels are transferred, otherwise a NULL is returned.
2836 % The format of the GetVirtualPixelCache() method is:
2838 % const Quantum *GetVirtualPixelCache(const Image *image,
2839 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2840 % const ssize_t y,const size_t columns,const size_t rows,
2841 % ExceptionInfo *exception)
2843 % A description of each parameter follows:
2845 % o image: the image.
2847 % o virtual_pixel_method: the virtual pixel method.
2849 % o x,y,columns,rows: These values define the perimeter of a region of
2852 % o exception: return any errors or warnings in this structure.
2855 static const Quantum *GetVirtualPixelCache(const Image *image,
2856 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2857 const size_t columns,const size_t rows,ExceptionInfo *exception)
2860 *restrict cache_info;
2863 id = GetOpenMPThreadId();
2868 assert(image != (const Image *) NULL);
2869 assert(image->signature == MagickSignature);
2870 assert(image->cache != (Cache) NULL);
2871 cache_info=(CacheInfo *) image->cache;
2872 assert(cache_info->signature == MagickSignature);
2873 assert(id < (int) cache_info->number_threads);
2874 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2875 cache_info->nexus_info[id],exception);
2880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884 % G e t V i r t u a l P i x e l Q u e u e %
2888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2890 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2891 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2893 % The format of the GetVirtualPixelQueue() method is:
2895 % const Quantum *GetVirtualPixelQueue(const Image image)
2897 % A description of each parameter follows:
2899 % o image: the image.
2902 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2905 *restrict cache_info;
2908 id = GetOpenMPThreadId();
2910 assert(image != (const Image *) NULL);
2911 assert(image->signature == MagickSignature);
2912 assert(image->cache != (Cache) NULL);
2913 cache_info=(CacheInfo *) image->cache;
2914 assert(cache_info->signature == MagickSignature);
2915 if (cache_info->methods.get_virtual_pixels_handler !=
2916 (GetVirtualPixelsHandler) NULL)
2917 return(cache_info->methods.get_virtual_pixels_handler(image));
2918 assert(id < (int) cache_info->number_threads);
2919 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927 % G e t V i r t u a l P i x e l s %
2931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2933 % GetVirtualPixels() returns an immutable pixel region. If the
2934 % region is successfully accessed, a pointer to it is returned, otherwise
2935 % NULL is returned. The returned pointer may point to a temporary working
2936 % copy of the pixels or it may point to the original pixels in memory.
2937 % Performance is maximized if the selected region is part of one row, or one
2938 % or more full rows, since there is opportunity to access the pixels in-place
2939 % (without a copy) if the image is in memory, or in a memory-mapped file. The
2940 % returned pointer must *never* be deallocated by the user.
2942 % Pixels accessed via the returned pointer represent a simple array of type
2943 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
2944 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
2945 % access the meta-content (of type void) corresponding to the the
2948 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
2950 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
2951 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
2952 % GetCacheViewAuthenticPixels() instead.
2954 % The format of the GetVirtualPixels() method is:
2956 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
2957 % const ssize_t y,const size_t columns,const size_t rows,
2958 % ExceptionInfo *exception)
2960 % A description of each parameter follows:
2962 % o image: the image.
2964 % o x,y,columns,rows: These values define the perimeter of a region of
2967 % o exception: return any errors or warnings in this structure.
2970 MagickExport const Quantum *GetVirtualPixels(const Image *image,
2971 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
2972 ExceptionInfo *exception)
2975 *restrict cache_info;
2978 id = GetOpenMPThreadId();
2983 assert(image != (const Image *) NULL);
2984 assert(image->signature == MagickSignature);
2985 assert(image->cache != (Cache) NULL);
2986 cache_info=(CacheInfo *) image->cache;
2987 assert(cache_info->signature == MagickSignature);
2988 if (cache_info->methods.get_virtual_pixel_handler !=
2989 (GetVirtualPixelHandler) NULL)
2990 return(cache_info->methods.get_virtual_pixel_handler(image,
2991 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
2992 assert(id < (int) cache_info->number_threads);
2993 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2994 columns,rows,cache_info->nexus_info[id],exception);
2999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3003 + 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 %
3007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3009 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3010 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3012 % The format of the GetVirtualPixelsCache() method is:
3014 % Quantum *GetVirtualPixelsCache(const Image *image)
3016 % A description of each parameter follows:
3018 % o image: the image.
3021 static const Quantum *GetVirtualPixelsCache(const Image *image)
3024 *restrict cache_info;
3027 id = GetOpenMPThreadId();
3029 assert(image != (const Image *) NULL);
3030 assert(image->signature == MagickSignature);
3031 assert(image->cache != (Cache) NULL);
3032 cache_info=(CacheInfo *) image->cache;
3033 assert(cache_info->signature == MagickSignature);
3034 assert(id < (int) cache_info->number_threads);
3035 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3043 + G e t V i r t u a l P i x e l s N e x u s %
3047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3052 % The format of the GetVirtualPixelsNexus() method is:
3054 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3055 % NexusInfo *nexus_info)
3057 % A description of each parameter follows:
3059 % o cache: the pixel cache.
3061 % o nexus_info: the cache nexus to return the colormap pixels.
3064 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3065 NexusInfo *restrict nexus_info)
3068 *restrict cache_info;
3070 assert(cache != (Cache) NULL);
3071 cache_info=(CacheInfo *) cache;
3072 assert(cache_info->signature == MagickSignature);
3073 if (cache_info->storage_class == UndefinedClass)
3074 return((Quantum *) NULL);
3075 return((const Quantum *) nexus_info->pixels);
3079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3083 + O p e n P i x e l C a c h e %
3087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3089 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3090 % dimensions, allocating space for the image pixels and optionally the
3091 % metacontent, and memory mapping the cache if it is disk based. The cache
3092 % nexus array is initialized as well.
3094 % The format of the OpenPixelCache() method is:
3096 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3097 % ExceptionInfo *exception)
3099 % A description of each parameter follows:
3101 % o image: the image.
3103 % o mode: ReadMode, WriteMode, or IOMode.
3105 % o exception: return any errors or warnings in this structure.
3109 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3111 cache_info->mapped=MagickFalse;
3112 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3113 (size_t) cache_info->length));
3114 if (cache_info->pixels == (Quantum *) NULL)
3116 cache_info->mapped=MagickTrue;
3117 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3118 cache_info->length);
3122 #if defined(__cplusplus) || defined(c_plusplus)
3127 static void CacheSignalHandler(int status)
3129 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3133 #if defined(__cplusplus) || defined(c_plusplus)
3137 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3144 Open pixel cache on disk.
3146 if (cache_info->file != -1)
3147 return(MagickTrue); /* cache already open */
3148 if (*cache_info->cache_filename == '\0')
3149 file=AcquireUniqueFileResource(cache_info->cache_filename);
3155 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3160 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3161 O_BINARY | O_EXCL,S_MODE);
3163 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3169 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3172 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3177 return(MagickFalse);
3178 (void) AcquireMagickResource(FileResource,1);
3179 cache_info->file=file;
3180 cache_info->mode=mode;
3184 static inline MagickOffsetType WritePixelCacheRegion(
3185 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3186 const MagickSizeType length,const unsigned char *restrict buffer)
3188 register MagickOffsetType
3194 #if !defined(MAGICKCORE_HAVE_PWRITE)
3195 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3196 return((MagickOffsetType) -1);
3199 for (i=0; i < (MagickOffsetType) length; i+=count)
3201 #if !defined(MAGICKCORE_HAVE_PWRITE)
3202 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3203 (MagickSizeType) SSIZE_MAX));
3205 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3206 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3218 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3221 *restrict cache_info;
3228 cache_info=(CacheInfo *) image->cache;
3229 if (image->debug != MagickFalse)
3232 format[MaxTextExtent],
3233 message[MaxTextExtent];
3235 (void) FormatMagickSize(length,MagickFalse,"B",MaxTextExtent,format);
3236 (void) FormatLocaleString(message,MaxTextExtent,
3237 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3238 cache_info->cache_filename,cache_info->file,format);
3239 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3241 if (length != (MagickSizeType) ((MagickOffsetType) length))
3242 return(MagickFalse);
3243 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3245 return(MagickFalse);
3246 if ((MagickSizeType) offset >= length)
3248 extent=(MagickOffsetType) length-1;
3249 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3250 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3251 if (cache_info->synchronize != MagickFalse)
3252 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3255 (void) signal(SIGBUS,CacheSignalHandler);
3257 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3260 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3261 ExceptionInfo *exception)
3264 *restrict cache_info,
3268 format[MaxTextExtent],
3269 message[MaxTextExtent];
3285 assert(image != (const Image *) NULL);
3286 assert(image->signature == MagickSignature);
3287 assert(image->cache != (Cache) NULL);
3288 if (image->debug != MagickFalse)
3289 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3290 if ((image->columns == 0) || (image->rows == 0))
3291 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3292 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3293 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3294 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3296 cache_info=(CacheInfo *) image->cache;
3297 assert(cache_info->signature == MagickSignature);
3298 source_info=(*cache_info);
3299 source_info.file=(-1);
3300 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3301 image->filename,(double) GetImageIndexInList(image));
3302 cache_info->storage_class=image->storage_class;
3303 cache_info->colorspace=image->colorspace;
3304 cache_info->alpha_trait=image->alpha_trait;
3305 cache_info->read_mask=image->read_mask;
3306 cache_info->write_mask=image->write_mask;
3307 cache_info->rows=image->rows;
3308 cache_info->columns=image->columns;
3309 InitializePixelChannelMap(image);
3310 cache_info->number_channels=GetPixelChannels(image);
3311 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3312 sizeof(*image->channel_map));
3313 cache_info->metacontent_extent=image->metacontent_extent;
3314 cache_info->mode=mode;
3315 if (image->ping != MagickFalse)
3317 cache_info->type=PingCache;
3318 cache_info->pixels=(Quantum *) NULL;
3319 cache_info->metacontent=(void *) NULL;
3320 cache_info->length=0;
3323 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3324 packet_size=cache_info->number_channels*sizeof(Quantum);
3325 if (image->metacontent_extent != 0)
3326 packet_size+=cache_info->metacontent_extent;
3327 length=number_pixels*packet_size;
3328 columns=(size_t) (length/cache_info->rows/packet_size);
3329 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3330 ((ssize_t) cache_info->rows < 0))
3331 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3333 cache_info->length=length;
3334 status=AcquireMagickResource(AreaResource,cache_info->length);
3335 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3336 cache_info->metacontent_extent);
3337 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3339 status=AcquireMagickResource(MemoryResource,cache_info->length);
3340 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3341 (cache_info->type == MemoryCache))
3343 AllocatePixelCachePixels(cache_info);
3344 if (cache_info->pixels == (Quantum *) NULL)
3345 cache_info->pixels=source_info.pixels;
3349 Create memory pixel cache.
3352 cache_info->type=MemoryCache;
3353 cache_info->metacontent=(void *) NULL;
3354 if (cache_info->metacontent_extent != 0)
3355 cache_info->metacontent=(void *) (cache_info->pixels+
3356 number_pixels*cache_info->number_channels);
3357 if ((source_info.storage_class != UndefinedClass) &&
3360 status=ClonePixelCacheRepository(cache_info,&source_info,
3362 RelinquishPixelCachePixels(&source_info);
3364 if (image->debug != MagickFalse)
3366 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3367 MaxTextExtent,format);
3368 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3370 (void) FormatLocaleString(message,MaxTextExtent,
3371 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3372 cache_info->filename,cache_info->mapped != MagickFalse ?
3373 "Anonymous" : "Heap",type,(double) cache_info->columns,
3374 (double) cache_info->rows,(double)
3375 cache_info->number_channels,format);
3376 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3382 RelinquishMagickResource(MemoryResource,cache_info->length);
3385 Create pixel cache on disk.
3387 status=AcquireMagickResource(DiskResource,cache_info->length);
3388 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3393 if (cache_info->type == DistributedCache)
3394 RelinquishMagickResource(DiskResource,cache_info->length);
3395 server_info=AcquireDistributeCacheInfo(exception);
3396 if (server_info != (DistributeCacheInfo *) NULL)
3398 status=OpenDistributePixelCache(server_info,image);
3399 if (status == MagickFalse)
3401 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3402 GetDistributeCacheHostname(server_info));
3403 server_info=DestroyDistributeCacheInfo(server_info);
3408 Create a distributed pixel cache.
3410 cache_info->type=DistributedCache;
3411 cache_info->server_info=server_info;
3412 (void) FormatLocaleString(cache_info->cache_filename,
3413 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3414 (DistributeCacheInfo *) cache_info->server_info),
3415 GetDistributeCachePort((DistributeCacheInfo *)
3416 cache_info->server_info));
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,MagickFalse,"B",
3427 MaxTextExtent,format);
3428 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3430 (void) FormatLocaleString(message,MaxTextExtent,
3431 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3432 cache_info->filename,cache_info->cache_filename,
3433 GetDistributeCacheFile((DistributeCacheInfo *)
3434 cache_info->server_info),type,(double) cache_info->columns,
3435 (double) cache_info->rows,(double)
3436 cache_info->number_channels,format);
3437 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3443 RelinquishMagickResource(DiskResource,cache_info->length);
3444 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3445 "CacheResourcesExhausted","`%s'",image->filename);
3446 return(MagickFalse);
3448 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3450 (void) ClosePixelCacheOnDisk(cache_info);
3451 *cache_info->cache_filename='\0';
3453 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3455 RelinquishMagickResource(DiskResource,cache_info->length);
3456 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3458 return(MagickFalse);
3460 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3461 cache_info->length);
3462 if (status == MagickFalse)
3464 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3466 return(MagickFalse);
3468 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3469 cache_info->metacontent_extent);
3470 if (length != (MagickSizeType) ((size_t) length))
3471 cache_info->type=DiskCache;
3474 status=AcquireMagickResource(MapResource,cache_info->length);
3475 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3476 (cache_info->type != MemoryCache))
3477 cache_info->type=DiskCache;
3480 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3481 cache_info->offset,(size_t) cache_info->length);
3482 if (cache_info->pixels == (Quantum *) NULL)
3484 cache_info->type=DiskCache;
3485 cache_info->pixels=source_info.pixels;
3490 Create file-backed memory-mapped pixel cache.
3493 (void) ClosePixelCacheOnDisk(cache_info);
3494 cache_info->type=MapCache;
3495 cache_info->mapped=MagickTrue;
3496 cache_info->metacontent=(void *) NULL;
3497 if (cache_info->metacontent_extent != 0)
3498 cache_info->metacontent=(void *) (cache_info->pixels+
3499 number_pixels*cache_info->number_channels);
3500 if ((source_info.storage_class != UndefinedClass) &&
3503 status=ClonePixelCacheRepository(cache_info,&source_info,
3505 RelinquishPixelCachePixels(&source_info);
3507 if (image->debug != MagickFalse)
3509 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3510 MaxTextExtent,format);
3511 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3513 (void) FormatLocaleString(message,MaxTextExtent,
3514 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3515 cache_info->filename,cache_info->cache_filename,
3516 cache_info->file,type,(double) cache_info->columns,(double)
3517 cache_info->rows,(double) cache_info->number_channels,
3519 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3525 RelinquishMagickResource(MapResource,cache_info->length);
3528 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3530 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3531 RelinquishPixelCachePixels(&source_info);
3533 if (image->debug != MagickFalse)
3535 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",MaxTextExtent,
3537 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3539 (void) FormatLocaleString(message,MaxTextExtent,
3540 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3541 cache_info->cache_filename,cache_info->file,type,(double)
3542 cache_info->columns,(double) cache_info->rows,(double)
3543 cache_info->number_channels,format);
3544 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3554 + P e r s i s t P i x e l C a c h e %
3558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3560 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3561 % persistent pixel cache is one that resides on disk and is not destroyed
3562 % when the program exits.
3564 % The format of the PersistPixelCache() method is:
3566 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3567 % const MagickBooleanType attach,MagickOffsetType *offset,
3568 % ExceptionInfo *exception)
3570 % A description of each parameter follows:
3572 % o image: the image.
3574 % o filename: the persistent pixel cache filename.
3576 % o attach: A value other than zero initializes the persistent pixel cache.
3578 % o initialize: A value other than zero initializes the persistent pixel
3581 % o offset: the offset in the persistent cache to store pixels.
3583 % o exception: return any errors or warnings in this structure.
3586 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3587 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3588 ExceptionInfo *exception)
3591 *restrict cache_info,
3592 *restrict clone_info;
3603 assert(image != (Image *) NULL);
3604 assert(image->signature == MagickSignature);
3605 if (image->debug != MagickFalse)
3606 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3607 assert(image->cache != (void *) NULL);
3608 assert(filename != (const char *) NULL);
3609 assert(offset != (MagickOffsetType *) NULL);
3610 page_size=GetMagickPageSize();
3611 cache_info=(CacheInfo *) image->cache;
3612 assert(cache_info->signature == MagickSignature);
3613 if (attach != MagickFalse)
3616 Attach existing persistent pixel cache.
3618 if (image->debug != MagickFalse)
3619 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3620 "attach persistent cache");
3621 (void) CopyMagickString(cache_info->cache_filename,filename,
3623 cache_info->type=DiskCache;
3624 cache_info->offset=(*offset);
3625 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3626 return(MagickFalse);
3627 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3630 if ((cache_info->mode != ReadMode) &&
3631 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3632 (cache_info->reference_count == 1))
3634 LockSemaphoreInfo(cache_info->semaphore);
3635 if ((cache_info->mode != ReadMode) &&
3636 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3637 (cache_info->reference_count == 1))
3643 Usurp existing persistent pixel cache.
3645 status=rename_utf8(cache_info->cache_filename,filename);
3648 (void) CopyMagickString(cache_info->cache_filename,filename,
3650 *offset+=cache_info->length+page_size-(cache_info->length %
3652 UnlockSemaphoreInfo(cache_info->semaphore);
3653 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3654 if (image->debug != MagickFalse)
3655 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3656 "Usurp resident persistent cache");
3660 UnlockSemaphoreInfo(cache_info->semaphore);
3663 Clone persistent pixel cache.
3665 clone_image=(*image);
3666 clone_info=(CacheInfo *) clone_image.cache;
3667 image->cache=ClonePixelCache(cache_info);
3668 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3669 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3670 cache_info->type=DiskCache;
3671 cache_info->offset=(*offset);
3672 cache_info=(CacheInfo *) image->cache;
3673 status=OpenPixelCache(image,IOMode,exception);
3674 if (status != MagickFalse)
3675 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3676 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3677 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3686 + 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 %
3690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3692 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3693 % defined by the region rectangle and returns a pointer to the region. This
3694 % region is subsequently transferred from the pixel cache with
3695 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3696 % pixels are transferred, otherwise a NULL is returned.
3698 % The format of the QueueAuthenticPixelCacheNexus() method is:
3700 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3701 % const ssize_t y,const size_t columns,const size_t rows,
3702 % const MagickBooleanType clone,NexusInfo *nexus_info,
3703 % ExceptionInfo *exception)
3705 % A description of each parameter follows:
3707 % o image: the image.
3709 % o x,y,columns,rows: These values define the perimeter of a region of
3712 % o nexus_info: the cache nexus to set.
3714 % o clone: clone the pixel cache.
3716 % o exception: return any errors or warnings in this structure.
3719 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3720 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3721 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3724 *restrict cache_info;
3739 Validate pixel cache geometry.
3741 assert(image != (const Image *) NULL);
3742 assert(image->signature == MagickSignature);
3743 assert(image->cache != (Cache) NULL);
3744 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3745 if (cache_info == (Cache) NULL)
3746 return((Quantum *) NULL);
3747 assert(cache_info->signature == MagickSignature);
3748 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3749 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3750 (y >= (ssize_t) cache_info->rows))
3752 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3753 "PixelsAreNotAuthentic","`%s'",image->filename);
3754 return((Quantum *) NULL);
3756 offset=(MagickOffsetType) y*cache_info->columns+x;
3758 return((Quantum *) NULL);
3759 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3760 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3761 if ((MagickSizeType) offset >= number_pixels)
3762 return((Quantum *) NULL);
3768 region.width=columns;
3770 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3780 + 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 %
3784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3786 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3787 % defined by the region rectangle and returns a pointer to the region. This
3788 % region is subsequently transferred from the pixel cache with
3789 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3790 % pixels are transferred, otherwise a NULL is returned.
3792 % The format of the QueueAuthenticPixelsCache() method is:
3794 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3795 % const ssize_t y,const size_t columns,const size_t rows,
3796 % ExceptionInfo *exception)
3798 % A description of each parameter follows:
3800 % o image: the image.
3802 % o x,y,columns,rows: These values define the perimeter of a region of
3805 % o exception: return any errors or warnings in this structure.
3808 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3809 const ssize_t y,const size_t columns,const size_t rows,
3810 ExceptionInfo *exception)
3813 *restrict cache_info;
3816 id = GetOpenMPThreadId();
3821 assert(image != (const Image *) NULL);
3822 assert(image->signature == MagickSignature);
3823 assert(image->cache != (Cache) NULL);
3824 cache_info=(CacheInfo *) image->cache;
3825 assert(cache_info->signature == MagickSignature);
3826 assert(id < (int) cache_info->number_threads);
3827 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3828 cache_info->nexus_info[id],exception);
3833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3837 % Q u e u e A u t h e n t i c P i x e l s %
3841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3843 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3844 % successfully initialized a pointer to a Quantum array representing the
3845 % region is returned, otherwise NULL is returned. The returned pointer may
3846 % point to a temporary working buffer for the pixels or it may point to the
3847 % final location of the pixels in memory.
3849 % Write-only access means that any existing pixel values corresponding to
3850 % the region are ignored. This is useful if the initial image is being
3851 % created from scratch, or if the existing pixel values are to be
3852 % completely replaced without need to refer to their pre-existing values.
3853 % The application is free to read and write the pixel buffer returned by
3854 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3855 % initialize the pixel array values. Initializing pixel array values is the
3856 % application's responsibility.
3858 % Performance is maximized if the selected region is part of one row, or
3859 % one or more full rows, since then there is opportunity to access the
3860 % pixels in-place (without a copy) if the image is in memory, or in a
3861 % memory-mapped file. The returned pointer must *never* be deallocated
3864 % Pixels accessed via the returned pointer represent a simple array of type
3865 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3866 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3867 % obtain the meta-content (of type void) corresponding to the region.
3868 % Once the Quantum (and/or Quantum) array has been updated, the
3869 % changes must be saved back to the underlying image using
3870 % SyncAuthenticPixels() or they may be lost.
3872 % The format of the QueueAuthenticPixels() method is:
3874 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3875 % const ssize_t y,const size_t columns,const size_t rows,
3876 % ExceptionInfo *exception)
3878 % A description of each parameter follows:
3880 % o image: the image.
3882 % o x,y,columns,rows: These values define the perimeter of a region of
3885 % o exception: return any errors or warnings in this structure.
3888 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3889 const ssize_t y,const size_t columns,const size_t rows,
3890 ExceptionInfo *exception)
3893 *restrict cache_info;
3896 id = GetOpenMPThreadId();
3901 assert(image != (Image *) NULL);
3902 assert(image->signature == MagickSignature);
3903 assert(image->cache != (Cache) NULL);
3904 cache_info=(CacheInfo *) image->cache;
3905 assert(cache_info->signature == MagickSignature);
3906 if (cache_info->methods.queue_authentic_pixels_handler !=
3907 (QueueAuthenticPixelsHandler) NULL)
3909 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3910 columns,rows,exception);
3913 assert(id < (int) cache_info->number_threads);
3914 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3915 cache_info->nexus_info[id],exception);
3920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3924 + 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 %
3928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3930 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3933 % The format of the ReadPixelCacheMetacontent() method is:
3935 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
3936 % NexusInfo *nexus_info,ExceptionInfo *exception)
3938 % A description of each parameter follows:
3940 % o cache_info: the pixel cache.
3942 % o nexus_info: the cache nexus to read the metacontent.
3944 % o exception: return any errors or warnings in this structure.
3948 static inline MagickOffsetType ReadPixelCacheRegion(
3949 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3950 const MagickSizeType length,unsigned char *restrict buffer)
3952 register MagickOffsetType
3958 #if !defined(MAGICKCORE_HAVE_PREAD)
3959 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3960 return((MagickOffsetType) -1);
3963 for (i=0; i < (MagickOffsetType) length; i+=count)
3965 #if !defined(MAGICKCORE_HAVE_PREAD)
3966 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3967 (MagickSizeType) SSIZE_MAX));
3969 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3970 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3982 static MagickBooleanType ReadPixelCacheMetacontent(
3983 CacheInfo *restrict cache_info,NexusInfo *restrict nexus_info,
3984 ExceptionInfo *exception)
3997 register unsigned char
4003 if (cache_info->metacontent_extent == 0)
4004 return(MagickFalse);
4005 if (nexus_info->authentic_pixel_cache != MagickFalse)
4007 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4008 nexus_info->region.x;
4009 length=(MagickSizeType) nexus_info->region.width*
4010 cache_info->metacontent_extent;
4011 extent=length*nexus_info->region.height;
4012 rows=nexus_info->region.height;
4014 q=(unsigned char *) nexus_info->metacontent;
4015 switch (cache_info->type)
4020 register unsigned char
4024 Read meta-content from memory.
4026 if ((cache_info->columns == nexus_info->region.width) &&
4027 (extent == (MagickSizeType) ((size_t) extent)))
4032 p=(unsigned char *) cache_info->metacontent+offset*
4033 cache_info->metacontent_extent;
4034 for (y=0; y < (ssize_t) rows; y++)
4036 (void) memcpy(q,p,(size_t) length);
4037 p+=cache_info->metacontent_extent*cache_info->columns;
4038 q+=cache_info->metacontent_extent*nexus_info->region.width;
4045 Read meta content from disk.
4047 LockSemaphoreInfo(cache_info->file_semaphore);
4048 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4050 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4051 cache_info->cache_filename);
4052 UnlockSemaphoreInfo(cache_info->file_semaphore);
4053 return(MagickFalse);
4055 if ((cache_info->columns == nexus_info->region.width) &&
4056 (extent <= MagickMaxBufferExtent))
4061 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4062 for (y=0; y < (ssize_t) rows; y++)
4064 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4065 cache_info->number_channels*sizeof(Quantum)+offset*
4066 cache_info->metacontent_extent,length,(unsigned char *) q);
4067 if (count != (MagickOffsetType) length)
4069 offset+=cache_info->columns;
4070 q+=cache_info->metacontent_extent*nexus_info->region.width;
4072 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4073 (void) ClosePixelCacheOnDisk(cache_info);
4074 UnlockSemaphoreInfo(cache_info->file_semaphore);
4077 case DistributedCache:
4083 Read metacontent from distributed cache.
4085 LockSemaphoreInfo(cache_info->file_semaphore);
4086 region=nexus_info->region;
4087 if ((cache_info->columns != nexus_info->region.width) ||
4088 (extent > MagickMaxBufferExtent))
4095 for (y=0; y < (ssize_t) rows; y++)
4097 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4098 cache_info->server_info,®ion,length,(unsigned char *) q);
4099 if (count != (MagickOffsetType) length)
4101 q+=cache_info->metacontent_extent*nexus_info->region.width;
4104 UnlockSemaphoreInfo(cache_info->file_semaphore);
4110 if (y < (ssize_t) rows)
4112 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4113 cache_info->cache_filename);
4114 return(MagickFalse);
4116 if ((cache_info->debug != MagickFalse) &&
4117 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4118 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4119 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4120 nexus_info->region.width,(double) nexus_info->region.height,(double)
4121 nexus_info->region.x,(double) nexus_info->region.y);
4126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4130 + R e a d P i x e l C a c h e P i x e l s %
4134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4136 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4139 % The format of the ReadPixelCachePixels() method is:
4141 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4142 % NexusInfo *nexus_info,ExceptionInfo *exception)
4144 % A description of each parameter follows:
4146 % o cache_info: the pixel cache.
4148 % o nexus_info: the cache nexus to read the pixels.
4150 % o exception: return any errors or warnings in this structure.
4153 static MagickBooleanType ReadPixelCachePixels(CacheInfo *restrict cache_info,
4154 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4173 if (nexus_info->authentic_pixel_cache != MagickFalse)
4175 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4176 nexus_info->region.x;
4177 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4179 extent=length*nexus_info->region.height;
4180 rows=nexus_info->region.height;
4182 q=nexus_info->pixels;
4183 switch (cache_info->type)
4192 Read pixels from memory.
4194 if ((cache_info->columns == nexus_info->region.width) &&
4195 (extent == (MagickSizeType) ((size_t) extent)))
4200 p=cache_info->pixels+offset*cache_info->number_channels;
4201 for (y=0; y < (ssize_t) rows; y++)
4203 (void) memcpy(q,p,(size_t) length);
4204 p+=cache_info->number_channels*cache_info->columns;
4205 q+=cache_info->number_channels*nexus_info->region.width;
4212 Read pixels from disk.
4214 LockSemaphoreInfo(cache_info->file_semaphore);
4215 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4217 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4218 cache_info->cache_filename);
4219 UnlockSemaphoreInfo(cache_info->file_semaphore);
4220 return(MagickFalse);
4222 if ((cache_info->columns == nexus_info->region.width) &&
4223 (extent <= MagickMaxBufferExtent))
4228 for (y=0; y < (ssize_t) rows; y++)
4230 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4231 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4232 if (count != (MagickOffsetType) length)
4234 offset+=cache_info->columns;
4235 q+=cache_info->number_channels*nexus_info->region.width;
4237 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4238 (void) ClosePixelCacheOnDisk(cache_info);
4239 UnlockSemaphoreInfo(cache_info->file_semaphore);
4242 case DistributedCache:
4248 Read pixels from distributed cache.
4250 LockSemaphoreInfo(cache_info->file_semaphore);
4251 region=nexus_info->region;
4252 if ((cache_info->columns != nexus_info->region.width) ||
4253 (extent > MagickMaxBufferExtent))
4260 for (y=0; y < (ssize_t) rows; y++)
4262 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4263 cache_info->server_info,®ion,length,(unsigned char *) q);
4264 if (count != (MagickOffsetType) length)
4266 q+=cache_info->number_channels*nexus_info->region.width;
4269 UnlockSemaphoreInfo(cache_info->file_semaphore);
4275 if (y < (ssize_t) rows)
4277 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4278 cache_info->cache_filename);
4279 return(MagickFalse);
4281 if ((cache_info->debug != MagickFalse) &&
4282 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4283 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4284 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4285 nexus_info->region.width,(double) nexus_info->region.height,(double)
4286 nexus_info->region.x,(double) nexus_info->region.y);
4291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4295 + R e f e r e n c e P i x e l C a c h e %
4299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4301 % ReferencePixelCache() increments the reference count associated with the
4302 % pixel cache returning a pointer to the cache.
4304 % The format of the ReferencePixelCache method is:
4306 % Cache ReferencePixelCache(Cache cache_info)
4308 % A description of each parameter follows:
4310 % o cache_info: the pixel cache.
4313 MagickPrivate Cache ReferencePixelCache(Cache cache)
4316 *restrict cache_info;
4318 assert(cache != (Cache *) NULL);
4319 cache_info=(CacheInfo *) cache;
4320 assert(cache_info->signature == MagickSignature);
4321 LockSemaphoreInfo(cache_info->semaphore);
4322 cache_info->reference_count++;
4323 UnlockSemaphoreInfo(cache_info->semaphore);
4328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4332 + S e t P i x e l C a c h e M e t h o d s %
4336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4338 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4340 % The format of the SetPixelCacheMethods() method is:
4342 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4344 % A description of each parameter follows:
4346 % o cache: the pixel cache.
4348 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4351 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4354 *restrict cache_info;
4356 GetOneAuthenticPixelFromHandler
4357 get_one_authentic_pixel_from_handler;
4359 GetOneVirtualPixelFromHandler
4360 get_one_virtual_pixel_from_handler;
4363 Set cache pixel methods.
4365 assert(cache != (Cache) NULL);
4366 assert(cache_methods != (CacheMethods *) NULL);
4367 cache_info=(CacheInfo *) cache;
4368 assert(cache_info->signature == MagickSignature);
4369 if (cache_info->debug != MagickFalse)
4370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4371 cache_info->filename);
4372 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4373 cache_info->methods.get_virtual_pixel_handler=
4374 cache_methods->get_virtual_pixel_handler;
4375 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4376 cache_info->methods.destroy_pixel_handler=
4377 cache_methods->destroy_pixel_handler;
4378 if (cache_methods->get_virtual_metacontent_from_handler !=
4379 (GetVirtualMetacontentFromHandler) NULL)
4380 cache_info->methods.get_virtual_metacontent_from_handler=
4381 cache_methods->get_virtual_metacontent_from_handler;
4382 if (cache_methods->get_authentic_pixels_handler !=
4383 (GetAuthenticPixelsHandler) NULL)
4384 cache_info->methods.get_authentic_pixels_handler=
4385 cache_methods->get_authentic_pixels_handler;
4386 if (cache_methods->queue_authentic_pixels_handler !=
4387 (QueueAuthenticPixelsHandler) NULL)
4388 cache_info->methods.queue_authentic_pixels_handler=
4389 cache_methods->queue_authentic_pixels_handler;
4390 if (cache_methods->sync_authentic_pixels_handler !=
4391 (SyncAuthenticPixelsHandler) NULL)
4392 cache_info->methods.sync_authentic_pixels_handler=
4393 cache_methods->sync_authentic_pixels_handler;
4394 if (cache_methods->get_authentic_pixels_from_handler !=
4395 (GetAuthenticPixelsFromHandler) NULL)
4396 cache_info->methods.get_authentic_pixels_from_handler=
4397 cache_methods->get_authentic_pixels_from_handler;
4398 if (cache_methods->get_authentic_metacontent_from_handler !=
4399 (GetAuthenticMetacontentFromHandler) NULL)
4400 cache_info->methods.get_authentic_metacontent_from_handler=
4401 cache_methods->get_authentic_metacontent_from_handler;
4402 get_one_virtual_pixel_from_handler=
4403 cache_info->methods.get_one_virtual_pixel_from_handler;
4404 if (get_one_virtual_pixel_from_handler !=
4405 (GetOneVirtualPixelFromHandler) NULL)
4406 cache_info->methods.get_one_virtual_pixel_from_handler=
4407 cache_methods->get_one_virtual_pixel_from_handler;
4408 get_one_authentic_pixel_from_handler=
4409 cache_methods->get_one_authentic_pixel_from_handler;
4410 if (get_one_authentic_pixel_from_handler !=
4411 (GetOneAuthenticPixelFromHandler) NULL)
4412 cache_info->methods.get_one_authentic_pixel_from_handler=
4413 cache_methods->get_one_authentic_pixel_from_handler;
4417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4421 + S e t P i x e l C a c h e N e x u s P i x e l s %
4425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4427 % SetPixelCacheNexusPixels() defines the region of the cache for the
4428 % specified cache nexus.
4430 % The format of the SetPixelCacheNexusPixels() method is:
4432 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4433 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4434 % ExceptionInfo *exception)
4436 % A description of each parameter follows:
4438 % o cache_info: the pixel cache.
4440 % o mode: ReadMode, WriteMode, or IOMode.
4442 % o region: A pointer to the RectangleInfo structure that defines the
4443 % region of this particular cache nexus.
4445 % o nexus_info: the cache nexus to set.
4447 % o exception: return any errors or warnings in this structure.
4451 static inline MagickBooleanType AcquireCacheNexusPixels(
4452 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4453 ExceptionInfo *exception)
4455 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4456 return(MagickFalse);
4457 nexus_info->mapped=MagickFalse;
4458 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4459 (size_t) nexus_info->length));
4460 if (nexus_info->cache == (Quantum *) NULL)
4462 nexus_info->mapped=MagickTrue;
4463 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4464 nexus_info->length);
4466 if (nexus_info->cache == (Quantum *) NULL)
4468 (void) ThrowMagickException(exception,GetMagickModule(),
4469 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4470 cache_info->filename);
4471 return(MagickFalse);
4476 static inline MagickBooleanType IsPixelCacheAuthentic(
4477 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4486 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4488 if (cache_info->type == PingCache)
4490 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4491 nexus_info->region.x;
4492 status=nexus_info->pixels == (cache_info->pixels+offset*
4493 cache_info->number_channels) ? MagickTrue : MagickFalse;
4497 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4500 if (mode == ReadMode)
4502 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4505 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4508 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4509 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4510 ExceptionInfo *exception)
4519 assert(cache_info != (const CacheInfo *) NULL);
4520 assert(cache_info->signature == MagickSignature);
4521 if (cache_info->type == UndefinedCache)
4522 return((Quantum *) NULL);
4523 nexus_info->region=(*region);
4524 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4530 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4531 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4532 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4533 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4534 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4535 ((nexus_info->region.width == cache_info->columns) ||
4536 ((nexus_info->region.width % cache_info->columns) == 0)))))
4542 Pixels are accessed directly from memory.
4544 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4545 nexus_info->region.x;
4546 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4548 nexus_info->metacontent=(void *) NULL;
4549 if (cache_info->metacontent_extent != 0)
4550 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4551 offset*cache_info->metacontent_extent;
4552 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4553 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4555 return(nexus_info->pixels);
4559 Pixels are stored in a staging region until they are synced to the cache.
4561 number_pixels=(MagickSizeType) nexus_info->region.width*
4562 nexus_info->region.height;
4563 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4564 if (cache_info->metacontent_extent != 0)
4565 length+=number_pixels*cache_info->metacontent_extent;
4566 if (nexus_info->cache == (Quantum *) NULL)
4568 nexus_info->length=length;
4569 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4570 if (status == MagickFalse)
4572 nexus_info->length=0;
4573 return((Quantum *) NULL);
4577 if (nexus_info->length < length)
4579 RelinquishCacheNexusPixels(nexus_info);
4580 nexus_info->length=length;
4581 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4582 if (status == MagickFalse)
4584 nexus_info->length=0;
4585 return((Quantum *) NULL);
4588 nexus_info->pixels=nexus_info->cache;
4589 nexus_info->metacontent=(void *) NULL;
4590 if (cache_info->metacontent_extent != 0)
4591 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4592 cache_info->number_channels);
4593 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4594 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4596 return(nexus_info->pixels);
4600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4604 % 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 %
4608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4610 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4611 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4612 % access that is outside the boundaries of the image cache.
4614 % The format of the SetPixelCacheVirtualMethod() method is:
4616 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4617 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4619 % A description of each parameter follows:
4621 % o image: the image.
4623 % o virtual_pixel_method: choose the type of virtual pixel.
4625 % o exception: return any errors or warnings in this structure.
4629 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4630 ExceptionInfo *exception)
4633 *restrict cache_info;
4636 *restrict image_view;
4644 assert(image != (Image *) NULL);
4645 assert(image->signature == MagickSignature);
4646 if (image->debug != MagickFalse)
4647 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4648 assert(image->cache != (Cache) NULL);
4649 cache_info=(CacheInfo *) image->cache;
4650 assert(cache_info->signature == MagickSignature);
4651 image->alpha_trait=BlendPixelTrait;
4653 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4654 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4655 #pragma omp parallel for schedule(static,4) shared(status) \
4656 magick_threads(image,image,1,1)
4658 for (y=0; y < (ssize_t) image->rows; y++)
4666 if (status == MagickFalse)
4668 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4669 if (q == (Quantum *) NULL)
4674 for (x=0; x < (ssize_t) image->columns; x++)
4676 SetPixelAlpha(image,alpha,q);
4677 q+=GetPixelChannels(image);
4679 status=SyncCacheViewAuthenticPixels(image_view,exception);
4681 image_view=DestroyCacheView(image_view);
4685 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4686 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4689 *restrict cache_info;
4694 assert(image != (Image *) NULL);
4695 assert(image->signature == MagickSignature);
4696 if (image->debug != MagickFalse)
4697 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4698 assert(image->cache != (Cache) NULL);
4699 cache_info=(CacheInfo *) image->cache;
4700 assert(cache_info->signature == MagickSignature);
4701 method=cache_info->virtual_pixel_method;
4702 cache_info->virtual_pixel_method=virtual_pixel_method;
4703 if ((image->columns != 0) && (image->rows != 0))
4704 switch (virtual_pixel_method)
4706 case BackgroundVirtualPixelMethod:
4708 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4709 (image->alpha_trait == UndefinedPixelTrait))
4710 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4711 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4712 (IsGrayColorspace(image->colorspace) != MagickFalse))
4713 (void) SetImageColorspace(image,sRGBColorspace,exception);
4716 case TransparentVirtualPixelMethod:
4718 if (image->alpha_trait == UndefinedPixelTrait)
4719 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4733 + 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 %
4737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4739 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4740 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4741 % is synced, otherwise MagickFalse.
4743 % The format of the SyncAuthenticPixelCacheNexus() method is:
4745 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4746 % NexusInfo *nexus_info,ExceptionInfo *exception)
4748 % A description of each parameter follows:
4750 % o image: the image.
4752 % o nexus_info: the cache nexus to sync.
4754 % o exception: return any errors or warnings in this structure.
4757 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4758 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4761 *restrict cache_info;
4767 Transfer pixels to the cache.
4769 assert(image != (Image *) NULL);
4770 assert(image->signature == MagickSignature);
4771 if (image->cache == (Cache) NULL)
4772 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4773 cache_info=(CacheInfo *) image->cache;
4774 assert(cache_info->signature == MagickSignature);
4775 if (cache_info->type == UndefinedCache)
4776 return(MagickFalse);
4777 if (nexus_info->authentic_pixel_cache != MagickFalse)
4779 image->taint=MagickTrue;
4782 assert(cache_info->signature == MagickSignature);
4783 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4784 if ((cache_info->metacontent_extent != 0) &&
4785 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4786 return(MagickFalse);
4787 if (status != MagickFalse)
4788 image->taint=MagickTrue;
4793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4797 + S y n c A u t h e n t i c P i x e l C a c h e %
4801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4803 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4804 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4805 % otherwise MagickFalse.
4807 % The format of the SyncAuthenticPixelsCache() method is:
4809 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4810 % ExceptionInfo *exception)
4812 % A description of each parameter follows:
4814 % o image: the image.
4816 % o exception: return any errors or warnings in this structure.
4819 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4820 ExceptionInfo *exception)
4823 *restrict cache_info;
4826 id = GetOpenMPThreadId();
4831 assert(image != (Image *) NULL);
4832 assert(image->signature == MagickSignature);
4833 assert(image->cache != (Cache) NULL);
4834 cache_info=(CacheInfo *) image->cache;
4835 assert(cache_info->signature == MagickSignature);
4836 assert(id < (int) cache_info->number_threads);
4837 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4847 % S y n c A u t h e n t i c P i x e l s %
4851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4853 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4854 % The method returns MagickTrue if the pixel region is flushed, otherwise
4857 % The format of the SyncAuthenticPixels() method is:
4859 % MagickBooleanType SyncAuthenticPixels(Image *image,
4860 % ExceptionInfo *exception)
4862 % A description of each parameter follows:
4864 % o image: the image.
4866 % o exception: return any errors or warnings in this structure.
4869 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4870 ExceptionInfo *exception)
4873 *restrict cache_info;
4876 id = GetOpenMPThreadId();
4881 assert(image != (Image *) NULL);
4882 assert(image->signature == MagickSignature);
4883 assert(image->cache != (Cache) NULL);
4884 cache_info=(CacheInfo *) image->cache;
4885 assert(cache_info->signature == MagickSignature);
4886 if (cache_info->methods.sync_authentic_pixels_handler !=
4887 (SyncAuthenticPixelsHandler) NULL)
4889 status=cache_info->methods.sync_authentic_pixels_handler(image,
4893 assert(id < (int) cache_info->number_threads);
4894 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4904 + S y n c I m a g e P i x e l C a c h e %
4908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4910 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4911 % The method returns MagickTrue if the pixel region is flushed, otherwise
4914 % The format of the SyncImagePixelCache() method is:
4916 % MagickBooleanType SyncImagePixelCache(Image *image,
4917 % ExceptionInfo *exception)
4919 % A description of each parameter follows:
4921 % o image: the image.
4923 % o exception: return any errors or warnings in this structure.
4926 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4927 ExceptionInfo *exception)
4930 *restrict cache_info;
4932 assert(image != (Image *) NULL);
4933 assert(exception != (ExceptionInfo *) NULL);
4934 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4935 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4943 + 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 %
4947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4949 % WritePixelCacheMetacontent() writes the meta-content to the specified region
4950 % of the pixel cache.
4952 % The format of the WritePixelCacheMetacontent() method is:
4954 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4955 % NexusInfo *nexus_info,ExceptionInfo *exception)
4957 % A description of each parameter follows:
4959 % o cache_info: the pixel cache.
4961 % o nexus_info: the cache nexus to write the meta-content.
4963 % o exception: return any errors or warnings in this structure.
4966 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4967 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
4977 register const unsigned char
4986 if (cache_info->metacontent_extent == 0)
4987 return(MagickFalse);
4988 if (nexus_info->authentic_pixel_cache != MagickFalse)
4990 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4991 nexus_info->region.x;
4992 length=(MagickSizeType) nexus_info->region.width*
4993 cache_info->metacontent_extent;
4994 extent=(MagickSizeType) length*nexus_info->region.height;
4995 rows=nexus_info->region.height;
4997 p=(unsigned char *) nexus_info->metacontent;
4998 switch (cache_info->type)
5003 register unsigned char
5007 Write associated pixels to memory.
5009 if ((cache_info->columns == nexus_info->region.width) &&
5010 (extent == (MagickSizeType) ((size_t) extent)))
5015 q=(unsigned char *) cache_info->metacontent+offset*
5016 cache_info->metacontent_extent;
5017 for (y=0; y < (ssize_t) rows; y++)
5019 (void) memcpy(q,p,(size_t) length);
5020 p+=nexus_info->region.width*cache_info->metacontent_extent;
5021 q+=cache_info->columns*cache_info->metacontent_extent;
5028 Write associated pixels to disk.
5030 LockSemaphoreInfo(cache_info->file_semaphore);
5031 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5033 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5034 cache_info->cache_filename);
5035 UnlockSemaphoreInfo(cache_info->file_semaphore);
5036 return(MagickFalse);
5038 if ((cache_info->columns == nexus_info->region.width) &&
5039 (extent <= MagickMaxBufferExtent))
5044 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5045 for (y=0; y < (ssize_t) rows; y++)
5047 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5048 cache_info->number_channels*sizeof(Quantum)+offset*
5049 cache_info->metacontent_extent,length,(const unsigned char *) p);
5050 if (count != (MagickOffsetType) length)
5052 p+=cache_info->metacontent_extent*nexus_info->region.width;
5053 offset+=cache_info->columns;
5055 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5056 (void) ClosePixelCacheOnDisk(cache_info);
5057 UnlockSemaphoreInfo(cache_info->file_semaphore);
5060 case DistributedCache:
5066 Write metacontent to distributed cache.
5068 LockSemaphoreInfo(cache_info->file_semaphore);
5069 region=nexus_info->region;
5070 if ((cache_info->columns != nexus_info->region.width) ||
5071 (extent > MagickMaxBufferExtent))
5078 for (y=0; y < (ssize_t) rows; y++)
5080 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5081 cache_info->server_info,®ion,length,(const unsigned char *) p);
5082 if (count != (MagickOffsetType) length)
5084 p+=cache_info->metacontent_extent*nexus_info->region.width;
5087 UnlockSemaphoreInfo(cache_info->file_semaphore);
5093 if (y < (ssize_t) rows)
5095 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5096 cache_info->cache_filename);
5097 return(MagickFalse);
5099 if ((cache_info->debug != MagickFalse) &&
5100 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5101 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5102 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5103 nexus_info->region.width,(double) nexus_info->region.height,(double)
5104 nexus_info->region.x,(double) nexus_info->region.y);
5109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5113 + W r i t e C a c h e P i x e l s %
5117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5119 % WritePixelCachePixels() writes image pixels to the specified region of the
5122 % The format of the WritePixelCachePixels() method is:
5124 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5125 % NexusInfo *nexus_info,ExceptionInfo *exception)
5127 % A description of each parameter follows:
5129 % o cache_info: the pixel cache.
5131 % o nexus_info: the cache nexus to write the pixels.
5133 % o exception: return any errors or warnings in this structure.
5136 static MagickBooleanType WritePixelCachePixels(CacheInfo *restrict cache_info,
5137 NexusInfo *restrict nexus_info,ExceptionInfo *exception)
5147 register const Quantum
5156 if (nexus_info->authentic_pixel_cache != MagickFalse)
5158 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5159 nexus_info->region.x;
5160 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5162 extent=length*nexus_info->region.height;
5163 rows=nexus_info->region.height;
5165 p=nexus_info->pixels;
5166 switch (cache_info->type)
5175 Write pixels to memory.
5177 if ((cache_info->columns == nexus_info->region.width) &&
5178 (extent == (MagickSizeType) ((size_t) extent)))
5183 q=cache_info->pixels+offset*cache_info->number_channels;
5184 for (y=0; y < (ssize_t) rows; y++)
5186 (void) memcpy(q,p,(size_t) length);
5187 p+=cache_info->number_channels*nexus_info->region.width;
5188 q+=cache_info->columns*cache_info->number_channels;
5195 Write pixels to disk.
5197 LockSemaphoreInfo(cache_info->file_semaphore);
5198 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5200 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5201 cache_info->cache_filename);
5202 UnlockSemaphoreInfo(cache_info->file_semaphore);
5203 return(MagickFalse);
5205 if ((cache_info->columns == nexus_info->region.width) &&
5206 (extent <= MagickMaxBufferExtent))
5211 for (y=0; y < (ssize_t) rows; y++)
5213 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5214 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5216 if (count != (MagickOffsetType) length)
5218 p+=cache_info->number_channels*nexus_info->region.width;
5219 offset+=cache_info->columns;
5221 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5222 (void) ClosePixelCacheOnDisk(cache_info);
5223 UnlockSemaphoreInfo(cache_info->file_semaphore);
5226 case DistributedCache:
5232 Write pixels to distributed cache.
5234 LockSemaphoreInfo(cache_info->file_semaphore);
5235 region=nexus_info->region;
5236 if ((cache_info->columns != nexus_info->region.width) ||
5237 (extent > MagickMaxBufferExtent))
5244 for (y=0; y < (ssize_t) rows; y++)
5246 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5247 cache_info->server_info,®ion,length,(const unsigned char *) p);
5248 if (count != (MagickOffsetType) length)
5250 p+=cache_info->number_channels*nexus_info->region.width;
5253 UnlockSemaphoreInfo(cache_info->file_semaphore);
5259 if (y < (ssize_t) rows)
5261 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5262 cache_info->cache_filename);
5263 return(MagickFalse);
5265 if ((cache_info->debug != MagickFalse) &&
5266 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5267 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5268 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5269 nexus_info->region.width,(double) nexus_info->region.height,(double)
5270 nexus_info->region.x,(double) nexus_info->region.y);