2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/distribute-cache-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/log.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/memory-private.h"
60 #include "MagickCore/nt-base-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
100 #if defined(__cplusplus) || defined(c_plusplus)
105 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
109 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
110 const ssize_t,const size_t,const size_t,ExceptionInfo *),
111 *GetVirtualPixelsCache(const Image *);
114 *GetVirtualMetacontentFromCache(const Image *);
116 static MagickBooleanType
117 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
120 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
122 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
123 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
124 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
125 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
129 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
130 const size_t,ExceptionInfo *),
131 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
132 const size_t,ExceptionInfo *),
133 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
134 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
136 #if defined(__cplusplus) || defined(c_plusplus)
143 static volatile MagickBooleanType
144 instantiate_cache = MagickFalse;
147 *cache_semaphore = (SemaphoreInfo *) NULL;
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 + A c q u i r e P i x e l C a c h e %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 % AcquirePixelCache() acquires a pixel cache.
162 % The format of the AcquirePixelCache() method is:
164 % Cache AcquirePixelCache(const size_t number_threads)
166 % A description of each parameter follows:
168 % o number_threads: the number of nexus threads.
171 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
179 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
180 if (cache_info == (CacheInfo *) NULL)
181 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
182 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
183 cache_info->type=UndefinedCache;
184 cache_info->mode=IOMode;
185 cache_info->colorspace=sRGBColorspace;
186 cache_info->file=(-1);
187 cache_info->id=GetMagickThreadId();
188 cache_info->number_threads=number_threads;
189 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
190 cache_info->number_threads=GetOpenMPMaximumThreads();
191 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
192 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
193 if (cache_info->number_threads == 0)
194 cache_info->number_threads=1;
195 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
196 if (cache_info->nexus_info == (NexusInfo **) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
199 if (synchronize != (const char *) NULL)
201 cache_info->synchronize=IsStringTrue(synchronize);
202 synchronize=DestroyString(synchronize);
204 cache_info->semaphore=AllocateSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->file_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 return((Cache ) cache_info);
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % A c q u i r e P i x e l C a c h e N e x u s %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
225 % The format of the AcquirePixelCacheNexus method is:
227 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
229 % A description of each parameter follows:
231 % o number_threads: the number of nexus threads.
234 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
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)
293 assert(image != (const Image *) NULL);
294 assert(image->signature == MagickSignature);
295 assert(exception != (ExceptionInfo *) NULL);
296 assert(exception->signature == MagickSignature);
297 assert(image->cache != (Cache) NULL);
298 cache_info=(CacheInfo *) image->cache;
299 assert(cache_info->signature == MagickSignature);
301 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
302 return((const void *) NULL);
303 *length=cache_info->length;
304 return((const void *) cache_info->pixels);
308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 + C a c h e C o m p o n e n t G e n e s i s %
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 % CacheComponentGenesis() instantiates the cache component.
320 % The format of the CacheComponentGenesis method is:
322 % MagickBooleanType CacheComponentGenesis(void)
325 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
327 AcquireSemaphoreInfo(&cache_semaphore);
332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 + C a c h e C o m p o n e n t T e r m i n u s %
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 % CacheComponentTerminus() destroys the cache component.
344 % The format of the CacheComponentTerminus() method is:
346 % CacheComponentTerminus(void)
349 MagickPrivate void CacheComponentTerminus(void)
351 if (cache_semaphore == (SemaphoreInfo *) NULL)
352 AcquireSemaphoreInfo(&cache_semaphore);
353 LockSemaphoreInfo(cache_semaphore);
354 instantiate_cache=MagickFalse;
355 UnlockSemaphoreInfo(cache_semaphore);
356 DestroySemaphoreInfo(&cache_semaphore);
360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 + C l o n e P i x e l C a c h e %
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 % ClonePixelCache() clones a pixel cache.
372 % The format of the ClonePixelCache() method is:
374 % Cache ClonePixelCache(const Cache cache)
376 % A description of each parameter follows:
378 % o cache: the pixel cache.
381 MagickPrivate Cache ClonePixelCache(const Cache cache)
389 assert(cache != NULL);
390 cache_info=(const CacheInfo *) cache;
391 assert(cache_info->signature == MagickSignature);
392 if (cache_info->debug != MagickFalse)
393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
394 cache_info->filename);
395 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
396 if (clone_info == (Cache) NULL)
397 return((Cache) NULL);
398 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
399 return((Cache ) clone_info);
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 + C l o n e P i x e l C a c h e M e t h o d s %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
416 % The format of the ClonePixelCacheMethods() method is:
418 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
420 % A description of each parameter follows:
422 % o clone: Specifies a pointer to a Cache structure.
424 % o cache: the pixel cache.
427 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
433 assert(clone != (Cache) NULL);
434 source_info=(CacheInfo *) clone;
435 assert(source_info->signature == MagickSignature);
436 if (source_info->debug != MagickFalse)
437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
438 source_info->filename);
439 assert(cache != (Cache) NULL);
440 cache_info=(CacheInfo *) cache;
441 assert(cache_info->signature == MagickSignature);
442 source_info->methods=cache_info->methods;
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450 + C l o n e P i x e l C a c h e R e p o s i t o r y %
454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
455 % ClonePixelCacheRepository() clones the source pixel cache to the destination
458 % The format of the ClonePixelCacheRepository() method is:
460 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
461 % CacheInfo *source_info,ExceptionInfo *exception)
463 % A description of each parameter follows:
465 % o cache_info: the pixel cache.
467 % o source_info: the source pixel cache.
469 % o exception: return any errors or warnings in this structure.
473 static inline MagickSizeType MagickMin(const MagickSizeType x,
474 const MagickSizeType y)
481 static MagickBooleanType ClonePixelCacheRepository(CacheInfo *clone_info,
482 CacheInfo *cache_info,ExceptionInfo *exception)
484 #define MaxCacheThreads 2
485 #define cache_threads(source,destination,chunk) \
486 num_threads((chunk) < (16*GetMagickResourceLimit(ThreadResource)) ? 1 : \
487 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
488 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
504 assert(cache_info != (CacheInfo *) NULL);
505 assert(clone_info != (CacheInfo *) NULL);
506 assert(exception != (ExceptionInfo *) NULL);
507 if (cache_info->type == PingCache)
509 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
510 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
511 ((clone_info->type == MemoryCache) || (clone_info->type == MapCache)) &&
512 (cache_info->columns == clone_info->columns) &&
513 (cache_info->rows == clone_info->rows) &&
514 (cache_info->number_channels == clone_info->number_channels) &&
515 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
516 (cache_info->metacontent_extent == clone_info->metacontent_extent))
519 Identical pixel cache morphology.
521 (void) memcpy(clone_info->pixels,cache_info->pixels,cache_info->columns*
522 cache_info->number_channels*cache_info->rows*
523 sizeof(*cache_info->pixels));
524 if (cache_info->metacontent_extent != 0)
525 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
526 cache_info->columns*cache_info->rows*clone_info->metacontent_extent*
527 sizeof(cache_info->metacontent));
531 Mismatched pixel cache morphology.
533 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
534 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
535 if ((cache_nexus == (NexusInfo **) NULL) ||
536 (clone_nexus == (NexusInfo **) NULL))
537 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
538 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
539 optimize=(cache_info->number_channels == clone_info->number_channels) &&
540 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
541 MagickTrue : MagickFalse;
542 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
543 clone_info->columns*clone_info->number_channels);
545 #if defined(MAGICKCORE_OPENMP_SUPPORT)
546 #pragma omp parallel for schedule(static,4) shared(status) \
547 cache_threads(cache_info,clone_info,cache_info->rows)
549 for (y=0; y < (ssize_t) cache_info->rows; y++)
552 id = GetOpenMPThreadId();
563 if (status == MagickFalse)
565 if (y >= (ssize_t) clone_info->rows)
567 region.width=cache_info->columns;
571 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,cache_nexus[id],
573 if (pixels == (Quantum *) NULL)
575 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
576 if (status == MagickFalse)
578 region.width=clone_info->columns;
579 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
580 clone_nexus[id],exception);
581 if (pixels == (Quantum *) NULL)
583 if (optimize != MagickFalse)
584 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
588 register const Quantum
595 Mismatched pixel channel map.
597 p=cache_nexus[id]->pixels;
598 q=clone_nexus[id]->pixels;
599 for (x=0; x < (ssize_t) cache_info->columns; x++)
604 if (x == (ssize_t) clone_info->columns)
606 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
614 channel=clone_info->channel_map[i].channel;
615 traits=cache_info->channel_map[channel].traits;
616 if (traits != UndefinedPixelTrait)
617 (void) memcpy(q,p+cache_info->channel_map[channel].offset,
621 p+=cache_info->number_channels;
624 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
626 if ((cache_info->metacontent_extent != 0) &&
627 (clone_info->metacontent_extent != 0))
632 length=(size_t) MagickMin(cache_info->metacontent_extent,
633 clone_info->metacontent_extent);
634 #if defined(MAGICKCORE_OPENMP_SUPPORT)
635 #pragma omp parallel for schedule(static,4) shared(status) \
636 cache_threads(cache_info,clone_info,cache_info->rows)
638 for (y=0; y < (ssize_t) cache_info->rows; y++)
641 id = GetOpenMPThreadId();
649 if (status == MagickFalse)
651 if (y >= (ssize_t) clone_info->rows)
653 region.width=cache_info->columns;
657 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
658 cache_nexus[id],exception);
659 if (pixels == (Quantum *) NULL)
661 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
662 if (status == MagickFalse)
664 region.width=clone_info->columns;
665 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
666 clone_nexus[id],exception);
667 if (pixels == (Quantum *) NULL)
669 (void) memcpy(clone_nexus[id]->metacontent,cache_nexus[id]->metacontent,
670 length*sizeof(cache_nexus[id]->metacontent));
671 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
674 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
675 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
676 if (cache_info->debug != MagickFalse)
679 message[MaxTextExtent];
681 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
682 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
683 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
684 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
694 + D e s t r o y I m a g e P i x e l C a c h e %
698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
702 % The format of the DestroyImagePixelCache() method is:
704 % void DestroyImagePixelCache(Image *image)
706 % A description of each parameter follows:
708 % o image: the image.
711 static void DestroyImagePixelCache(Image *image)
713 assert(image != (Image *) NULL);
714 assert(image->signature == MagickSignature);
715 if (image->debug != MagickFalse)
716 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
717 if (image->cache == (void *) NULL)
719 image->cache=DestroyPixelCache(image->cache);
723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727 + D e s t r o y I m a g e P i x e l s %
731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733 % DestroyImagePixels() deallocates memory associated with the pixel cache.
735 % The format of the DestroyImagePixels() method is:
737 % void DestroyImagePixels(Image *image)
739 % A description of each parameter follows:
741 % o image: the image.
744 MagickExport void DestroyImagePixels(Image *image)
749 assert(image != (const Image *) NULL);
750 assert(image->signature == MagickSignature);
751 if (image->debug != MagickFalse)
752 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
753 assert(image->cache != (Cache) NULL);
754 cache_info=(CacheInfo *) image->cache;
755 assert(cache_info->signature == MagickSignature);
756 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
758 cache_info->methods.destroy_pixel_handler(image);
761 image->cache=DestroyPixelCache(image->cache);
765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769 + D e s t r o y P i x e l C a c h e %
773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
775 % DestroyPixelCache() deallocates memory associated with the pixel cache.
777 % The format of the DestroyPixelCache() method is:
779 % Cache DestroyPixelCache(Cache cache)
781 % A description of each parameter follows:
783 % o cache: the pixel cache.
787 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
793 if (cache_info->file != -1)
795 status=close(cache_info->file);
796 cache_info->file=(-1);
797 RelinquishMagickResource(FileResource,1);
799 return(status == -1 ? MagickFalse : MagickTrue);
802 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
804 switch (cache_info->type)
808 if (cache_info->mapped == MagickFalse)
809 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
812 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
813 (size_t) cache_info->length);
814 RelinquishMagickResource(MemoryResource,cache_info->length);
819 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
821 if (cache_info->mode != ReadMode)
822 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
823 *cache_info->cache_filename='\0';
824 RelinquishMagickResource(MapResource,cache_info->length);
828 if (cache_info->file != -1)
829 (void) ClosePixelCacheOnDisk(cache_info);
830 if (cache_info->mode != ReadMode)
831 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
832 *cache_info->cache_filename='\0';
833 RelinquishMagickResource(DiskResource,cache_info->length);
836 case DistributedCache:
838 *cache_info->cache_filename='\0';
839 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
840 cache_info->server_info);
846 cache_info->type=UndefinedCache;
847 cache_info->mapped=MagickFalse;
848 cache_info->metacontent=(void *) NULL;
851 MagickPrivate Cache DestroyPixelCache(Cache cache)
856 assert(cache != (Cache) NULL);
857 cache_info=(CacheInfo *) cache;
858 assert(cache_info->signature == MagickSignature);
859 if (cache_info->debug != MagickFalse)
860 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
861 cache_info->filename);
862 LockSemaphoreInfo(cache_info->semaphore);
863 cache_info->reference_count--;
864 if (cache_info->reference_count != 0)
866 UnlockSemaphoreInfo(cache_info->semaphore);
867 return((Cache) NULL);
869 UnlockSemaphoreInfo(cache_info->semaphore);
870 if (cache_info->debug != MagickFalse)
873 message[MaxTextExtent];
875 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
876 cache_info->filename);
877 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
879 RelinquishPixelCachePixels(cache_info);
880 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
881 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
882 cache_info->server_info);
883 if (cache_info->nexus_info != (NexusInfo **) NULL)
884 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
885 cache_info->number_threads);
886 if (cache_info->random_info != (RandomInfo *) NULL)
887 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
888 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
889 DestroySemaphoreInfo(&cache_info->file_semaphore);
890 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
891 DestroySemaphoreInfo(&cache_info->semaphore);
892 cache_info->signature=(~MagickSignature);
893 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
903 + D e s t r o y P i x e l C a c h e N e x u s %
907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
911 % The format of the DestroyPixelCacheNexus() method is:
913 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
914 % const size_t number_threads)
916 % A description of each parameter follows:
918 % o nexus_info: the nexus to destroy.
920 % o number_threads: the number of nexus threads.
924 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
926 if (nexus_info->mapped == MagickFalse)
927 (void) RelinquishAlignedMemory(nexus_info->cache);
929 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
930 nexus_info->cache=(Quantum *) NULL;
931 nexus_info->pixels=(Quantum *) NULL;
932 nexus_info->metacontent=(void *) NULL;
933 nexus_info->length=0;
934 nexus_info->mapped=MagickFalse;
937 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
938 const size_t number_threads)
943 assert(nexus_info != (NexusInfo **) NULL);
944 for (i=0; i < (ssize_t) number_threads; i++)
946 if (nexus_info[i]->cache != (Quantum *) NULL)
947 RelinquishCacheNexusPixels(nexus_info[i]);
948 nexus_info[i]->signature=(~MagickSignature);
950 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
951 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
960 % G e t A u t h e n t i c M e t a c o n t e n t %
964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
967 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
968 % returned if the associated pixels are not available.
970 % The format of the GetAuthenticMetacontent() method is:
972 % void *GetAuthenticMetacontent(const Image *image)
974 % A description of each parameter follows:
976 % o image: the image.
979 MagickExport void *GetAuthenticMetacontent(const Image *image)
985 id = GetOpenMPThreadId();
987 assert(image != (const Image *) NULL);
988 assert(image->signature == MagickSignature);
989 assert(image->cache != (Cache) NULL);
990 cache_info=(CacheInfo *) image->cache;
991 assert(cache_info->signature == MagickSignature);
992 if (cache_info->methods.get_authentic_metacontent_from_handler !=
993 (GetAuthenticMetacontentFromHandler) NULL)
998 metacontent=cache_info->methods.
999 get_authentic_metacontent_from_handler(image);
1000 return(metacontent);
1002 assert(id < (int) cache_info->number_threads);
1003 return(cache_info->nexus_info[id]->metacontent);
1007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1011 + 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 %
1015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1017 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1018 % with the last call to QueueAuthenticPixelsCache() or
1019 % GetAuthenticPixelsCache().
1021 % The format of the GetAuthenticMetacontentFromCache() method is:
1023 % void *GetAuthenticMetacontentFromCache(const Image *image)
1025 % A description of each parameter follows:
1027 % o image: the image.
1030 static void *GetAuthenticMetacontentFromCache(const Image *image)
1036 id = GetOpenMPThreadId();
1038 assert(image != (const Image *) NULL);
1039 assert(image->signature == MagickSignature);
1040 assert(image->cache != (Cache) NULL);
1041 cache_info=(CacheInfo *) image->cache;
1042 assert(cache_info->signature == MagickSignature);
1043 assert(id < (int) cache_info->number_threads);
1044 return(cache_info->nexus_info[id]->metacontent);
1048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1052 + 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 %
1056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1058 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1059 % disk pixel cache as defined by the geometry parameters. A pointer to the
1060 % pixels is returned if the pixels are transferred, otherwise a NULL is
1063 % The format of the GetAuthenticPixelCacheNexus() method is:
1065 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1066 % const ssize_t y,const size_t columns,const size_t rows,
1067 % NexusInfo *nexus_info,ExceptionInfo *exception)
1069 % A description of each parameter follows:
1071 % o image: the image.
1073 % o x,y,columns,rows: These values define the perimeter of a region of
1076 % o nexus_info: the cache nexus to return.
1078 % o exception: return any errors or warnings in this structure.
1082 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1083 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1084 ExceptionInfo *exception)
1093 Transfer pixels from the cache.
1095 assert(image != (Image *) NULL);
1096 assert(image->signature == MagickSignature);
1097 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1098 nexus_info,exception);
1099 if (pixels == (Quantum *) NULL)
1100 return((Quantum *) NULL);
1101 cache_info=(CacheInfo *) image->cache;
1102 assert(cache_info->signature == MagickSignature);
1103 if (nexus_info->authentic_cache != MagickFalse)
1105 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1106 return((Quantum *) NULL);
1107 if (cache_info->metacontent_extent != 0)
1108 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1109 return((Quantum *) NULL);
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118 + 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 %
1122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1124 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1125 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1127 % The format of the GetAuthenticPixelsFromCache() method is:
1129 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1131 % A description of each parameter follows:
1133 % o image: the image.
1136 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1142 id = GetOpenMPThreadId();
1144 assert(image != (const Image *) NULL);
1145 assert(image->signature == MagickSignature);
1146 assert(image->cache != (Cache) NULL);
1147 cache_info=(CacheInfo *) image->cache;
1148 assert(cache_info->signature == MagickSignature);
1149 assert(id < (int) cache_info->number_threads);
1150 return(cache_info->nexus_info[id]->pixels);
1154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 % G e t A u t h e n t i c P i x e l Q u e u e %
1162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164 % GetAuthenticPixelQueue() returns the authentic pixels associated
1165 % corresponding with the last call to QueueAuthenticPixels() or
1166 % GetAuthenticPixels().
1168 % The format of the GetAuthenticPixelQueue() method is:
1170 % Quantum *GetAuthenticPixelQueue(const Image image)
1172 % A description of each parameter follows:
1174 % o image: the image.
1177 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1183 id = GetOpenMPThreadId();
1185 assert(image != (const Image *) NULL);
1186 assert(image->signature == MagickSignature);
1187 assert(image->cache != (Cache) NULL);
1188 cache_info=(CacheInfo *) image->cache;
1189 assert(cache_info->signature == MagickSignature);
1190 if (cache_info->methods.get_authentic_pixels_from_handler !=
1191 (GetAuthenticPixelsFromHandler) NULL)
1192 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1193 assert(id < (int) cache_info->number_threads);
1194 return(cache_info->nexus_info[id]->pixels);
1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202 % G e t A u t h e n t i c P i x e l s %
1205 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1208 % region is successfully accessed, a pointer to a Quantum array
1209 % representing the region is returned, otherwise NULL is returned.
1211 % The returned pointer may point to a temporary working copy of the pixels
1212 % or it may point to the original pixels in memory. Performance is maximized
1213 % if the selected region is part of one row, or one or more full rows, since
1214 % then there is opportunity to access the pixels in-place (without a copy)
1215 % if the image is in memory, or in a memory-mapped file. The returned pointer
1216 % must *never* be deallocated by the user.
1218 % Pixels accessed via the returned pointer represent a simple array of type
1219 % Quantum. If the image has corresponding metacontent,call
1220 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1221 % meta-content corresponding to the region. Once the Quantum array has
1222 % been updated, the changes must be saved back to the underlying image using
1223 % SyncAuthenticPixels() or they may be lost.
1225 % The format of the GetAuthenticPixels() method is:
1227 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1228 % const ssize_t y,const size_t columns,const size_t rows,
1229 % ExceptionInfo *exception)
1231 % A description of each parameter follows:
1233 % o image: the image.
1235 % o x,y,columns,rows: These values define the perimeter of a region of
1238 % o exception: return any errors or warnings in this structure.
1241 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1242 const ssize_t y,const size_t columns,const size_t rows,
1243 ExceptionInfo *exception)
1249 id = GetOpenMPThreadId();
1254 assert(image != (Image *) NULL);
1255 assert(image->signature == MagickSignature);
1256 assert(image->cache != (Cache) NULL);
1257 cache_info=(CacheInfo *) image->cache;
1258 assert(cache_info->signature == MagickSignature);
1259 if (cache_info->methods.get_authentic_pixels_handler !=
1260 (GetAuthenticPixelsHandler) NULL)
1262 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1266 assert(id < (int) cache_info->number_threads);
1267 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1268 cache_info->nexus_info[id],exception);
1273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1277 + G e t A u t h e n t i c P i x e l s C a c h e %
1281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1283 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1284 % as defined by the geometry parameters. A pointer to the pixels is returned
1285 % if the pixels are transferred, otherwise a NULL is returned.
1287 % The format of the GetAuthenticPixelsCache() method is:
1289 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1290 % const ssize_t y,const size_t columns,const size_t rows,
1291 % ExceptionInfo *exception)
1293 % A description of each parameter follows:
1295 % o image: the image.
1297 % o x,y,columns,rows: These values define the perimeter of a region of
1300 % o exception: return any errors or warnings in this structure.
1303 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1304 const ssize_t y,const size_t columns,const size_t rows,
1305 ExceptionInfo *exception)
1311 id = GetOpenMPThreadId();
1316 assert(image != (const Image *) NULL);
1317 assert(image->signature == MagickSignature);
1318 assert(image->cache != (Cache) NULL);
1319 cache_info=(CacheInfo *) image->cache;
1320 if (cache_info == (Cache) NULL)
1321 return((Quantum *) NULL);
1322 assert(cache_info->signature == MagickSignature);
1323 assert(id < (int) cache_info->number_threads);
1324 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1325 cache_info->nexus_info[id],exception);
1330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334 + G e t I m a g e E x t e n t %
1338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340 % GetImageExtent() returns the extent of the pixels associated corresponding
1341 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1343 % The format of the GetImageExtent() method is:
1345 % MagickSizeType GetImageExtent(const Image *image)
1347 % A description of each parameter follows:
1349 % o image: the image.
1352 MagickExport MagickSizeType GetImageExtent(const Image *image)
1358 id = GetOpenMPThreadId();
1360 assert(image != (Image *) NULL);
1361 assert(image->signature == MagickSignature);
1362 if (image->debug != MagickFalse)
1363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1364 assert(image->cache != (Cache) NULL);
1365 cache_info=(CacheInfo *) image->cache;
1366 assert(cache_info->signature == MagickSignature);
1367 assert(id < (int) cache_info->number_threads);
1368 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376 + G e t I m a g e P i x e l C a c h e %
1380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1382 % GetImagePixelCache() ensures that there is only a single reference to the
1383 % pixel cache to be modified, updating the provided cache pointer to point to
1384 % a clone of the original pixel cache if necessary.
1386 % The format of the GetImagePixelCache method is:
1388 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1389 % ExceptionInfo *exception)
1391 % A description of each parameter follows:
1393 % o image: the image.
1395 % o clone: any value other than MagickFalse clones the cache pixels.
1397 % o exception: return any errors or warnings in this structure.
1401 static inline MagickBooleanType ValidatePixelCacheMorphology(
1402 const Image *restrict image)
1405 *restrict cache_info;
1407 const PixelChannelMap
1412 Does the image match the pixel cache morphology?
1414 cache_info=(CacheInfo *) image->cache;
1415 p=image->channel_map;
1416 q=cache_info->channel_map;
1417 if ((image->storage_class != cache_info->storage_class) ||
1418 (image->colorspace != cache_info->colorspace) ||
1419 (image->alpha_trait != cache_info->alpha_trait) ||
1420 (image->read_mask != cache_info->read_mask) ||
1421 (image->write_mask != cache_info->write_mask) ||
1422 (image->columns != cache_info->columns) ||
1423 (image->rows != cache_info->rows) ||
1424 (image->number_channels != cache_info->number_channels) ||
1425 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1426 (image->metacontent_extent != cache_info->metacontent_extent) ||
1427 (cache_info->nexus_info == (NexusInfo **) NULL))
1428 return(MagickFalse);
1432 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1433 ExceptionInfo *exception)
1442 static MagickSizeType
1448 cache_timestamp = 0;
1451 LockSemaphoreInfo(image->semaphore);
1452 if (cpu_throttle == 0)
1453 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1454 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1455 MagickDelay(cpu_throttle);
1456 if (time_limit == 0)
1459 Set the expire time in seconds.
1461 time_limit=GetMagickResourceLimit(TimeResource);
1462 cache_timestamp=time((time_t *) NULL);
1464 if ((time_limit != MagickResourceInfinity) &&
1465 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1466 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1467 assert(image->cache != (Cache) NULL);
1468 cache_info=(CacheInfo *) image->cache;
1469 destroy=MagickFalse;
1470 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1472 LockSemaphoreInfo(cache_info->semaphore);
1473 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1484 clone_image=(*image);
1485 clone_image.semaphore=AllocateSemaphoreInfo();
1486 clone_image.reference_count=1;
1487 clone_image.cache=ClonePixelCache(cache_info);
1488 clone_info=(CacheInfo *) clone_image.cache;
1489 status=OpenPixelCache(&clone_image,IOMode,exception);
1490 if (status != MagickFalse)
1492 if (clone != MagickFalse)
1493 status=ClonePixelCacheRepository(clone_info,cache_info,
1495 if (status != MagickFalse)
1497 if (cache_info->reference_count == 1)
1498 cache_info->nexus_info=(NexusInfo **) NULL;
1500 image->cache=clone_image.cache;
1503 DestroySemaphoreInfo(&clone_image.semaphore);
1505 UnlockSemaphoreInfo(cache_info->semaphore);
1507 if (destroy != MagickFalse)
1508 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1509 if (status != MagickFalse)
1512 Ensure the image matches the pixel cache morphology.
1514 image->taint=MagickTrue;
1515 image->type=UndefinedType;
1516 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1518 status=OpenPixelCache(image,IOMode,exception);
1519 cache_info=(CacheInfo *) image->cache;
1520 if (cache_info->type == DiskCache)
1521 (void) ClosePixelCacheOnDisk(cache_info);
1524 UnlockSemaphoreInfo(image->semaphore);
1525 if (status == MagickFalse)
1526 return((Cache) NULL);
1527 return(image->cache);
1531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535 + G e t I m a g e P i x e l C a c h e T y p e %
1539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1542 % DiskCache, MemoryCache, MapCache, or PingCache.
1544 % The format of the GetImagePixelCacheType() method is:
1546 % CacheType GetImagePixelCacheType(const Image *image)
1548 % A description of each parameter follows:
1550 % o image: the image.
1553 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1558 assert(image != (Image *) NULL);
1559 assert(image->signature == MagickSignature);
1560 assert(image->cache != (Cache) NULL);
1561 cache_info=(CacheInfo *) image->cache;
1562 assert(cache_info->signature == MagickSignature);
1563 return(cache_info->type);
1567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1571 % G e t O n e A u t h e n t i c P i x e l %
1575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1578 % location. The image background color is returned if an error occurs.
1580 % The format of the GetOneAuthenticPixel() method is:
1582 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1583 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1585 % A description of each parameter follows:
1587 % o image: the image.
1589 % o x,y: These values define the location of the pixel to return.
1591 % o pixel: return a pixel at the specified (x,y) location.
1593 % o exception: return any errors or warnings in this structure.
1596 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1597 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1608 assert(image != (Image *) NULL);
1609 assert(image->signature == MagickSignature);
1610 assert(image->cache != (Cache) NULL);
1611 cache_info=(CacheInfo *) image->cache;
1612 assert(cache_info->signature == MagickSignature);
1613 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1614 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1615 (GetOneAuthenticPixelFromHandler) NULL)
1616 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1618 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1619 if (q == (Quantum *) NULL)
1621 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1622 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1623 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1624 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1625 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1626 return(MagickFalse);
1628 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1630 PixelChannel channel=GetPixelChannelChannel(image,i);
1631 pixel[channel]=q[i];
1637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641 + 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 %
1645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1647 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1648 % location. The image background color is returned if an error occurs.
1650 % The format of the GetOneAuthenticPixelFromCache() method is:
1652 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1653 % const ssize_t x,const ssize_t y,Quantum *pixel,
1654 % ExceptionInfo *exception)
1656 % A description of each parameter follows:
1658 % o image: the image.
1660 % o x,y: These values define the location of the pixel to return.
1662 % o pixel: return a pixel at the specified (x,y) location.
1664 % o exception: return any errors or warnings in this structure.
1667 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1668 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1674 id = GetOpenMPThreadId();
1682 assert(image != (const Image *) NULL);
1683 assert(image->signature == MagickSignature);
1684 assert(image->cache != (Cache) NULL);
1685 cache_info=(CacheInfo *) image->cache;
1686 assert(cache_info->signature == MagickSignature);
1687 assert(id < (int) cache_info->number_threads);
1688 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1689 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1691 if (q == (Quantum *) NULL)
1693 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1694 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1695 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1696 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1697 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1698 return(MagickFalse);
1700 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1702 PixelChannel channel=GetPixelChannelChannel(image,i);
1703 pixel[channel]=q[i];
1709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1713 % G e t O n e V i r t u a l P i x e l %
1717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1719 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1720 % (x,y) location. The image background color is returned if an error occurs.
1721 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1723 % The format of the GetOneVirtualPixel() method is:
1725 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1726 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1728 % A description of each parameter follows:
1730 % o image: the image.
1732 % o x,y: These values define the location of the pixel to return.
1734 % o pixel: return a pixel at the specified (x,y) location.
1736 % o exception: return any errors or warnings in this structure.
1739 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1740 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1746 id = GetOpenMPThreadId();
1754 assert(image != (const Image *) NULL);
1755 assert(image->signature == MagickSignature);
1756 assert(image->cache != (Cache) NULL);
1757 cache_info=(CacheInfo *) image->cache;
1758 assert(cache_info->signature == MagickSignature);
1759 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1760 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1761 (GetOneVirtualPixelFromHandler) NULL)
1762 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1763 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1764 assert(id < (int) cache_info->number_threads);
1765 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1766 1UL,1UL,cache_info->nexus_info[id],exception);
1767 if (p == (const Quantum *) NULL)
1769 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1770 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1771 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1772 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1773 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1774 return(MagickFalse);
1776 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1778 PixelChannel channel=GetPixelChannelChannel(image,i);
1779 pixel[channel]=p[i];
1785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1789 + 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 %
1793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1795 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1796 % specified (x,y) location. The image background color is returned if an
1799 % The format of the GetOneVirtualPixelFromCache() method is:
1801 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1802 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1803 % Quantum *pixel,ExceptionInfo *exception)
1805 % A description of each parameter follows:
1807 % o image: the image.
1809 % o virtual_pixel_method: the virtual pixel method.
1811 % o x,y: These values define the location of the pixel to return.
1813 % o pixel: return a pixel at the specified (x,y) location.
1815 % o exception: return any errors or warnings in this structure.
1818 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1819 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1820 Quantum *pixel,ExceptionInfo *exception)
1826 id = GetOpenMPThreadId();
1834 assert(image != (const Image *) NULL);
1835 assert(image->signature == MagickSignature);
1836 assert(image->cache != (Cache) NULL);
1837 cache_info=(CacheInfo *) image->cache;
1838 assert(cache_info->signature == MagickSignature);
1839 assert(id < (int) cache_info->number_threads);
1840 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1841 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1842 cache_info->nexus_info[id],exception);
1843 if (p == (const Quantum *) NULL)
1845 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1846 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
1847 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
1848 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
1849 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
1850 return(MagickFalse);
1852 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1854 PixelChannel channel=GetPixelChannelChannel(image,i);
1855 pixel[channel]=p[i];
1861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1865 % G e t O n e V i r t u a l P i x e l I n f o %
1869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1871 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1872 % location. The image background color is returned if an error occurs. If
1873 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1875 % The format of the GetOneVirtualPixelInfo() method is:
1877 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1878 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1879 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1881 % A description of each parameter follows:
1883 % o image: the image.
1885 % o virtual_pixel_method: the virtual pixel method.
1887 % o x,y: these values define the location of the pixel to return.
1889 % o pixel: return a pixel at the specified (x,y) location.
1891 % o exception: return any errors or warnings in this structure.
1894 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1895 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1896 PixelInfo *pixel,ExceptionInfo *exception)
1902 id = GetOpenMPThreadId();
1904 register const Quantum
1907 assert(image != (const Image *) NULL);
1908 assert(image->signature == MagickSignature);
1909 assert(image->cache != (Cache) NULL);
1910 cache_info=(CacheInfo *) image->cache;
1911 assert(cache_info->signature == MagickSignature);
1912 assert(id < (int) cache_info->number_threads);
1913 GetPixelInfo(image,pixel);
1914 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1915 cache_info->nexus_info[id],exception);
1916 if (p == (const Quantum *) NULL)
1917 return(MagickFalse);
1918 GetPixelInfoPixel(image,p,pixel);
1923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1927 + G e t P i x e l C a c h e C o l o r s p a c e %
1931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1933 % GetPixelCacheColorspace() returns the class type of the pixel cache.
1935 % The format of the GetPixelCacheColorspace() method is:
1937 % Colorspace GetPixelCacheColorspace(Cache cache)
1939 % A description of each parameter follows:
1941 % o cache: the pixel cache.
1944 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
1949 assert(cache != (Cache) NULL);
1950 cache_info=(CacheInfo *) cache;
1951 assert(cache_info->signature == MagickSignature);
1952 if (cache_info->debug != MagickFalse)
1953 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1954 cache_info->filename);
1955 return(cache_info->colorspace);
1959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1963 + G e t P i x e l C a c h e M e t h o d s %
1967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1969 % GetPixelCacheMethods() initializes the CacheMethods structure.
1971 % The format of the GetPixelCacheMethods() method is:
1973 % void GetPixelCacheMethods(CacheMethods *cache_methods)
1975 % A description of each parameter follows:
1977 % o cache_methods: Specifies a pointer to a CacheMethods structure.
1980 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
1982 assert(cache_methods != (CacheMethods *) NULL);
1983 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
1984 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
1985 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
1986 cache_methods->get_virtual_metacontent_from_handler=
1987 GetVirtualMetacontentFromCache;
1988 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
1989 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
1990 cache_methods->get_authentic_metacontent_from_handler=
1991 GetAuthenticMetacontentFromCache;
1992 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
1993 cache_methods->get_one_authentic_pixel_from_handler=
1994 GetOneAuthenticPixelFromCache;
1995 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
1996 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
1997 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2005 + G e t P i x e l C a c h e N e x u s E x t e n t %
2009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2012 % corresponding with the last call to SetPixelCacheNexusPixels() or
2013 % GetPixelCacheNexusPixels().
2015 % The format of the GetPixelCacheNexusExtent() method is:
2017 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2018 % NexusInfo *nexus_info)
2020 % A description of each parameter follows:
2022 % o nexus_info: the nexus info.
2025 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2026 NexusInfo *nexus_info)
2034 assert(cache != NULL);
2035 cache_info=(CacheInfo *) cache;
2036 assert(cache_info->signature == MagickSignature);
2037 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2039 return((MagickSizeType) cache_info->columns*cache_info->rows);
2044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2048 + G e t P i x e l C a c h e P i x e l s %
2052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2054 % GetPixelCachePixels() returns the pixels associated with the specified image.
2056 % The format of the GetPixelCachePixels() method is:
2058 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2059 % ExceptionInfo *exception)
2061 % A description of each parameter follows:
2063 % o image: the image.
2065 % o length: the pixel cache length.
2067 % o exception: return any errors or warnings in this structure.
2070 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2071 ExceptionInfo *exception)
2076 assert(image != (const Image *) NULL);
2077 assert(image->signature == MagickSignature);
2078 assert(image->cache != (Cache) NULL);
2079 assert(length != (MagickSizeType *) NULL);
2080 assert(exception != (ExceptionInfo *) NULL);
2081 assert(exception->signature == MagickSignature);
2082 cache_info=(CacheInfo *) image->cache;
2083 assert(cache_info->signature == MagickSignature);
2085 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2086 return((void *) NULL);
2087 *length=cache_info->length;
2088 return((void *) cache_info->pixels);
2092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2096 + 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 %
2100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2104 % The format of the GetPixelCacheStorageClass() method is:
2106 % ClassType GetPixelCacheStorageClass(Cache cache)
2108 % A description of each parameter follows:
2110 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2112 % o cache: the pixel cache.
2115 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2120 assert(cache != (Cache) NULL);
2121 cache_info=(CacheInfo *) cache;
2122 assert(cache_info->signature == MagickSignature);
2123 if (cache_info->debug != MagickFalse)
2124 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2125 cache_info->filename);
2126 return(cache_info->storage_class);
2130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2134 + G e t P i x e l C a c h e T i l e S i z e %
2138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2140 % GetPixelCacheTileSize() returns the pixel cache tile size.
2142 % The format of the GetPixelCacheTileSize() method is:
2144 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2147 % A description of each parameter follows:
2149 % o image: the image.
2151 % o width: the optimize cache tile width in pixels.
2153 % o height: the optimize cache tile height in pixels.
2156 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2162 assert(image != (Image *) NULL);
2163 assert(image->signature == MagickSignature);
2164 if (image->debug != MagickFalse)
2165 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2166 cache_info=(CacheInfo *) image->cache;
2167 assert(cache_info->signature == MagickSignature);
2168 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2169 if (GetImagePixelCacheType(image) == DiskCache)
2170 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2179 + 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 %
2183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2185 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2186 % pixel cache. A virtual pixel is any pixel access that is outside the
2187 % boundaries of the image cache.
2189 % The format of the GetPixelCacheVirtualMethod() method is:
2191 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2193 % A description of each parameter follows:
2195 % o image: the image.
2198 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2203 assert(image != (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 return(cache_info->virtual_pixel_method);
2212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216 + 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 %
2220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2222 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2223 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2225 % The format of the GetVirtualMetacontentFromCache() method is:
2227 % void *GetVirtualMetacontentFromCache(const Image *image)
2229 % A description of each parameter follows:
2231 % o image: the image.
2234 static const void *GetVirtualMetacontentFromCache(const Image *image)
2240 id = GetOpenMPThreadId();
2245 assert(image != (const Image *) NULL);
2246 assert(image->signature == MagickSignature);
2247 assert(image->cache != (Cache) NULL);
2248 cache_info=(CacheInfo *) image->cache;
2249 assert(cache_info->signature == MagickSignature);
2250 assert(id < (int) cache_info->number_threads);
2251 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2252 cache_info->nexus_info[id]);
2253 return(metacontent);
2257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2261 + 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 %
2265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2267 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2270 % The format of the GetVirtualMetacontentFromNexus() method is:
2272 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2273 % NexusInfo *nexus_info)
2275 % A description of each parameter follows:
2277 % o cache: the pixel cache.
2279 % o nexus_info: the cache nexus to return the meta-content.
2282 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2283 NexusInfo *nexus_info)
2288 assert(cache != (Cache) NULL);
2289 cache_info=(CacheInfo *) cache;
2290 assert(cache_info->signature == MagickSignature);
2291 if (cache_info->storage_class == UndefinedClass)
2292 return((void *) NULL);
2293 return(nexus_info->metacontent);
2297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2301 % G e t V i r t u a l M e t a c o n t e n t %
2305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2307 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2308 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2309 % returned if the meta-content are not available.
2311 % The format of the GetVirtualMetacontent() method is:
2313 % const void *GetVirtualMetacontent(const Image *image)
2315 % A description of each parameter follows:
2317 % o image: the image.
2320 MagickExport const void *GetVirtualMetacontent(const Image *image)
2326 id = GetOpenMPThreadId();
2331 assert(image != (const Image *) NULL);
2332 assert(image->signature == MagickSignature);
2333 assert(image->cache != (Cache) NULL);
2334 cache_info=(CacheInfo *) image->cache;
2335 assert(cache_info->signature == MagickSignature);
2336 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2337 if (metacontent != (void *) NULL)
2338 return(metacontent);
2339 assert(id < (int) cache_info->number_threads);
2340 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2341 cache_info->nexus_info[id]);
2342 return(metacontent);
2346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2350 + 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 %
2354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2356 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2357 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2358 % is returned if the pixels are transferred, otherwise a NULL is returned.
2360 % The format of the GetVirtualPixelsFromNexus() method is:
2362 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2363 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2364 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2365 % ExceptionInfo *exception)
2367 % A description of each parameter follows:
2369 % o image: the image.
2371 % o virtual_pixel_method: the virtual pixel method.
2373 % o x,y,columns,rows: These values define the perimeter of a region of
2376 % o nexus_info: the cache nexus to acquire.
2378 % o exception: return any errors or warnings in this structure.
2385 0, 48, 12, 60, 3, 51, 15, 63,
2386 32, 16, 44, 28, 35, 19, 47, 31,
2387 8, 56, 4, 52, 11, 59, 7, 55,
2388 40, 24, 36, 20, 43, 27, 39, 23,
2389 2, 50, 14, 62, 1, 49, 13, 61,
2390 34, 18, 46, 30, 33, 17, 45, 29,
2391 10, 58, 6, 54, 9, 57, 5, 53,
2392 42, 26, 38, 22, 41, 25, 37, 21
2395 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2400 index=x+DitherMatrix[x & 0x07]-32L;
2403 if (index >= (ssize_t) columns)
2404 return((ssize_t) columns-1L);
2408 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2413 index=y+DitherMatrix[y & 0x07]-32L;
2416 if (index >= (ssize_t) rows)
2417 return((ssize_t) rows-1L);
2421 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2425 if (x >= (ssize_t) columns)
2426 return((ssize_t) (columns-1));
2430 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2434 if (y >= (ssize_t) rows)
2435 return((ssize_t) (rows-1));
2439 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2441 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2444 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2446 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2449 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2450 const size_t extent)
2456 Compute the remainder of dividing offset by extent. It returns not only
2457 the quotient (tile the offset falls in) but also the positive remainer
2458 within that tile such that 0 <= remainder < extent. This method is
2459 essentially a ldiv() using a floored modulo division rather than the
2460 normal default truncated modulo division.
2462 modulo.quotient=offset/(ssize_t) extent;
2465 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2469 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2470 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2471 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2472 ExceptionInfo *exception)
2489 virtual_pixel[MaxPixelChannels];
2494 register const Quantum
2507 register unsigned char
2514 *virtual_metacontent;
2519 assert(image != (const Image *) NULL);
2520 assert(image->signature == MagickSignature);
2521 assert(image->cache != (Cache) NULL);
2522 cache_info=(CacheInfo *) image->cache;
2523 assert(cache_info->signature == MagickSignature);
2524 if (cache_info->type == UndefinedCache)
2525 return((const Quantum *) NULL);
2528 region.width=columns;
2530 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2532 if (pixels == (Quantum *) NULL)
2533 return((const Quantum *) NULL);
2535 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2536 nexus_info->region.x;
2537 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2538 nexus_info->region.width-1L;
2539 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2540 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2541 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2542 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2548 Pixel request is inside cache extents.
2550 if (nexus_info->authentic_cache != MagickFalse)
2552 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2553 if (status == MagickFalse)
2554 return((const Quantum *) NULL);
2555 if (cache_info->metacontent_extent != 0)
2557 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2558 if (status == MagickFalse)
2559 return((const Quantum *) NULL);
2564 Pixel request is outside cache extents.
2566 s=(unsigned char *) nexus_info->metacontent;
2567 virtual_nexus=AcquirePixelCacheNexus(1);
2568 if (virtual_nexus == (NexusInfo **) NULL)
2570 if (virtual_nexus != (NexusInfo **) NULL)
2571 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2572 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2573 "UnableToGetCacheNexus","`%s'",image->filename);
2574 return((const Quantum *) NULL);
2576 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2577 sizeof(*virtual_pixel));
2578 virtual_metacontent=(void *) NULL;
2579 switch (virtual_pixel_method)
2581 case BackgroundVirtualPixelMethod:
2582 case BlackVirtualPixelMethod:
2583 case GrayVirtualPixelMethod:
2584 case TransparentVirtualPixelMethod:
2585 case MaskVirtualPixelMethod:
2586 case WhiteVirtualPixelMethod:
2587 case EdgeVirtualPixelMethod:
2588 case CheckerTileVirtualPixelMethod:
2589 case HorizontalTileVirtualPixelMethod:
2590 case VerticalTileVirtualPixelMethod:
2592 if (cache_info->metacontent_extent != 0)
2595 Acquire a metacontent buffer.
2597 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2598 cache_info->metacontent_extent);
2599 if (virtual_metacontent == (void *) NULL)
2601 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2602 (void) ThrowMagickException(exception,GetMagickModule(),
2603 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2604 return((const Quantum *) NULL);
2606 (void) ResetMagickMemory(virtual_metacontent,0,
2607 cache_info->metacontent_extent);
2609 switch (virtual_pixel_method)
2611 case BlackVirtualPixelMethod:
2613 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2614 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2615 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2618 case GrayVirtualPixelMethod:
2620 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2621 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2623 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2626 case TransparentVirtualPixelMethod:
2628 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2629 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
2630 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2633 case MaskVirtualPixelMethod:
2634 case WhiteVirtualPixelMethod:
2636 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2637 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2638 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2643 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2645 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2647 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2649 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2651 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2661 for (v=0; v < (ssize_t) rows; v++)
2667 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2668 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2669 y_offset=EdgeY(y_offset,cache_info->rows);
2670 for (u=0; u < (ssize_t) columns; u+=length)
2676 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2677 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2678 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2686 Transfer a single pixel.
2688 length=(MagickSizeType) 1;
2689 switch (virtual_pixel_method)
2691 case EdgeVirtualPixelMethod:
2694 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2695 EdgeX(x_offset,cache_info->columns),
2696 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2698 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2701 case RandomVirtualPixelMethod:
2703 if (cache_info->random_info == (RandomInfo *) NULL)
2704 cache_info->random_info=AcquireRandomInfo();
2705 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2706 RandomX(cache_info->random_info,cache_info->columns),
2707 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2708 *virtual_nexus,exception);
2709 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2712 case DitherVirtualPixelMethod:
2714 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2715 DitherX(x_offset,cache_info->columns),
2716 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2718 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2721 case TileVirtualPixelMethod:
2723 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2724 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2725 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2726 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2728 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2731 case MirrorVirtualPixelMethod:
2733 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2734 if ((x_modulo.quotient & 0x01) == 1L)
2735 x_modulo.remainder=(ssize_t) cache_info->columns-
2736 x_modulo.remainder-1L;
2737 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2738 if ((y_modulo.quotient & 0x01) == 1L)
2739 y_modulo.remainder=(ssize_t) cache_info->rows-
2740 y_modulo.remainder-1L;
2741 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2742 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2744 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2747 case HorizontalTileEdgeVirtualPixelMethod:
2749 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2750 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2751 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2752 *virtual_nexus,exception);
2753 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2756 case VerticalTileEdgeVirtualPixelMethod:
2758 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2759 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2760 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2761 *virtual_nexus,exception);
2762 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2765 case BackgroundVirtualPixelMethod:
2766 case BlackVirtualPixelMethod:
2767 case GrayVirtualPixelMethod:
2768 case TransparentVirtualPixelMethod:
2769 case MaskVirtualPixelMethod:
2770 case WhiteVirtualPixelMethod:
2773 r=virtual_metacontent;
2776 case CheckerTileVirtualPixelMethod:
2778 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2779 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2780 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2783 r=virtual_metacontent;
2786 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2787 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2789 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2792 case HorizontalTileVirtualPixelMethod:
2794 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2797 r=virtual_metacontent;
2800 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2801 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2802 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2803 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2805 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2808 case VerticalTileVirtualPixelMethod:
2810 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2813 r=virtual_metacontent;
2816 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2817 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2818 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2819 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2821 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2825 if (p == (const Quantum *) NULL)
2827 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2829 q+=cache_info->number_channels;
2830 if ((s != (void *) NULL) && (r != (const void *) NULL))
2832 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2833 s+=cache_info->metacontent_extent;
2838 Transfer a run of pixels.
2840 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2841 (size_t) length,1UL,*virtual_nexus,exception);
2842 if (p == (const Quantum *) NULL)
2844 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2845 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2846 q+=length*cache_info->number_channels;
2847 if ((r != (void *) NULL) && (s != (const void *) NULL))
2849 (void) memcpy(s,r,(size_t) length);
2850 s+=length*cache_info->metacontent_extent;
2857 if (virtual_metacontent != (void *) NULL)
2858 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2859 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2868 + G e t V i r t u a l P i x e l C a c h e %
2872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
2875 % cache as defined by the geometry parameters. A pointer to the pixels
2876 % is returned if the pixels are transferred, otherwise a NULL is returned.
2878 % The format of the GetVirtualPixelCache() method is:
2880 % const Quantum *GetVirtualPixelCache(const Image *image,
2881 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2882 % const ssize_t y,const size_t columns,const size_t rows,
2883 % ExceptionInfo *exception)
2885 % A description of each parameter follows:
2887 % o image: the image.
2889 % o virtual_pixel_method: the virtual pixel method.
2891 % o x,y,columns,rows: These values define the perimeter of a region of
2894 % o exception: return any errors or warnings in this structure.
2897 static const Quantum *GetVirtualPixelCache(const Image *image,
2898 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2899 const size_t columns,const size_t rows,ExceptionInfo *exception)
2905 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 assert(id < (int) cache_info->number_threads);
2916 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
2917 cache_info->nexus_info[id],exception);
2922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2926 % G e t V i r t u a l P i x e l Q u e u e %
2930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2932 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
2933 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
2935 % The format of the GetVirtualPixelQueue() method is:
2937 % const Quantum *GetVirtualPixelQueue(const Image image)
2939 % A description of each parameter follows:
2941 % o image: the image.
2944 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
2950 id = GetOpenMPThreadId();
2952 assert(image != (const Image *) NULL);
2953 assert(image->signature == MagickSignature);
2954 assert(image->cache != (Cache) NULL);
2955 cache_info=(CacheInfo *) image->cache;
2956 assert(cache_info->signature == MagickSignature);
2957 if (cache_info->methods.get_virtual_pixels_handler !=
2958 (GetVirtualPixelsHandler) NULL)
2959 return(cache_info->methods.get_virtual_pixels_handler(image));
2960 assert(id < (int) cache_info->number_threads);
2961 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
2965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2969 % G e t V i r t u a l P i x e l s %
2973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2975 % GetVirtualPixels() returns an immutable pixel region. If the
2976 % region is successfully accessed, a pointer to it is returned, otherwise
2977 % NULL is returned. The returned pointer may point to a temporary working
2978 % copy of the pixels or it may point to the original pixels in memory.
2979 % Performance is maximized if the selected region is part of one row, or one
2980 % or more full rows, since there is opportunity to access the pixels in-place
2981 % (without a copy) if the image is in memory, or in a memory-mapped file. The
2982 % returned pointer must *never* be deallocated by the user.
2984 % Pixels accessed via the returned pointer represent a simple array of type
2985 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
2986 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
2987 % access the meta-content (of type void) corresponding to the the
2990 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
2992 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
2993 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
2994 % GetCacheViewAuthenticPixels() instead.
2996 % The format of the GetVirtualPixels() method is:
2998 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
2999 % const ssize_t y,const size_t columns,const size_t rows,
3000 % ExceptionInfo *exception)
3002 % A description of each parameter follows:
3004 % o image: the image.
3006 % o x,y,columns,rows: These values define the perimeter of a region of
3009 % o exception: return any errors or warnings in this structure.
3012 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3013 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3014 ExceptionInfo *exception)
3020 id = GetOpenMPThreadId();
3025 assert(image != (const Image *) NULL);
3026 assert(image->signature == MagickSignature);
3027 assert(image->cache != (Cache) NULL);
3028 cache_info=(CacheInfo *) image->cache;
3029 assert(cache_info->signature == MagickSignature);
3030 if (cache_info->methods.get_virtual_pixel_handler !=
3031 (GetVirtualPixelHandler) NULL)
3032 return(cache_info->methods.get_virtual_pixel_handler(image,
3033 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3034 assert(id < (int) cache_info->number_threads);
3035 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3036 columns,rows,cache_info->nexus_info[id],exception);
3041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3045 + 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 %
3049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3051 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3052 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3054 % The format of the GetVirtualPixelsCache() method is:
3056 % Quantum *GetVirtualPixelsCache(const Image *image)
3058 % A description of each parameter follows:
3060 % o image: the image.
3063 static const Quantum *GetVirtualPixelsCache(const Image *image)
3069 id = GetOpenMPThreadId();
3071 assert(image != (const Image *) NULL);
3072 assert(image->signature == MagickSignature);
3073 assert(image->cache != (Cache) NULL);
3074 cache_info=(CacheInfo *) image->cache;
3075 assert(cache_info->signature == MagickSignature);
3076 assert(id < (int) cache_info->number_threads);
3077 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3085 + G e t V i r t u a l P i x e l s N e x u s %
3089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3091 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3094 % The format of the GetVirtualPixelsNexus() method is:
3096 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3097 % NexusInfo *nexus_info)
3099 % A description of each parameter follows:
3101 % o cache: the pixel cache.
3103 % o nexus_info: the cache nexus to return the colormap pixels.
3106 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3107 NexusInfo *nexus_info)
3112 assert(cache != (Cache) NULL);
3113 cache_info=(CacheInfo *) cache;
3114 assert(cache_info->signature == MagickSignature);
3115 if (cache_info->storage_class == UndefinedClass)
3116 return((Quantum *) NULL);
3117 return((const Quantum *) nexus_info->pixels);
3121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3125 + O p e n P i x e l C a c h e %
3129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3131 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3132 % dimensions, allocating space for the image pixels and optionally the
3133 % metacontent, and memory mapping the cache if it is disk based. The cache
3134 % nexus array is initialized as well.
3136 % The format of the OpenPixelCache() method is:
3138 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3139 % ExceptionInfo *exception)
3141 % A description of each parameter follows:
3143 % o image: the image.
3145 % o mode: ReadMode, WriteMode, or IOMode.
3147 % o exception: return any errors or warnings in this structure.
3151 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3153 cache_info->mapped=MagickFalse;
3154 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3155 (size_t) cache_info->length));
3156 if (cache_info->pixels == (Quantum *) NULL)
3158 cache_info->mapped=MagickTrue;
3159 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3160 cache_info->length);
3164 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3171 Open pixel cache on disk.
3173 if (cache_info->file != -1)
3174 return(MagickTrue); /* cache already open */
3175 if (*cache_info->cache_filename == '\0')
3176 file=AcquireUniqueFileResource(cache_info->cache_filename);
3182 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3187 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3188 O_BINARY | O_EXCL,S_MODE);
3190 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3196 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3199 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3204 return(MagickFalse);
3205 (void) AcquireMagickResource(FileResource,1);
3206 cache_info->file=file;
3207 cache_info->mode=mode;
3211 static inline MagickOffsetType WritePixelCacheRegion(
3212 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3213 const MagickSizeType length,const unsigned char *restrict buffer)
3215 register MagickOffsetType
3221 #if !defined(MAGICKCORE_HAVE_PWRITE)
3222 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3223 return((MagickOffsetType) -1);
3226 for (i=0; i < (MagickOffsetType) length; i+=count)
3228 #if !defined(MAGICKCORE_HAVE_PWRITE)
3229 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3230 (MagickSizeType) SSIZE_MAX));
3232 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3233 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
3245 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3255 cache_info=(CacheInfo *) image->cache;
3256 if (image->debug != MagickFalse)
3259 format[MaxTextExtent],
3260 message[MaxTextExtent];
3262 (void) FormatMagickSize(length,MagickFalse,format);
3263 (void) FormatLocaleString(message,MaxTextExtent,
3264 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3265 cache_info->cache_filename,cache_info->file,format);
3266 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3268 if (length != (MagickSizeType) ((MagickOffsetType) length))
3269 return(MagickFalse);
3270 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3272 return(MagickFalse);
3273 if ((MagickSizeType) offset >= length)
3275 extent=(MagickOffsetType) length-1;
3276 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3277 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3278 if (cache_info->synchronize != MagickFalse)
3283 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3285 return(MagickFalse);
3288 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3291 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3292 ExceptionInfo *exception)
3299 format[MaxTextExtent],
3300 message[MaxTextExtent];
3316 assert(image != (const Image *) NULL);
3317 assert(image->signature == MagickSignature);
3318 assert(image->cache != (Cache) NULL);
3319 if (image->debug != MagickFalse)
3320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3321 if ((image->columns == 0) || (image->rows == 0))
3322 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3323 cache_info=(CacheInfo *) image->cache;
3324 assert(cache_info->signature == MagickSignature);
3325 source_info=(*cache_info);
3326 source_info.file=(-1);
3327 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3328 image->filename,(double) GetImageIndexInList(image));
3329 cache_info->storage_class=image->storage_class;
3330 cache_info->colorspace=image->colorspace;
3331 cache_info->alpha_trait=image->alpha_trait;
3332 cache_info->read_mask=image->read_mask;
3333 cache_info->write_mask=image->write_mask;
3334 cache_info->rows=image->rows;
3335 cache_info->columns=image->columns;
3336 InitializePixelChannelMap(image);
3337 cache_info->number_channels=GetPixelChannels(image);
3338 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3339 sizeof(*image->channel_map));
3340 cache_info->metacontent_extent=image->metacontent_extent;
3341 cache_info->mode=mode;
3342 if (image->ping != MagickFalse)
3344 cache_info->type=PingCache;
3345 cache_info->pixels=(Quantum *) NULL;
3346 cache_info->metacontent=(void *) NULL;
3347 cache_info->length=0;
3350 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3351 packet_size=cache_info->number_channels*sizeof(Quantum);
3352 if (image->metacontent_extent != 0)
3353 packet_size+=cache_info->metacontent_extent;
3354 length=number_pixels*packet_size;
3355 columns=(size_t) (length/cache_info->rows/packet_size);
3356 if (cache_info->columns != columns)
3357 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3359 cache_info->length=length;
3360 status=AcquireMagickResource(AreaResource,cache_info->length);
3361 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3362 cache_info->metacontent_extent);
3363 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3365 status=AcquireMagickResource(MemoryResource,cache_info->length);
3366 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3367 (cache_info->type == MemoryCache))
3369 AllocatePixelCachePixels(cache_info);
3370 if (cache_info->pixels == (Quantum *) NULL)
3371 cache_info->pixels=source_info.pixels;
3375 Create memory pixel cache.
3378 cache_info->type=MemoryCache;
3379 cache_info->metacontent=(void *) NULL;
3380 if (cache_info->metacontent_extent != 0)
3381 cache_info->metacontent=(void *) (cache_info->pixels+
3382 number_pixels*cache_info->number_channels);
3383 if ((source_info.storage_class != UndefinedClass) &&
3386 status=ClonePixelCacheRepository(cache_info,&source_info,
3388 RelinquishPixelCachePixels(&source_info);
3390 if (image->debug != MagickFalse)
3392 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3393 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3395 (void) FormatLocaleString(message,MaxTextExtent,
3396 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3397 cache_info->filename,cache_info->mapped != MagickFalse ?
3398 "Anonymous" : "Heap",type,(double) cache_info->columns,
3399 (double) cache_info->rows,(double)
3400 cache_info->number_channels,format);
3401 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3407 RelinquishMagickResource(MemoryResource,cache_info->length);
3410 Create pixel cache on disk.
3412 status=AcquireMagickResource(DiskResource,cache_info->length);
3413 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3418 if (cache_info->type == DistributedCache)
3419 RelinquishMagickResource(DiskResource,cache_info->length);
3420 server_info=AcquireDistributeCacheInfo(exception);
3421 if (server_info != (DistributeCacheInfo *) NULL)
3423 status=OpenDistributePixelCache(server_info,image);
3424 if (status == MagickFalse)
3426 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3427 GetDistributeCacheHostname(server_info));
3428 server_info=DestroyDistributeCacheInfo(server_info);
3433 Create a distributed pixel cache.
3435 cache_info->type=DistributedCache;
3436 cache_info->server_info=server_info;
3437 (void) FormatLocaleString(cache_info->cache_filename,
3438 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
3439 (DistributeCacheInfo *) cache_info->server_info),
3440 GetDistributeCachePort((DistributeCacheInfo *)
3441 cache_info->server_info));
3442 if ((source_info.storage_class != UndefinedClass) &&
3445 status=ClonePixelCacheRepository(cache_info,&source_info,
3447 RelinquishPixelCachePixels(&source_info);
3449 if (image->debug != MagickFalse)
3451 (void) FormatMagickSize(cache_info->length,MagickFalse,
3453 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3455 (void) FormatLocaleString(message,MaxTextExtent,
3456 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3457 cache_info->filename,cache_info->cache_filename,
3458 GetDistributeCacheFile((DistributeCacheInfo *)
3459 cache_info->server_info),type,(double) cache_info->columns,
3460 (double) cache_info->rows,(double)
3461 cache_info->number_channels,format);
3462 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3468 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3469 "CacheResourcesExhausted","`%s'",image->filename);
3470 return(MagickFalse);
3472 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3474 (void) ClosePixelCacheOnDisk(cache_info);
3475 *cache_info->cache_filename='\0';
3477 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3479 RelinquishMagickResource(DiskResource,cache_info->length);
3480 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3482 return(MagickFalse);
3484 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3485 cache_info->length);
3486 if (status == MagickFalse)
3488 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3490 return(MagickFalse);
3492 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3493 cache_info->metacontent_extent);
3494 if (length != (MagickSizeType) ((size_t) length))
3495 cache_info->type=DiskCache;
3498 status=AcquireMagickResource(MapResource,cache_info->length);
3499 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3500 (cache_info->type != MemoryCache))
3501 cache_info->type=DiskCache;
3504 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3505 cache_info->offset,(size_t) cache_info->length);
3506 if (cache_info->pixels == (Quantum *) NULL)
3508 cache_info->type=DiskCache;
3509 cache_info->pixels=source_info.pixels;
3514 Create file-backed memory-mapped pixel cache.
3517 (void) ClosePixelCacheOnDisk(cache_info);
3518 cache_info->type=MapCache;
3519 cache_info->mapped=MagickTrue;
3520 cache_info->metacontent=(void *) NULL;
3521 if (cache_info->metacontent_extent != 0)
3522 cache_info->metacontent=(void *) (cache_info->pixels+
3523 number_pixels*cache_info->number_channels);
3524 if ((source_info.storage_class != UndefinedClass) &&
3527 status=ClonePixelCacheRepository(cache_info,&source_info,
3529 RelinquishPixelCachePixels(&source_info);
3531 if (image->debug != MagickFalse)
3533 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3534 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3536 (void) FormatLocaleString(message,MaxTextExtent,
3537 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3538 cache_info->filename,cache_info->cache_filename,
3539 cache_info->file,type,(double) cache_info->columns,(double)
3540 cache_info->rows,(double) cache_info->number_channels,
3542 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3548 RelinquishMagickResource(MapResource,cache_info->length);
3551 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3553 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3554 RelinquishPixelCachePixels(&source_info);
3556 if (image->debug != MagickFalse)
3558 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3559 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3561 (void) FormatLocaleString(message,MaxTextExtent,
3562 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3563 cache_info->cache_filename,cache_info->file,type,(double)
3564 cache_info->columns,(double) cache_info->rows,(double)
3565 cache_info->number_channels,format);
3566 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3576 + P e r s i s t P i x e l C a c h e %
3580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3583 % persistent pixel cache is one that resides on disk and is not destroyed
3584 % when the program exits.
3586 % The format of the PersistPixelCache() method is:
3588 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3589 % const MagickBooleanType attach,MagickOffsetType *offset,
3590 % ExceptionInfo *exception)
3592 % A description of each parameter follows:
3594 % o image: the image.
3596 % o filename: the persistent pixel cache filename.
3598 % o attach: A value other than zero initializes the persistent pixel cache.
3600 % o initialize: A value other than zero initializes the persistent pixel
3603 % o offset: the offset in the persistent cache to store pixels.
3605 % o exception: return any errors or warnings in this structure.
3608 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3609 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3610 ExceptionInfo *exception)
3625 assert(image != (Image *) NULL);
3626 assert(image->signature == MagickSignature);
3627 if (image->debug != MagickFalse)
3628 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3629 assert(image->cache != (void *) NULL);
3630 assert(filename != (const char *) NULL);
3631 assert(offset != (MagickOffsetType *) NULL);
3632 page_size=GetMagickPageSize();
3633 cache_info=(CacheInfo *) image->cache;
3634 assert(cache_info->signature == MagickSignature);
3635 if (attach != MagickFalse)
3638 Attach existing persistent pixel cache.
3640 if (image->debug != MagickFalse)
3641 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3642 "attach persistent cache");
3643 (void) CopyMagickString(cache_info->cache_filename,filename,
3645 cache_info->type=DiskCache;
3646 cache_info->offset=(*offset);
3647 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3648 return(MagickFalse);
3649 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3652 if ((cache_info->mode != ReadMode) &&
3653 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3654 (cache_info->reference_count == 1))
3656 LockSemaphoreInfo(cache_info->semaphore);
3657 if ((cache_info->mode != ReadMode) &&
3658 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
3659 (cache_info->reference_count == 1))
3665 Usurp existing persistent pixel cache.
3667 status=rename_utf8(cache_info->cache_filename,filename);
3670 (void) CopyMagickString(cache_info->cache_filename,filename,
3672 *offset+=cache_info->length+page_size-(cache_info->length %
3674 UnlockSemaphoreInfo(cache_info->semaphore);
3675 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
3676 if (image->debug != MagickFalse)
3677 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3678 "Usurp resident persistent cache");
3682 UnlockSemaphoreInfo(cache_info->semaphore);
3685 Clone persistent pixel cache.
3687 clone_image=(*image);
3688 clone_info=(CacheInfo *) clone_image.cache;
3689 image->cache=ClonePixelCache(cache_info);
3690 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
3691 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
3692 cache_info->type=DiskCache;
3693 cache_info->offset=(*offset);
3694 cache_info=(CacheInfo *) image->cache;
3695 status=OpenPixelCache(image,IOMode,exception);
3696 if (status != MagickFalse)
3697 status=ClonePixelCacheRepository(cache_info,clone_info,exception);
3698 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3699 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3708 + 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 %
3712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3714 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3715 % defined by the region rectangle and returns a pointer to the region. This
3716 % region is subsequently transferred from the pixel cache with
3717 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3718 % pixels are transferred, otherwise a NULL is returned.
3720 % The format of the QueueAuthenticPixelCacheNexus() method is:
3722 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3723 % const ssize_t y,const size_t columns,const size_t rows,
3724 % const MagickBooleanType clone,NexusInfo *nexus_info,
3725 % ExceptionInfo *exception)
3727 % A description of each parameter follows:
3729 % o image: the image.
3731 % o x,y,columns,rows: These values define the perimeter of a region of
3734 % o nexus_info: the cache nexus to set.
3736 % o clone: clone the pixel cache.
3738 % o exception: return any errors or warnings in this structure.
3741 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3742 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3743 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3761 Validate pixel cache geometry.
3763 assert(image != (const Image *) NULL);
3764 assert(image->signature == MagickSignature);
3765 assert(image->cache != (Cache) NULL);
3766 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3767 if (cache_info == (Cache) NULL)
3768 return((Quantum *) NULL);
3769 assert(cache_info->signature == MagickSignature);
3770 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3771 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3772 (y >= (ssize_t) cache_info->rows))
3774 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3775 "PixelsAreNotAuthentic","`%s'",image->filename);
3776 return((Quantum *) NULL);
3778 offset=(MagickOffsetType) y*cache_info->columns+x;
3780 return((Quantum *) NULL);
3781 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3782 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3783 if ((MagickSizeType) offset >= number_pixels)
3784 return((Quantum *) NULL);
3790 region.width=columns;
3792 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3802 + 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 %
3806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3808 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3809 % defined by the region rectangle and returns a pointer to the region. This
3810 % region is subsequently transferred from the pixel cache with
3811 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3812 % pixels are transferred, otherwise a NULL is returned.
3814 % The format of the QueueAuthenticPixelsCache() method is:
3816 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3817 % const ssize_t y,const size_t columns,const size_t rows,
3818 % ExceptionInfo *exception)
3820 % A description of each parameter follows:
3822 % o image: the image.
3824 % o x,y,columns,rows: These values define the perimeter of a region of
3827 % o exception: return any errors or warnings in this structure.
3830 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3831 const ssize_t y,const size_t columns,const size_t rows,
3832 ExceptionInfo *exception)
3838 id = GetOpenMPThreadId();
3843 assert(image != (const Image *) NULL);
3844 assert(image->signature == MagickSignature);
3845 assert(image->cache != (Cache) NULL);
3846 cache_info=(CacheInfo *) image->cache;
3847 assert(cache_info->signature == MagickSignature);
3848 assert(id < (int) cache_info->number_threads);
3849 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3850 cache_info->nexus_info[id],exception);
3855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3859 % Q u e u e A u t h e n t i c P i x e l s %
3863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3865 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
3866 % successfully initialized a pointer to a Quantum array representing the
3867 % region is returned, otherwise NULL is returned. The returned pointer may
3868 % point to a temporary working buffer for the pixels or it may point to the
3869 % final location of the pixels in memory.
3871 % Write-only access means that any existing pixel values corresponding to
3872 % the region are ignored. This is useful if the initial image is being
3873 % created from scratch, or if the existing pixel values are to be
3874 % completely replaced without need to refer to their pre-existing values.
3875 % The application is free to read and write the pixel buffer returned by
3876 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
3877 % initialize the pixel array values. Initializing pixel array values is the
3878 % application's responsibility.
3880 % Performance is maximized if the selected region is part of one row, or
3881 % one or more full rows, since then there is opportunity to access the
3882 % pixels in-place (without a copy) if the image is in memory, or in a
3883 % memory-mapped file. The returned pointer must *never* be deallocated
3886 % Pixels accessed via the returned pointer represent a simple array of type
3887 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3888 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3889 % obtain the meta-content (of type void) corresponding to the region.
3890 % Once the Quantum (and/or Quantum) array has been updated, the
3891 % changes must be saved back to the underlying image using
3892 % SyncAuthenticPixels() or they may be lost.
3894 % The format of the QueueAuthenticPixels() method is:
3896 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3897 % const ssize_t y,const size_t columns,const size_t rows,
3898 % ExceptionInfo *exception)
3900 % A description of each parameter follows:
3902 % o image: the image.
3904 % o x,y,columns,rows: These values define the perimeter of a region of
3907 % o exception: return any errors or warnings in this structure.
3910 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
3911 const ssize_t y,const size_t columns,const size_t rows,
3912 ExceptionInfo *exception)
3918 id = GetOpenMPThreadId();
3923 assert(image != (Image *) NULL);
3924 assert(image->signature == MagickSignature);
3925 assert(image->cache != (Cache) NULL);
3926 cache_info=(CacheInfo *) image->cache;
3927 assert(cache_info->signature == MagickSignature);
3928 if (cache_info->methods.queue_authentic_pixels_handler !=
3929 (QueueAuthenticPixelsHandler) NULL)
3931 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
3932 columns,rows,exception);
3935 assert(id < (int) cache_info->number_threads);
3936 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
3937 cache_info->nexus_info[id],exception);
3942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3946 + 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 %
3950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3952 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
3955 % The format of the ReadPixelCacheMetacontent() method is:
3957 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
3958 % NexusInfo *nexus_info,ExceptionInfo *exception)
3960 % A description of each parameter follows:
3962 % o cache_info: the pixel cache.
3964 % o nexus_info: the cache nexus to read the metacontent.
3966 % o exception: return any errors or warnings in this structure.
3970 static inline MagickOffsetType ReadPixelCacheRegion(
3971 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
3972 const MagickSizeType length,unsigned char *restrict buffer)
3974 register MagickOffsetType
3980 #if !defined(MAGICKCORE_HAVE_PREAD)
3981 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3982 return((MagickOffsetType) -1);
3985 for (i=0; i < (MagickOffsetType) length; i+=count)
3987 #if !defined(MAGICKCORE_HAVE_PREAD)
3988 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3989 (MagickSizeType) SSIZE_MAX));
3991 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
3992 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
4004 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4005 NexusInfo *nexus_info,ExceptionInfo *exception)
4018 register unsigned char
4024 if (cache_info->metacontent_extent == 0)
4025 return(MagickFalse);
4026 if (nexus_info->authentic_cache != MagickFalse)
4028 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4029 nexus_info->region.x;
4030 length=(MagickSizeType) nexus_info->region.width*
4031 cache_info->metacontent_extent;
4032 extent=length*nexus_info->region.height;
4033 rows=nexus_info->region.height;
4035 q=(unsigned char *) nexus_info->metacontent;
4036 switch (cache_info->type)
4041 register unsigned char
4045 Read meta-content from memory.
4047 if ((cache_info->columns == nexus_info->region.width) &&
4048 (extent == (MagickSizeType) ((size_t) extent)))
4053 p=(unsigned char *) cache_info->metacontent+offset*
4054 cache_info->metacontent_extent;
4055 for (y=0; y < (ssize_t) rows; y++)
4057 (void) memcpy(q,p,(size_t) length);
4058 p+=cache_info->metacontent_extent*cache_info->columns;
4059 q+=cache_info->metacontent_extent*nexus_info->region.width;
4066 Read meta content from disk.
4068 LockSemaphoreInfo(cache_info->file_semaphore);
4069 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4071 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4072 cache_info->cache_filename);
4073 UnlockSemaphoreInfo(cache_info->file_semaphore);
4074 return(MagickFalse);
4076 if ((cache_info->columns == nexus_info->region.width) &&
4077 (extent <= MagickMaxBufferExtent))
4082 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4083 for (y=0; y < (ssize_t) rows; y++)
4085 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4086 cache_info->number_channels*sizeof(Quantum)+offset*
4087 cache_info->metacontent_extent,length,(unsigned char *) q);
4088 if (count != (MagickOffsetType) length)
4090 offset+=cache_info->columns;
4091 q+=cache_info->metacontent_extent*nexus_info->region.width;
4093 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4094 (void) ClosePixelCacheOnDisk(cache_info);
4095 UnlockSemaphoreInfo(cache_info->file_semaphore);
4098 case DistributedCache:
4104 Read metacontent from distributed cache.
4106 LockSemaphoreInfo(cache_info->file_semaphore);
4107 region=nexus_info->region;
4108 if ((cache_info->columns != nexus_info->region.width) ||
4109 (extent > MagickMaxBufferExtent))
4116 for (y=0; y < (ssize_t) rows; y++)
4118 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4119 cache_info->server_info,®ion,length,(unsigned char *) q);
4120 if (count != (MagickOffsetType) length)
4122 q+=cache_info->metacontent_extent*nexus_info->region.width;
4125 UnlockSemaphoreInfo(cache_info->file_semaphore);
4131 if (y < (ssize_t) rows)
4133 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4134 cache_info->cache_filename);
4135 return(MagickFalse);
4137 if ((cache_info->debug != MagickFalse) &&
4138 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4139 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4140 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4141 nexus_info->region.width,(double) nexus_info->region.height,(double)
4142 nexus_info->region.x,(double) nexus_info->region.y);
4147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4151 + R e a d P i x e l C a c h e P i x e l s %
4155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4157 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4160 % The format of the ReadPixelCachePixels() method is:
4162 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4163 % NexusInfo *nexus_info,ExceptionInfo *exception)
4165 % A description of each parameter follows:
4167 % o cache_info: the pixel cache.
4169 % o nexus_info: the cache nexus to read the pixels.
4171 % o exception: return any errors or warnings in this structure.
4174 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4175 NexusInfo *nexus_info,ExceptionInfo *exception)
4194 if (nexus_info->authentic_cache != MagickFalse)
4196 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4197 nexus_info->region.x;
4198 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4200 extent=length*nexus_info->region.height;
4201 rows=nexus_info->region.height;
4203 q=nexus_info->pixels;
4204 switch (cache_info->type)
4213 Read pixels from memory.
4215 if ((cache_info->columns == nexus_info->region.width) &&
4216 (extent == (MagickSizeType) ((size_t) extent)))
4221 p=cache_info->pixels+offset*cache_info->number_channels;
4222 for (y=0; y < (ssize_t) rows; y++)
4224 (void) memcpy(q,p,(size_t) length);
4225 p+=cache_info->number_channels*cache_info->columns;
4226 q+=cache_info->number_channels*nexus_info->region.width;
4233 Read pixels from disk.
4235 LockSemaphoreInfo(cache_info->file_semaphore);
4236 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4238 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4239 cache_info->cache_filename);
4240 UnlockSemaphoreInfo(cache_info->file_semaphore);
4241 return(MagickFalse);
4243 if ((cache_info->columns == nexus_info->region.width) &&
4244 (extent <= MagickMaxBufferExtent))
4249 for (y=0; y < (ssize_t) rows; y++)
4251 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4252 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4253 if (count != (MagickOffsetType) length)
4255 offset+=cache_info->columns;
4256 q+=cache_info->number_channels*nexus_info->region.width;
4258 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4259 (void) ClosePixelCacheOnDisk(cache_info);
4260 UnlockSemaphoreInfo(cache_info->file_semaphore);
4263 case DistributedCache:
4269 Read pixels from distributed cache.
4271 LockSemaphoreInfo(cache_info->file_semaphore);
4272 region=nexus_info->region;
4273 if ((cache_info->columns != nexus_info->region.width) ||
4274 (extent > MagickMaxBufferExtent))
4281 for (y=0; y < (ssize_t) rows; y++)
4283 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4284 cache_info->server_info,®ion,length,(unsigned char *) q);
4285 if (count != (MagickOffsetType) length)
4287 q+=cache_info->number_channels*nexus_info->region.width;
4290 UnlockSemaphoreInfo(cache_info->file_semaphore);
4296 if (y < (ssize_t) rows)
4298 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4299 cache_info->cache_filename);
4300 return(MagickFalse);
4302 if ((cache_info->debug != MagickFalse) &&
4303 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4304 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4305 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4306 nexus_info->region.width,(double) nexus_info->region.height,(double)
4307 nexus_info->region.x,(double) nexus_info->region.y);
4312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4316 + R e f e r e n c e P i x e l C a c h e %
4320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4322 % ReferencePixelCache() increments the reference count associated with the
4323 % pixel cache returning a pointer to the cache.
4325 % The format of the ReferencePixelCache method is:
4327 % Cache ReferencePixelCache(Cache cache_info)
4329 % A description of each parameter follows:
4331 % o cache_info: the pixel cache.
4334 MagickPrivate Cache ReferencePixelCache(Cache cache)
4339 assert(cache != (Cache *) NULL);
4340 cache_info=(CacheInfo *) cache;
4341 assert(cache_info->signature == MagickSignature);
4342 LockSemaphoreInfo(cache_info->semaphore);
4343 cache_info->reference_count++;
4344 UnlockSemaphoreInfo(cache_info->semaphore);
4349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4353 + S e t P i x e l C a c h e M e t h o d s %
4357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4359 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4361 % The format of the SetPixelCacheMethods() method is:
4363 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4365 % A description of each parameter follows:
4367 % o cache: the pixel cache.
4369 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4372 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4377 GetOneAuthenticPixelFromHandler
4378 get_one_authentic_pixel_from_handler;
4380 GetOneVirtualPixelFromHandler
4381 get_one_virtual_pixel_from_handler;
4384 Set cache pixel methods.
4386 assert(cache != (Cache) NULL);
4387 assert(cache_methods != (CacheMethods *) NULL);
4388 cache_info=(CacheInfo *) cache;
4389 assert(cache_info->signature == MagickSignature);
4390 if (cache_info->debug != MagickFalse)
4391 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4392 cache_info->filename);
4393 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4394 cache_info->methods.get_virtual_pixel_handler=
4395 cache_methods->get_virtual_pixel_handler;
4396 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4397 cache_info->methods.destroy_pixel_handler=
4398 cache_methods->destroy_pixel_handler;
4399 if (cache_methods->get_virtual_metacontent_from_handler !=
4400 (GetVirtualMetacontentFromHandler) NULL)
4401 cache_info->methods.get_virtual_metacontent_from_handler=
4402 cache_methods->get_virtual_metacontent_from_handler;
4403 if (cache_methods->get_authentic_pixels_handler !=
4404 (GetAuthenticPixelsHandler) NULL)
4405 cache_info->methods.get_authentic_pixels_handler=
4406 cache_methods->get_authentic_pixels_handler;
4407 if (cache_methods->queue_authentic_pixels_handler !=
4408 (QueueAuthenticPixelsHandler) NULL)
4409 cache_info->methods.queue_authentic_pixels_handler=
4410 cache_methods->queue_authentic_pixels_handler;
4411 if (cache_methods->sync_authentic_pixels_handler !=
4412 (SyncAuthenticPixelsHandler) NULL)
4413 cache_info->methods.sync_authentic_pixels_handler=
4414 cache_methods->sync_authentic_pixels_handler;
4415 if (cache_methods->get_authentic_pixels_from_handler !=
4416 (GetAuthenticPixelsFromHandler) NULL)
4417 cache_info->methods.get_authentic_pixels_from_handler=
4418 cache_methods->get_authentic_pixels_from_handler;
4419 if (cache_methods->get_authentic_metacontent_from_handler !=
4420 (GetAuthenticMetacontentFromHandler) NULL)
4421 cache_info->methods.get_authentic_metacontent_from_handler=
4422 cache_methods->get_authentic_metacontent_from_handler;
4423 get_one_virtual_pixel_from_handler=
4424 cache_info->methods.get_one_virtual_pixel_from_handler;
4425 if (get_one_virtual_pixel_from_handler !=
4426 (GetOneVirtualPixelFromHandler) NULL)
4427 cache_info->methods.get_one_virtual_pixel_from_handler=
4428 cache_methods->get_one_virtual_pixel_from_handler;
4429 get_one_authentic_pixel_from_handler=
4430 cache_methods->get_one_authentic_pixel_from_handler;
4431 if (get_one_authentic_pixel_from_handler !=
4432 (GetOneAuthenticPixelFromHandler) NULL)
4433 cache_info->methods.get_one_authentic_pixel_from_handler=
4434 cache_methods->get_one_authentic_pixel_from_handler;
4438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4442 + S e t P i x e l C a c h e N e x u s P i x e l s %
4446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4448 % SetPixelCacheNexusPixels() defines the region of the cache for the
4449 % specified cache nexus.
4451 % The format of the SetPixelCacheNexusPixels() method is:
4453 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4454 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4455 % ExceptionInfo *exception)
4457 % A description of each parameter follows:
4459 % o cache_info: the pixel cache.
4461 % o mode: ReadMode, WriteMode, or IOMode.
4463 % o region: A pointer to the RectangleInfo structure that defines the
4464 % region of this particular cache nexus.
4466 % o nexus_info: the cache nexus to set.
4468 % o exception: return any errors or warnings in this structure.
4472 static inline MagickBooleanType AcquireCacheNexusPixels(
4473 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4474 ExceptionInfo *exception)
4476 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4477 return(MagickFalse);
4478 nexus_info->mapped=MagickFalse;
4479 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4480 (size_t) nexus_info->length));
4481 if (nexus_info->cache == (Quantum *) NULL)
4483 nexus_info->mapped=MagickTrue;
4484 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4485 nexus_info->length);
4487 if (nexus_info->cache == (Quantum *) NULL)
4489 (void) ThrowMagickException(exception,GetMagickModule(),
4490 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4491 cache_info->filename);
4492 return(MagickFalse);
4497 static inline MagickBooleanType IsAuthenticCache(
4498 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
4503 if (cache_info->type == PingCache)
4505 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4506 nexus_info->region.x;
4507 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
4511 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4514 if (mode == ReadMode)
4516 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4519 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4522 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4523 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4524 ExceptionInfo *exception)
4533 assert(cache_info != (const CacheInfo *) NULL);
4534 assert(cache_info->signature == MagickSignature);
4535 if (cache_info->type == UndefinedCache)
4536 return((Quantum *) NULL);
4537 nexus_info->region=(*region);
4538 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4544 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4545 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4546 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4547 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4548 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4549 ((nexus_info->region.width == cache_info->columns) ||
4550 ((nexus_info->region.width % cache_info->columns) == 0)))))
4556 Pixels are accessed directly from memory.
4558 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4559 nexus_info->region.x;
4560 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4562 nexus_info->metacontent=(void *) NULL;
4563 if (cache_info->metacontent_extent != 0)
4564 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4565 offset*cache_info->metacontent_extent;
4566 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4567 nexus_info->authentic_cache=IsAuthenticCache(cache_info,nexus_info);
4568 return(nexus_info->pixels);
4572 Pixels are stored in a staging region until they are synced to the cache.
4574 number_pixels=(MagickSizeType) nexus_info->region.width*
4575 nexus_info->region.height;
4576 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4577 if (cache_info->metacontent_extent != 0)
4578 length+=number_pixels*cache_info->metacontent_extent;
4579 if (nexus_info->cache == (Quantum *) NULL)
4581 nexus_info->length=length;
4582 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4583 if (status == MagickFalse)
4585 nexus_info->length=0;
4586 return((Quantum *) NULL);
4590 if (nexus_info->length < length)
4592 RelinquishCacheNexusPixels(nexus_info);
4593 nexus_info->length=length;
4594 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4595 if (status == MagickFalse)
4597 nexus_info->length=0;
4598 return((Quantum *) NULL);
4601 nexus_info->pixels=nexus_info->cache;
4602 nexus_info->metacontent=(void *) NULL;
4603 if (cache_info->metacontent_extent != 0)
4604 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4605 cache_info->number_channels);
4606 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4607 nexus_info->authentic_cache=IsAuthenticCache(cache_info,nexus_info);
4608 return(nexus_info->pixels);
4612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4616 % 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 %
4620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4622 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4623 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4624 % access that is outside the boundaries of the image cache.
4626 % The format of the SetPixelCacheVirtualMethod() method is:
4628 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4629 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4631 % A description of each parameter follows:
4633 % o image: the image.
4635 % o virtual_pixel_method: choose the type of virtual pixel.
4637 % o exception: return any errors or warnings in this structure.
4641 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4642 ExceptionInfo *exception)
4656 assert(image != (Image *) NULL);
4657 assert(image->signature == MagickSignature);
4658 if (image->debug != MagickFalse)
4659 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4660 assert(image->cache != (Cache) NULL);
4661 cache_info=(CacheInfo *) image->cache;
4662 assert(cache_info->signature == MagickSignature);
4663 image->alpha_trait=BlendPixelTrait;
4665 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4666 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4667 #pragma omp parallel for schedule(static,4) shared(status) \
4668 magick_threads(image,image,1,1)
4670 for (y=0; y < (ssize_t) image->rows; y++)
4678 if (status == MagickFalse)
4680 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4681 if (q == (Quantum *) NULL)
4686 for (x=0; x < (ssize_t) image->columns; x++)
4688 SetPixelAlpha(image,alpha,q);
4689 q+=GetPixelChannels(image);
4691 status=SyncCacheViewAuthenticPixels(image_view,exception);
4693 image_view=DestroyCacheView(image_view);
4697 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4698 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4706 assert(image != (Image *) NULL);
4707 assert(image->signature == MagickSignature);
4708 if (image->debug != MagickFalse)
4709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4710 assert(image->cache != (Cache) NULL);
4711 cache_info=(CacheInfo *) image->cache;
4712 assert(cache_info->signature == MagickSignature);
4713 method=cache_info->virtual_pixel_method;
4714 cache_info->virtual_pixel_method=virtual_pixel_method;
4715 if ((image->columns != 0) && (image->rows != 0))
4716 switch (virtual_pixel_method)
4718 case BackgroundVirtualPixelMethod:
4720 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4721 (image->alpha_trait != BlendPixelTrait))
4722 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4723 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4724 (IsGrayColorspace(image->colorspace) != MagickFalse))
4725 (void) SetImageColorspace(image,sRGBColorspace,exception);
4728 case TransparentVirtualPixelMethod:
4730 if (image->alpha_trait != BlendPixelTrait)
4731 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4745 + 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 %
4749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4751 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4752 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4753 % is synced, otherwise MagickFalse.
4755 % The format of the SyncAuthenticPixelCacheNexus() method is:
4757 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4758 % NexusInfo *nexus_info,ExceptionInfo *exception)
4760 % A description of each parameter follows:
4762 % o image: the image.
4764 % o nexus_info: the cache nexus to sync.
4766 % o exception: return any errors or warnings in this structure.
4769 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4770 NexusInfo *nexus_info,ExceptionInfo *exception)
4779 Transfer pixels to the cache.
4781 assert(image != (Image *) NULL);
4782 assert(image->signature == MagickSignature);
4783 if (image->cache == (Cache) NULL)
4784 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4785 cache_info=(CacheInfo *) image->cache;
4786 assert(cache_info->signature == MagickSignature);
4787 if (cache_info->type == UndefinedCache)
4788 return(MagickFalse);
4789 if (nexus_info->authentic_cache != MagickFalse)
4791 assert(cache_info->signature == MagickSignature);
4792 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4793 if ((cache_info->metacontent_extent != 0) &&
4794 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4795 return(MagickFalse);
4800 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4804 + S y n c A u t h e n t i c P i x e l C a c h e %
4808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4810 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4811 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4812 % otherwise MagickFalse.
4814 % The format of the SyncAuthenticPixelsCache() method is:
4816 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4817 % ExceptionInfo *exception)
4819 % A description of each parameter follows:
4821 % o image: the image.
4823 % o exception: return any errors or warnings in this structure.
4826 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
4827 ExceptionInfo *exception)
4833 id = GetOpenMPThreadId();
4838 assert(image != (Image *) NULL);
4839 assert(image->signature == MagickSignature);
4840 assert(image->cache != (Cache) NULL);
4841 cache_info=(CacheInfo *) image->cache;
4842 assert(cache_info->signature == MagickSignature);
4843 assert(id < (int) cache_info->number_threads);
4844 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4854 % S y n c A u t h e n t i c P i x e l s %
4858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4860 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
4861 % The method returns MagickTrue if the pixel region is flushed, otherwise
4864 % The format of the SyncAuthenticPixels() method is:
4866 % MagickBooleanType SyncAuthenticPixels(Image *image,
4867 % ExceptionInfo *exception)
4869 % A description of each parameter follows:
4871 % o image: the image.
4873 % o exception: return any errors or warnings in this structure.
4876 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
4877 ExceptionInfo *exception)
4883 id = GetOpenMPThreadId();
4888 assert(image != (Image *) NULL);
4889 assert(image->signature == MagickSignature);
4890 assert(image->cache != (Cache) NULL);
4891 cache_info=(CacheInfo *) image->cache;
4892 assert(cache_info->signature == MagickSignature);
4893 if (cache_info->methods.sync_authentic_pixels_handler !=
4894 (SyncAuthenticPixelsHandler) NULL)
4896 status=cache_info->methods.sync_authentic_pixels_handler(image,
4900 assert(id < (int) cache_info->number_threads);
4901 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4911 + S y n c I m a g e P i x e l C a c h e %
4915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4917 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
4918 % The method returns MagickTrue if the pixel region is flushed, otherwise
4921 % The format of the SyncImagePixelCache() method is:
4923 % MagickBooleanType SyncImagePixelCache(Image *image,
4924 % ExceptionInfo *exception)
4926 % A description of each parameter follows:
4928 % o image: the image.
4930 % o exception: return any errors or warnings in this structure.
4933 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
4934 ExceptionInfo *exception)
4939 assert(image != (Image *) NULL);
4940 assert(exception != (ExceptionInfo *) NULL);
4941 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4942 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
4946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4950 + 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 %
4954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4956 % WritePixelCacheMetacontent() writes the meta-content to the specified region
4957 % of the pixel cache.
4959 % The format of the WritePixelCacheMetacontent() method is:
4961 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4962 % NexusInfo *nexus_info,ExceptionInfo *exception)
4964 % A description of each parameter follows:
4966 % o cache_info: the pixel cache.
4968 % o nexus_info: the cache nexus to write the meta-content.
4970 % o exception: return any errors or warnings in this structure.
4973 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
4974 NexusInfo *nexus_info,ExceptionInfo *exception)
4984 register const unsigned char
4993 if (cache_info->metacontent_extent == 0)
4994 return(MagickFalse);
4995 if (nexus_info->authentic_cache != MagickFalse)
4997 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4998 nexus_info->region.x;
4999 length=(MagickSizeType) nexus_info->region.width*
5000 cache_info->metacontent_extent;
5001 extent=(MagickSizeType) length*nexus_info->region.height;
5002 rows=nexus_info->region.height;
5004 p=(unsigned char *) nexus_info->metacontent;
5005 switch (cache_info->type)
5010 register unsigned char
5014 Write associated pixels to memory.
5016 if ((cache_info->columns == nexus_info->region.width) &&
5017 (extent == (MagickSizeType) ((size_t) extent)))
5022 q=(unsigned char *) cache_info->metacontent+offset*
5023 cache_info->metacontent_extent;
5024 for (y=0; y < (ssize_t) rows; y++)
5026 (void) memcpy(q,p,(size_t) length);
5027 p+=nexus_info->region.width*cache_info->metacontent_extent;
5028 q+=cache_info->columns*cache_info->metacontent_extent;
5035 Write associated pixels to disk.
5037 LockSemaphoreInfo(cache_info->file_semaphore);
5038 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5040 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5041 cache_info->cache_filename);
5042 UnlockSemaphoreInfo(cache_info->file_semaphore);
5043 return(MagickFalse);
5045 if ((cache_info->columns == nexus_info->region.width) &&
5046 (extent <= MagickMaxBufferExtent))
5051 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5052 for (y=0; y < (ssize_t) rows; y++)
5054 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5055 cache_info->number_channels*sizeof(Quantum)+offset*
5056 cache_info->metacontent_extent,length,(const unsigned char *) p);
5057 if (count != (MagickOffsetType) length)
5059 p+=cache_info->metacontent_extent*nexus_info->region.width;
5060 offset+=cache_info->columns;
5062 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5063 (void) ClosePixelCacheOnDisk(cache_info);
5064 UnlockSemaphoreInfo(cache_info->file_semaphore);
5067 case DistributedCache:
5073 Write metacontent to distributed cache.
5075 LockSemaphoreInfo(cache_info->file_semaphore);
5076 region=nexus_info->region;
5077 if ((cache_info->columns != nexus_info->region.width) ||
5078 (extent > MagickMaxBufferExtent))
5085 for (y=0; y < (ssize_t) rows; y++)
5087 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5088 cache_info->server_info,®ion,length,(const unsigned char *) p);
5089 if (count != (MagickOffsetType) length)
5091 p+=cache_info->metacontent_extent*nexus_info->region.width;
5094 UnlockSemaphoreInfo(cache_info->file_semaphore);
5100 if (y < (ssize_t) rows)
5102 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5103 cache_info->cache_filename);
5104 return(MagickFalse);
5106 if ((cache_info->debug != MagickFalse) &&
5107 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5108 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5109 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5110 nexus_info->region.width,(double) nexus_info->region.height,(double)
5111 nexus_info->region.x,(double) nexus_info->region.y);
5116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5120 + W r i t e C a c h e P i x e l s %
5124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5126 % WritePixelCachePixels() writes image pixels to the specified region of the
5129 % The format of the WritePixelCachePixels() method is:
5131 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5132 % NexusInfo *nexus_info,ExceptionInfo *exception)
5134 % A description of each parameter follows:
5136 % o cache_info: the pixel cache.
5138 % o nexus_info: the cache nexus to write the pixels.
5140 % o exception: return any errors or warnings in this structure.
5143 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5144 NexusInfo *nexus_info,ExceptionInfo *exception)
5154 register const Quantum
5163 if (nexus_info->authentic_cache != MagickFalse)
5165 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5166 nexus_info->region.x;
5167 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5169 extent=length*nexus_info->region.height;
5170 rows=nexus_info->region.height;
5172 p=nexus_info->pixels;
5173 switch (cache_info->type)
5182 Write pixels to memory.
5184 if ((cache_info->columns == nexus_info->region.width) &&
5185 (extent == (MagickSizeType) ((size_t) extent)))
5190 q=cache_info->pixels+offset*cache_info->number_channels;
5191 for (y=0; y < (ssize_t) rows; y++)
5193 (void) memcpy(q,p,(size_t) length);
5194 p+=cache_info->number_channels*nexus_info->region.width;
5195 q+=cache_info->columns*cache_info->number_channels;
5202 Write pixels to disk.
5204 LockSemaphoreInfo(cache_info->file_semaphore);
5205 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5207 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5208 cache_info->cache_filename);
5209 UnlockSemaphoreInfo(cache_info->file_semaphore);
5210 return(MagickFalse);
5212 if ((cache_info->columns == nexus_info->region.width) &&
5213 (extent <= MagickMaxBufferExtent))
5218 for (y=0; y < (ssize_t) rows; y++)
5220 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5221 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5223 if (count != (MagickOffsetType) length)
5225 p+=cache_info->number_channels*nexus_info->region.width;
5226 offset+=cache_info->columns;
5228 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5229 (void) ClosePixelCacheOnDisk(cache_info);
5230 UnlockSemaphoreInfo(cache_info->file_semaphore);
5233 case DistributedCache:
5239 Write pixels to distributed cache.
5241 LockSemaphoreInfo(cache_info->file_semaphore);
5242 region=nexus_info->region;
5243 if ((cache_info->columns != nexus_info->region.width) ||
5244 (extent > MagickMaxBufferExtent))
5251 for (y=0; y < (ssize_t) rows; y++)
5253 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5254 cache_info->server_info,®ion,length,(const unsigned char *) p);
5255 if (count != (MagickOffsetType) length)
5257 p+=cache_info->number_channels*nexus_info->region.width;
5260 UnlockSemaphoreInfo(cache_info->file_semaphore);
5266 if (y < (ssize_t) rows)
5268 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5269 cache_info->cache_filename);
5270 return(MagickFalse);
5272 if ((cache_info->debug != MagickFalse) &&
5273 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5274 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5275 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5276 nexus_info->region.width,(double) nexus_info->region.height,(double)
5277 nexus_info->region.x,(double) nexus_info->region.y);