blob: e35c1bde934051ea1ab303bc46707f8accc75f1b [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
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. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#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/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78
79/*
cristy3ed852e2009-09-05 21:47:34 +000080 Typedef declarations.
81*/
82typedef struct _MagickModulo
83{
cristybb503372010-05-27 20:51:26 +000084 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000085 quotient,
86 remainder;
87} MagickModulo;
88
89struct _NexusInfo
90{
91 MagickBooleanType
92 mapped;
93
94 RectangleInfo
95 region;
96
97 MagickSizeType
98 length;
99
cristy4c08aed2011-07-01 19:47:50 +0000100 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000101 *cache,
102 *pixels;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 void
105 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000106
cristybb503372010-05-27 20:51:26 +0000107 size_t
cristy3ed852e2009-09-05 21:47:34 +0000108 signature;
109};
110
111/*
112 Forward declarations.
113*/
114#if defined(__cplusplus) || defined(c_plusplus)
115extern "C" {
116#endif
117
cristy4c08aed2011-07-01 19:47:50 +0000118static const Quantum
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
cristy4c08aed2011-07-01 19:47:50 +0000123static const void
124 *GetVirtualMetacontentFromCache(const Image *);
125
cristy3ed852e2009-09-05 21:47:34 +0000126static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000128 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
137
cristy4c08aed2011-07-01 19:47:50 +0000138static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000144 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146#if defined(__cplusplus) || defined(c_plusplus)
147}
148#endif
149
150/*
151 Global declarations.
152*/
153static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
155
156static SemaphoreInfo
157 *cache_semaphore = (SemaphoreInfo *) NULL;
158
159static SplayTreeInfo
160 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167+ A c q u i r e P i x e l C a c h e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquirePixelCache() acquires a pixel cache.
174%
175% The format of the AcquirePixelCache() method is:
176%
cristybb503372010-05-27 20:51:26 +0000177% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178%
179% A description of each parameter follows:
180%
181% o number_threads: the number of nexus threads.
182%
183*/
cristya6577ff2011-09-02 19:54:26 +0000184MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000185{
186 CacheInfo
187 *cache_info;
188
cristya64b85d2011-09-14 01:02:31 +0000189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000194 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristya6577ff2011-09-02 19:54:26 +0000250MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristya64b85d2011-09-14 01:02:31 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy7dc8ac52012-01-10 20:14:52 +0000264 nexus_info[i]=(NexusInfo *) AcquireQuantumMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
cristyd1dd6e42011-09-04 01:46:08 +0000301MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
cristy5ff4eaf2011-09-03 01:38:02 +0000339MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
cristy5ff4eaf2011-09-03 01:38:02 +0000363MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000387% mask. It returns MagickTrue if the pixel region is clipped, otherwise
388% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
cristy4c08aed2011-07-01 19:47:50 +0000417 register const Quantum
418 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristy4c08aed2011-07-01 19:47:50 +0000421 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristye076a6e2010-08-15 19:59:43 +0000424 register ssize_t
cristy12006112012-01-02 17:06:42 +0000425 x;
cristye076a6e2010-08-15 19:59:43 +0000426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
cristyc57486d2012-01-02 17:46:50 +0000428 Clip the image as defined by the clipping mask.
cristy3ed852e2009-09-05 21:47:34 +0000429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000434 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy12006112012-01-02 17:06:42 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
443 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
444 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000445 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
cristy12006112012-01-02 17:06:42 +0000451 for (x=0; x < (ssize_t) number_pixels; x++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy12006112012-01-02 17:06:42 +0000453 register ssize_t
454 i;
455
cristy4c08aed2011-07-01 19:47:50 +0000456 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000457 break;
cristy12006112012-01-02 17:06:42 +0000458 if (GetPixelIntensity(image->clip_mask,r) > ((Quantum) QuantumRange/2))
459 for (i=0; i < (ssize_t) image->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000460 {
cristy12006112012-01-02 17:06:42 +0000461 PixelChannel
462 channel;
463
464 PixelTrait
465 traits;
466
467 channel=GetPixelChannelMapChannel(image,i);
468 traits=GetPixelChannelMapTraits(image,channel);
cristyc57486d2012-01-02 17:46:50 +0000469 if (traits == UndefinedPixelTrait)
470 continue;
471 q[i]=p[i];
cristy3ed852e2009-09-05 21:47:34 +0000472 }
cristyed231572011-07-14 02:18:59 +0000473 p+=GetPixelChannels(image);
474 q+=GetPixelChannels(image);
475 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000476 }
477 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
478 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristy12006112012-01-02 17:06:42 +0000479 if (x < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000480 return(MagickFalse);
481 return(MagickTrue);
482}
483
484/*
485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486% %
487% %
488% %
489+ C l o n e P i x e l C a c h e %
490% %
491% %
492% %
493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494%
495% ClonePixelCache() clones a pixel cache.
496%
497% The format of the ClonePixelCache() method is:
498%
499% Cache ClonePixelCache(const Cache cache)
500%
501% A description of each parameter follows:
502%
503% o cache: the pixel cache.
504%
505*/
cristya6577ff2011-09-02 19:54:26 +0000506MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000507{
508 CacheInfo
509 *clone_info;
510
511 const CacheInfo
512 *cache_info;
513
cristy9f027d12011-09-21 01:17:17 +0000514 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000515 cache_info=(const CacheInfo *) cache;
516 assert(cache_info->signature == MagickSignature);
517 if (cache_info->debug != MagickFalse)
518 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
519 cache_info->filename);
520 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
521 if (clone_info == (Cache) NULL)
522 return((Cache) NULL);
523 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
524 return((Cache ) clone_info);
525}
526
527/*
528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
529% %
530% %
531% %
cristy60c44a82009-10-07 00:58:49 +0000532+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000533% %
534% %
535% %
536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
537% ClonePixelCachePixels() clones the source pixel cache to the destination
538% cache.
539%
540% The format of the ClonePixelCachePixels() method is:
541%
542% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
543% CacheInfo *source_info,ExceptionInfo *exception)
544%
545% A description of each parameter follows:
546%
547% o cache_info: the pixel cache.
548%
549% o source_info: the source pixel cache.
550%
551% o exception: return any errors or warnings in this structure.
552%
553*/
554
555static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
556{
557 int
558 status;
559
cristy5ee247a2010-02-12 15:42:34 +0000560 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000561 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000562 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000563 {
564 status=close(cache_info->file);
565 cache_info->file=(-1);
566 RelinquishMagickResource(FileResource,1);
567 }
cristyf84a1932010-01-03 18:00:18 +0000568 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000569 return(status == -1 ? MagickFalse : MagickTrue);
570}
571
572static void LimitPixelCacheDescriptors(void)
573{
574 register CacheInfo
575 *p,
576 *q;
577
578 /*
579 Limit # of open file descriptors.
580 */
581 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
582 return;
cristyf84a1932010-01-03 18:00:18 +0000583 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000584 if (cache_resources == (SplayTreeInfo *) NULL)
585 {
cristyf84a1932010-01-03 18:00:18 +0000586 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000587 return;
588 }
589 ResetSplayTreeIterator(cache_resources);
590 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
591 while (p != (CacheInfo *) NULL)
592 {
593 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000594 break;
cristy3ed852e2009-09-05 21:47:34 +0000595 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
596 }
597 for (q=p; p != (CacheInfo *) NULL; )
598 {
599 if ((p->type == DiskCache) && (p->file != -1) &&
600 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000601 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000602 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
603 }
604 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000605 {
606 /*
607 Close least recently used cache.
608 */
609 (void) close(q->file);
610 q->file=(-1);
611 }
cristyf84a1932010-01-03 18:00:18 +0000612 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000613}
614
615static inline MagickSizeType MagickMax(const MagickSizeType x,
616 const MagickSizeType y)
617{
618 if (x > y)
619 return(x);
620 return(y);
621}
622
623static inline MagickSizeType MagickMin(const MagickSizeType x,
624 const MagickSizeType y)
625{
626 if (x < y)
627 return(x);
628 return(y);
629}
630
631static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
632 const MapMode mode)
633{
634 int
635 file;
636
637 /*
638 Open pixel cache on disk.
639 */
cristyf84a1932010-01-03 18:00:18 +0000640 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000641 if (cache_info->file != -1)
642 {
cristyf84a1932010-01-03 18:00:18 +0000643 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000644 return(MagickTrue); /* cache already open */
645 }
646 LimitPixelCacheDescriptors();
647 if (*cache_info->cache_filename == '\0')
648 file=AcquireUniqueFileResource(cache_info->cache_filename);
649 else
650 switch (mode)
651 {
652 case ReadMode:
653 {
cristy18c6c272011-09-23 14:40:37 +0000654 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000655 break;
656 }
657 case WriteMode:
658 {
cristy18c6c272011-09-23 14:40:37 +0000659 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
660 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000661 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000662 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
664 }
665 case IOMode:
666 default:
667 {
cristy18c6c272011-09-23 14:40:37 +0000668 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000669 O_EXCL,S_MODE);
670 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000671 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000672 break;
673 }
674 }
675 if (file == -1)
676 {
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickFalse);
679 }
680 (void) AcquireMagickResource(FileResource,1);
681 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000682 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000683 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000684 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000685 return(MagickTrue);
686}
687
688static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
689 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000690 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000691{
692 register MagickOffsetType
693 i;
694
695 ssize_t
696 count;
697
cristy08a88202010-03-04 19:18:05 +0000698 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000699#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000700 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000701 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000702 {
cristyf84a1932010-01-03 18:00:18 +0000703 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000704 return((MagickOffsetType) -1);
705 }
706#endif
707 count=0;
708 for (i=0; i < (MagickOffsetType) length; i+=count)
709 {
710#if !defined(MAGICKCORE_HAVE_PREAD)
711 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
712 (MagickSizeType) SSIZE_MAX));
713#else
714 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000715 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000716#endif
717 if (count > 0)
718 continue;
719 count=0;
720 if (errno != EINTR)
721 {
722 i=(-1);
723 break;
724 }
725 }
726#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000727 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000728#endif
729 return(i);
730}
731
732static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
733 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000734 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000735{
736 register MagickOffsetType
737 i;
738
739 ssize_t
740 count;
741
cristy08a88202010-03-04 19:18:05 +0000742 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000743#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000744 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000745 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000746 {
cristyf84a1932010-01-03 18:00:18 +0000747 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000748 return((MagickOffsetType) -1);
749 }
750#endif
751 count=0;
752 for (i=0; i < (MagickOffsetType) length; i+=count)
753 {
754#if !defined(MAGICKCORE_HAVE_PWRITE)
755 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
756 (MagickSizeType) SSIZE_MAX));
757#else
758 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000759 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000760#endif
761 if (count > 0)
762 continue;
763 count=0;
764 if (errno != EINTR)
765 {
766 i=(-1);
767 break;
768 }
769 }
770#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000771 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000772#endif
773 return(i);
774}
775
cristy4c08aed2011-07-01 19:47:50 +0000776static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000777 CacheInfo *cache_info,ExceptionInfo *exception)
778{
779 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000780 count;
cristy3ed852e2009-09-05 21:47:34 +0000781
cristy4c08aed2011-07-01 19:47:50 +0000782 register MagickOffsetType
783 i;
cristye076a6e2010-08-15 19:59:43 +0000784
cristybb503372010-05-27 20:51:26 +0000785 size_t
cristy4c08aed2011-07-01 19:47:50 +0000786 length;
cristy3ed852e2009-09-05 21:47:34 +0000787
cristy4c08aed2011-07-01 19:47:50 +0000788 unsigned char
789 *blob;
790
791 /*
792 Clone pixel cache (both caches on disk).
793 */
cristy3ed852e2009-09-05 21:47:34 +0000794 if (cache_info->debug != MagickFalse)
795 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000796 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000797 sizeof(*blob));
798 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000799 {
cristy4c08aed2011-07-01 19:47:50 +0000800 (void) ThrowMagickException(exception,GetMagickModule(),
801 ResourceLimitError,"MemoryAllocationFailed","`%s'",
802 cache_info->filename);
803 return(MagickFalse);
804 }
cristy3dedf062011-07-02 14:07:40 +0000805 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000806 {
807 blob=(unsigned char *) RelinquishMagickMemory(blob);
808 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
809 cache_info->cache_filename);
810 return(MagickFalse);
811 }
cristy3dedf062011-07-02 14:07:40 +0000812 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000813 {
814 (void) ClosePixelCacheOnDisk(cache_info);
815 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000816 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
817 clone_info->cache_filename);
818 return(MagickFalse);
819 }
cristy4c08aed2011-07-01 19:47:50 +0000820 count=0;
821 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000822 {
cristy4c08aed2011-07-01 19:47:50 +0000823 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
824 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
825 blob);
826 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000827 {
cristy4c08aed2011-07-01 19:47:50 +0000828 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
829 cache_info->cache_filename);
830 break;
cristy3ed852e2009-09-05 21:47:34 +0000831 }
cristy4c08aed2011-07-01 19:47:50 +0000832 length=(size_t) count;
833 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
834 if ((MagickSizeType) count != length)
835 {
836 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
837 clone_info->cache_filename);
838 break;
839 }
840 }
841 (void) ClosePixelCacheOnDisk(clone_info);
842 (void) ClosePixelCacheOnDisk(cache_info);
843 blob=(unsigned char *) RelinquishMagickMemory(blob);
844 if (i < (MagickOffsetType) cache_info->length)
845 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000846 return(MagickTrue);
847}
848
cristyfd24a062012-01-02 14:46:34 +0000849static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000850 CacheInfo *cache_info,ExceptionInfo *exception)
851{
852 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000853 count;
cristy3ed852e2009-09-05 21:47:34 +0000854
cristy4c08aed2011-07-01 19:47:50 +0000855 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000856 {
cristy3ed852e2009-09-05 21:47:34 +0000857 /*
cristy4c08aed2011-07-01 19:47:50 +0000858 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000859 */
cristy4c08aed2011-07-01 19:47:50 +0000860 if (cache_info->debug != MagickFalse)
861 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
862 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
863 cache_info->length);
864 return(MagickTrue);
865 }
866 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
867 {
868 /*
869 Clone pixel cache (one cache on disk, one in memory).
870 */
871 if (cache_info->debug != MagickFalse)
872 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
873 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000874 {
cristy4c08aed2011-07-01 19:47:50 +0000875 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000876 cache_info->cache_filename);
877 return(MagickFalse);
878 }
cristy4c08aed2011-07-01 19:47:50 +0000879 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
880 cache_info->length,(unsigned char *) clone_info->pixels);
881 (void) ClosePixelCacheOnDisk(cache_info);
882 if ((MagickSizeType) count != cache_info->length)
883 {
884 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
885 cache_info->cache_filename);
886 return(MagickFalse);
887 }
888 return(MagickTrue);
889 }
890 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
891 {
892 /*
893 Clone pixel cache (one cache on disk, one in memory).
894 */
895 if (clone_info->debug != MagickFalse)
896 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
897 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
898 {
899 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
900 clone_info->cache_filename);
901 return(MagickFalse);
902 }
903 count=WritePixelCacheRegion(clone_info,clone_info->offset,
904 clone_info->length,(unsigned char *) cache_info->pixels);
905 (void) ClosePixelCacheOnDisk(clone_info);
906 if ((MagickSizeType) count != clone_info->length)
907 {
908 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
909 clone_info->cache_filename);
910 return(MagickFalse);
911 }
912 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000913 }
914 /*
cristy4c08aed2011-07-01 19:47:50 +0000915 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000916 */
cristy4c08aed2011-07-01 19:47:50 +0000917 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000918}
919
cristyfd24a062012-01-02 14:46:34 +0000920static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000921 CacheInfo *cache_info,ExceptionInfo *exception)
922{
cristy4c08aed2011-07-01 19:47:50 +0000923 MagickBooleanType
924 status;
cristy3ed852e2009-09-05 21:47:34 +0000925
cristy4c08aed2011-07-01 19:47:50 +0000926 MagickOffsetType
927 cache_offset,
928 clone_offset,
929 count;
930
931 register ssize_t
932 x;
933
cristyfd24a062012-01-02 14:46:34 +0000934 register unsigned char
935 *p;
936
cristy4c08aed2011-07-01 19:47:50 +0000937 size_t
cristy3ed852e2009-09-05 21:47:34 +0000938 length;
939
cristy4c08aed2011-07-01 19:47:50 +0000940 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000941 y;
942
cristy4c08aed2011-07-01 19:47:50 +0000943 unsigned char
944 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000945
cristy4c08aed2011-07-01 19:47:50 +0000946 /*
947 Clone pixel cache (unoptimized).
948 */
cristy3ed852e2009-09-05 21:47:34 +0000949 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000950 {
cristy4c08aed2011-07-01 19:47:50 +0000951 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
952 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
953 else
954 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
955 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
956 else
957 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
958 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
959 else
960 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
961 }
cristyed231572011-07-14 02:18:59 +0000962 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
963 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000964 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000965 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000966 if (blob == (unsigned char *) NULL)
967 {
968 (void) ThrowMagickException(exception,GetMagickModule(),
969 ResourceLimitError,"MemoryAllocationFailed","`%s'",
970 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000971 return(MagickFalse);
972 }
cristy4c08aed2011-07-01 19:47:50 +0000973 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
974 cache_offset=0;
975 clone_offset=0;
976 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000977 {
cristy4c08aed2011-07-01 19:47:50 +0000978 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000979 {
cristy4c08aed2011-07-01 19:47:50 +0000980 blob=(unsigned char *) RelinquishMagickMemory(blob);
981 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000982 cache_info->cache_filename);
983 return(MagickFalse);
984 }
cristy4c08aed2011-07-01 19:47:50 +0000985 cache_offset=cache_info->offset;
986 }
987 if (clone_info->type == DiskCache)
988 {
cristy3dedf062011-07-02 14:07:40 +0000989 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000990 {
cristy4c08aed2011-07-01 19:47:50 +0000991 blob=(unsigned char *) RelinquishMagickMemory(blob);
992 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
993 clone_info->cache_filename);
994 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000995 }
cristy4c08aed2011-07-01 19:47:50 +0000996 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000997 }
998 /*
cristy4c08aed2011-07-01 19:47:50 +0000999 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001000 */
cristy4c08aed2011-07-01 19:47:50 +00001001 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +00001002 p=blob;
cristy4c08aed2011-07-01 19:47:50 +00001003 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001004 {
cristy4c08aed2011-07-01 19:47:50 +00001005 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001006 {
cristy9e0719b2011-12-29 03:45:45 +00001007 register ssize_t
1008 i;
1009
cristy3ed852e2009-09-05 21:47:34 +00001010 /*
cristy4c08aed2011-07-01 19:47:50 +00001011 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001012 */
cristyed231572011-07-14 02:18:59 +00001013 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001014 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001015 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +00001016 else
1017 {
cristyfd24a062012-01-02 14:46:34 +00001018 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001019 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001020 {
cristy4c08aed2011-07-01 19:47:50 +00001021 status=MagickFalse;
1022 break;
cristy3ed852e2009-09-05 21:47:34 +00001023 }
1024 }
cristy4c08aed2011-07-01 19:47:50 +00001025 cache_offset+=length;
1026 if ((y < (ssize_t) clone_info->rows) &&
1027 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001028 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001029 {
cristy9e0719b2011-12-29 03:45:45 +00001030 PixelChannel
1031 channel;
1032
1033 PixelTrait
1034 traits;
1035
1036 ssize_t
1037 offset;
1038
cristy4c08aed2011-07-01 19:47:50 +00001039 /*
cristy3b8fe922011-12-29 18:56:23 +00001040 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001041 */
cristy9e0719b2011-12-29 03:45:45 +00001042 channel=clone_info->channel_map[i].channel;
1043 traits=cache_info->channel_map[channel].traits;
1044 if (traits == UndefinedPixelTrait)
1045 {
cristy0f4425e2011-12-31 20:33:02 +00001046 clone_offset+=sizeof(Quantum);
1047 continue;
cristy9e0719b2011-12-29 03:45:45 +00001048 }
cristy0f4425e2011-12-31 20:33:02 +00001049 offset=cache_info->channel_map[channel].offset;
1050 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001051 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
1052 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +00001053 else
1054 {
cristy0f4425e2011-12-31 20:33:02 +00001055 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +00001056 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +00001057 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +00001058 {
cristy0f4425e2011-12-31 20:33:02 +00001059 status=MagickFalse;
1060 break;
cristy4c08aed2011-07-01 19:47:50 +00001061 }
1062 }
cristy9e0719b2011-12-29 03:45:45 +00001063 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001064 }
1065 }
cristyed231572011-07-14 02:18:59 +00001066 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001067 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1068 for ( ; x < (ssize_t) clone_info->columns; x++)
1069 {
1070 /*
cristy9e0719b2011-12-29 03:45:45 +00001071 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001072 */
1073 if (clone_info->type != DiskCache)
1074 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1075 length);
1076 else
1077 {
1078 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1079 if ((MagickSizeType) count != length)
1080 {
1081 status=MagickFalse;
1082 break;
1083 }
1084 }
1085 clone_offset+=length;
1086 }
1087 }
cristyed231572011-07-14 02:18:59 +00001088 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001089 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1090 for ( ; y < (ssize_t) clone_info->rows; y++)
1091 {
1092 /*
cristy9e0719b2011-12-29 03:45:45 +00001093 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001094 */
1095 for (x=0; x < (ssize_t) clone_info->columns; x++)
1096 {
1097 if (clone_info->type != DiskCache)
1098 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1099 length);
1100 else
1101 {
1102 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1103 if ((MagickSizeType) count != length)
1104 {
1105 status=MagickFalse;
1106 break;
1107 }
1108 }
1109 clone_offset+=length;
1110 }
1111 }
cristy9e0719b2011-12-29 03:45:45 +00001112 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001113 (clone_info->metacontent_extent != 0))
1114 {
1115 /*
1116 Clone metacontent.
1117 */
1118 for (y=0; y < (ssize_t) cache_info->rows; y++)
1119 {
1120 for (x=0; x < (ssize_t) cache_info->columns; x++)
1121 {
1122 /*
1123 Read a set of metacontent.
1124 */
1125 length=cache_info->metacontent_extent;
1126 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001127 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +00001128 else
1129 {
cristyfd24a062012-01-02 14:46:34 +00001130 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001131 if ((MagickSizeType) count != length)
1132 {
1133 status=MagickFalse;
1134 break;
1135 }
1136 }
1137 cache_offset+=length;
1138 if ((y < (ssize_t) clone_info->rows) &&
1139 (x < (ssize_t) clone_info->columns))
1140 {
1141 /*
1142 Write a set of metacontent.
1143 */
1144 length=clone_info->metacontent_extent;
1145 if (clone_info->type != DiskCache)
1146 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +00001147 p,length);
cristy4c08aed2011-07-01 19:47:50 +00001148 else
1149 {
cristyfd24a062012-01-02 14:46:34 +00001150 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001151 if ((MagickSizeType) count != length)
1152 {
1153 status=MagickFalse;
1154 break;
1155 }
1156 }
1157 clone_offset+=length;
1158 }
1159 }
1160 length=clone_info->metacontent_extent;
1161 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1162 for ( ; x < (ssize_t) clone_info->columns; x++)
1163 {
1164 /*
cristy9e0719b2011-12-29 03:45:45 +00001165 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001166 */
1167 if (clone_info->type != DiskCache)
1168 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1169 blob,length);
1170 else
1171 {
cristy208b1002011-08-07 18:51:50 +00001172 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001173 if ((MagickSizeType) count != length)
1174 {
1175 status=MagickFalse;
1176 break;
1177 }
1178 }
1179 clone_offset+=length;
1180 }
1181 }
1182 length=clone_info->metacontent_extent;
1183 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1184 for ( ; y < (ssize_t) clone_info->rows; y++)
1185 {
1186 /*
cristy9e0719b2011-12-29 03:45:45 +00001187 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001188 */
1189 for (x=0; x < (ssize_t) clone_info->columns; x++)
1190 {
1191 if (clone_info->type != DiskCache)
1192 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1193 blob,length);
1194 else
1195 {
1196 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1197 if ((MagickSizeType) count != length)
1198 {
1199 status=MagickFalse;
1200 break;
1201 }
1202 }
1203 clone_offset+=length;
1204 }
1205 }
1206 }
1207 if (clone_info->type == DiskCache)
1208 (void) ClosePixelCacheOnDisk(clone_info);
1209 if (cache_info->type == DiskCache)
1210 (void) ClosePixelCacheOnDisk(cache_info);
1211 blob=(unsigned char *) RelinquishMagickMemory(blob);
1212 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001213}
1214
1215static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1216 CacheInfo *cache_info,ExceptionInfo *exception)
1217{
cristy3dfccb22011-12-28 21:47:20 +00001218 PixelChannelMap
1219 *p,
1220 *q;
1221
cristy5a7fbfb2010-11-06 16:10:59 +00001222 if (cache_info->type == PingCache)
1223 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001224 p=cache_info->channel_map;
1225 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001226 if ((cache_info->columns == clone_info->columns) &&
1227 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001228 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001229 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001230 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001231 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1232 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001233}
1234
1235/*
1236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1237% %
1238% %
1239% %
1240+ C l o n e P i x e l C a c h e M e t h o d s %
1241% %
1242% %
1243% %
1244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1245%
1246% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1247% another.
1248%
1249% The format of the ClonePixelCacheMethods() method is:
1250%
1251% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1252%
1253% A description of each parameter follows:
1254%
1255% o clone: Specifies a pointer to a Cache structure.
1256%
1257% o cache: the pixel cache.
1258%
1259*/
cristya6577ff2011-09-02 19:54:26 +00001260MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001261{
1262 CacheInfo
1263 *cache_info,
1264 *source_info;
1265
1266 assert(clone != (Cache) NULL);
1267 source_info=(CacheInfo *) clone;
1268 assert(source_info->signature == MagickSignature);
1269 if (source_info->debug != MagickFalse)
1270 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1271 source_info->filename);
1272 assert(cache != (Cache) NULL);
1273 cache_info=(CacheInfo *) cache;
1274 assert(cache_info->signature == MagickSignature);
1275 source_info->methods=cache_info->methods;
1276}
1277
1278/*
1279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1280% %
1281% %
1282% %
1283+ D e s t r o y I m a g e P i x e l C a c h e %
1284% %
1285% %
1286% %
1287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288%
1289% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1290%
1291% The format of the DestroyImagePixelCache() method is:
1292%
1293% void DestroyImagePixelCache(Image *image)
1294%
1295% A description of each parameter follows:
1296%
1297% o image: the image.
1298%
1299*/
1300static void DestroyImagePixelCache(Image *image)
1301{
1302 assert(image != (Image *) NULL);
1303 assert(image->signature == MagickSignature);
1304 if (image->debug != MagickFalse)
1305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1306 if (image->cache == (void *) NULL)
1307 return;
1308 image->cache=DestroyPixelCache(image->cache);
1309}
1310
1311/*
1312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313% %
1314% %
1315% %
1316+ D e s t r o y I m a g e P i x e l s %
1317% %
1318% %
1319% %
1320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1321%
1322% DestroyImagePixels() deallocates memory associated with the pixel cache.
1323%
1324% The format of the DestroyImagePixels() method is:
1325%
1326% void DestroyImagePixels(Image *image)
1327%
1328% A description of each parameter follows:
1329%
1330% o image: the image.
1331%
1332*/
1333MagickExport void DestroyImagePixels(Image *image)
1334{
1335 CacheInfo
1336 *cache_info;
1337
1338 assert(image != (const Image *) NULL);
1339 assert(image->signature == MagickSignature);
1340 if (image->debug != MagickFalse)
1341 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1342 assert(image->cache != (Cache) NULL);
1343 cache_info=(CacheInfo *) image->cache;
1344 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001345 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1346 {
1347 cache_info->methods.destroy_pixel_handler(image);
1348 return;
1349 }
cristy2036f5c2010-09-19 21:18:17 +00001350 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001351}
1352
1353/*
1354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355% %
1356% %
1357% %
1358+ D e s t r o y P i x e l C a c h e %
1359% %
1360% %
1361% %
1362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363%
1364% DestroyPixelCache() deallocates memory associated with the pixel cache.
1365%
1366% The format of the DestroyPixelCache() method is:
1367%
1368% Cache DestroyPixelCache(Cache cache)
1369%
1370% A description of each parameter follows:
1371%
1372% o cache: the pixel cache.
1373%
1374*/
1375
1376static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1377{
1378 switch (cache_info->type)
1379 {
1380 case MemoryCache:
1381 {
1382 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001383 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001384 cache_info->pixels);
1385 else
cristy4c08aed2011-07-01 19:47:50 +00001386 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001387 (size_t) cache_info->length);
1388 RelinquishMagickResource(MemoryResource,cache_info->length);
1389 break;
1390 }
1391 case MapCache:
1392 {
cristy4c08aed2011-07-01 19:47:50 +00001393 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001394 cache_info->length);
1395 RelinquishMagickResource(MapResource,cache_info->length);
1396 }
1397 case DiskCache:
1398 {
1399 if (cache_info->file != -1)
1400 (void) ClosePixelCacheOnDisk(cache_info);
1401 RelinquishMagickResource(DiskResource,cache_info->length);
1402 break;
1403 }
1404 default:
1405 break;
1406 }
1407 cache_info->type=UndefinedCache;
1408 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001409 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001410}
1411
cristya6577ff2011-09-02 19:54:26 +00001412MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001413{
1414 CacheInfo
1415 *cache_info;
1416
cristy3ed852e2009-09-05 21:47:34 +00001417 assert(cache != (Cache) NULL);
1418 cache_info=(CacheInfo *) cache;
1419 assert(cache_info->signature == MagickSignature);
1420 if (cache_info->debug != MagickFalse)
1421 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1422 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001423 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001424 cache_info->reference_count--;
1425 if (cache_info->reference_count != 0)
1426 {
cristyf84a1932010-01-03 18:00:18 +00001427 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001428 return((Cache) NULL);
1429 }
cristyf84a1932010-01-03 18:00:18 +00001430 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001431 if (cache_resources != (SplayTreeInfo *) NULL)
1432 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001433 if (cache_info->debug != MagickFalse)
1434 {
1435 char
1436 message[MaxTextExtent];
1437
cristyb51dff52011-05-19 16:55:47 +00001438 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001439 cache_info->filename);
1440 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1441 }
cristyc2e1bdd2009-09-10 23:43:34 +00001442 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1443 (cache_info->type != DiskCache)))
1444 RelinquishPixelCachePixels(cache_info);
1445 else
1446 {
1447 RelinquishPixelCachePixels(cache_info);
1448 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1449 }
cristy3ed852e2009-09-05 21:47:34 +00001450 *cache_info->cache_filename='\0';
1451 if (cache_info->nexus_info != (NexusInfo **) NULL)
1452 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1453 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001454 if (cache_info->random_info != (RandomInfo *) NULL)
1455 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001456 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1457 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1458 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1459 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001460 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001461 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001462 cache=(Cache) NULL;
1463 return(cache);
1464}
1465
1466/*
1467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468% %
1469% %
1470% %
1471+ D e s t r o y P i x e l C a c h e N e x u s %
1472% %
1473% %
1474% %
1475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476%
1477% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1478%
1479% The format of the DestroyPixelCacheNexus() method is:
1480%
1481% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001482% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001483%
1484% A description of each parameter follows:
1485%
1486% o nexus_info: the nexus to destroy.
1487%
1488% o number_threads: the number of nexus threads.
1489%
1490*/
1491
1492static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1493{
1494 if (nexus_info->mapped == MagickFalse)
cristy7dc8ac52012-01-10 20:14:52 +00001495 (void) RelinquishAlignedMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001496 else
1497 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001498 nexus_info->cache=(Quantum *) NULL;
1499 nexus_info->pixels=(Quantum *) NULL;
1500 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001501 nexus_info->length=0;
1502 nexus_info->mapped=MagickFalse;
1503}
1504
cristya6577ff2011-09-02 19:54:26 +00001505MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001506 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001507{
cristybb503372010-05-27 20:51:26 +00001508 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001509 i;
1510
1511 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001512 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001513 {
cristy4c08aed2011-07-01 19:47:50 +00001514 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001515 RelinquishCacheNexusPixels(nexus_info[i]);
1516 nexus_info[i]->signature=(~MagickSignature);
cristy7dc8ac52012-01-10 20:14:52 +00001517 nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001518 }
cristyb41ee102010-10-04 16:46:15 +00001519 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001520 return(nexus_info);
1521}
1522
1523/*
1524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1525% %
1526% %
1527% %
cristy4c08aed2011-07-01 19:47:50 +00001528% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001529% %
1530% %
1531% %
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533%
cristy4c08aed2011-07-01 19:47:50 +00001534% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1535% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1536% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001537%
cristy4c08aed2011-07-01 19:47:50 +00001538% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001539%
cristy4c08aed2011-07-01 19:47:50 +00001540% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001541%
1542% A description of each parameter follows:
1543%
1544% o image: the image.
1545%
1546*/
cristy4c08aed2011-07-01 19:47:50 +00001547MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001548{
1549 CacheInfo
1550 *cache_info;
1551
cristy5c9e6f22010-09-17 17:31:01 +00001552 const int
1553 id = GetOpenMPThreadId();
1554
cristy4c08aed2011-07-01 19:47:50 +00001555 void
1556 *metacontent;
1557
cristye7cc7cf2010-09-21 13:26:47 +00001558 assert(image != (const Image *) NULL);
1559 assert(image->signature == MagickSignature);
1560 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001561 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001562 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001563 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1564 (GetAuthenticMetacontentFromHandler) NULL)
1565 {
1566 metacontent=cache_info->methods.
1567 get_authentic_metacontent_from_handler(image);
1568 return(metacontent);
1569 }
cristy6ebe97c2010-07-03 01:17:28 +00001570 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001571 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1572 cache_info->nexus_info[id]);
1573 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001574}
1575
1576/*
1577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1578% %
1579% %
1580% %
cristy4c08aed2011-07-01 19:47:50 +00001581+ 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 %
cristy3ed852e2009-09-05 21:47:34 +00001582% %
1583% %
1584% %
1585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586%
cristy4c08aed2011-07-01 19:47:50 +00001587% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1588% with the last call to QueueAuthenticPixelsCache() or
1589% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001590%
cristy4c08aed2011-07-01 19:47:50 +00001591% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001592%
cristy4c08aed2011-07-01 19:47:50 +00001593% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001594%
1595% A description of each parameter follows:
1596%
1597% o image: the image.
1598%
1599*/
cristy4c08aed2011-07-01 19:47:50 +00001600static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001601{
1602 CacheInfo
1603 *cache_info;
1604
cristy2036f5c2010-09-19 21:18:17 +00001605 const int
1606 id = GetOpenMPThreadId();
1607
cristy4c08aed2011-07-01 19:47:50 +00001608 void
1609 *metacontent;
1610
cristy3ed852e2009-09-05 21:47:34 +00001611 assert(image != (const Image *) NULL);
1612 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001613 assert(image->cache != (Cache) NULL);
1614 cache_info=(CacheInfo *) image->cache;
1615 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001616 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001617 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1618 cache_info->nexus_info[id]);
1619 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001620}
1621
1622/*
1623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624% %
1625% %
1626% %
1627+ 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 %
1628% %
1629% %
1630% %
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632%
1633% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1634% disk pixel cache as defined by the geometry parameters. A pointer to the
1635% pixels is returned if the pixels are transferred, otherwise a NULL is
1636% returned.
1637%
1638% The format of the GetAuthenticPixelCacheNexus() method is:
1639%
cristy4c08aed2011-07-01 19:47:50 +00001640% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001641% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001642% NexusInfo *nexus_info,ExceptionInfo *exception)
1643%
1644% A description of each parameter follows:
1645%
1646% o image: the image.
1647%
1648% o x,y,columns,rows: These values define the perimeter of a region of
1649% pixels.
1650%
1651% o nexus_info: the cache nexus to return.
1652%
1653% o exception: return any errors or warnings in this structure.
1654%
1655*/
1656
cristy4c08aed2011-07-01 19:47:50 +00001657static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001658 NexusInfo *nexus_info)
1659{
cristy4c08aed2011-07-01 19:47:50 +00001660 MagickBooleanType
1661 status;
1662
cristy3ed852e2009-09-05 21:47:34 +00001663 MagickOffsetType
1664 offset;
1665
cristy73724512010-04-12 14:43:14 +00001666 if (cache_info->type == PingCache)
1667 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001668 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1669 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001670 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001671 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001672 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001673}
1674
cristya6577ff2011-09-02 19:54:26 +00001675MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001676 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001677 NexusInfo *nexus_info,ExceptionInfo *exception)
1678{
1679 CacheInfo
1680 *cache_info;
1681
cristy4c08aed2011-07-01 19:47:50 +00001682 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001683 *q;
cristy3ed852e2009-09-05 21:47:34 +00001684
1685 /*
1686 Transfer pixels from the cache.
1687 */
1688 assert(image != (Image *) NULL);
1689 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001690 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001691 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001692 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001693 cache_info=(CacheInfo *) image->cache;
1694 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001695 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001696 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001697 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001698 return((Quantum *) NULL);
1699 if (cache_info->metacontent_extent != 0)
1700 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1701 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001702 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001703}
1704
1705/*
1706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707% %
1708% %
1709% %
1710+ 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 %
1711% %
1712% %
1713% %
1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715%
1716% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1717% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1718%
1719% The format of the GetAuthenticPixelsFromCache() method is:
1720%
cristy4c08aed2011-07-01 19:47:50 +00001721% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001722%
1723% A description of each parameter follows:
1724%
1725% o image: the image.
1726%
1727*/
cristy4c08aed2011-07-01 19:47:50 +00001728static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001729{
1730 CacheInfo
1731 *cache_info;
1732
cristy5c9e6f22010-09-17 17:31:01 +00001733 const int
1734 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001735
cristye7cc7cf2010-09-21 13:26:47 +00001736 assert(image != (const Image *) NULL);
1737 assert(image->signature == MagickSignature);
1738 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001739 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001740 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001741 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001742 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001743}
1744
1745/*
1746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1747% %
1748% %
1749% %
1750% G e t A u t h e n t i c P i x e l Q u e u e %
1751% %
1752% %
1753% %
1754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755%
cristy4c08aed2011-07-01 19:47:50 +00001756% GetAuthenticPixelQueue() returns the authentic pixels associated
1757% corresponding with the last call to QueueAuthenticPixels() or
1758% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001759%
1760% The format of the GetAuthenticPixelQueue() method is:
1761%
cristy4c08aed2011-07-01 19:47:50 +00001762% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001763%
1764% A description of each parameter follows:
1765%
1766% o image: the image.
1767%
1768*/
cristy4c08aed2011-07-01 19:47:50 +00001769MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001770{
1771 CacheInfo
1772 *cache_info;
1773
cristy2036f5c2010-09-19 21:18:17 +00001774 const int
1775 id = GetOpenMPThreadId();
1776
cristy3ed852e2009-09-05 21:47:34 +00001777 assert(image != (const Image *) NULL);
1778 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001779 assert(image->cache != (Cache) NULL);
1780 cache_info=(CacheInfo *) image->cache;
1781 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001782 if (cache_info->methods.get_authentic_pixels_from_handler !=
1783 (GetAuthenticPixelsFromHandler) NULL)
1784 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001785 assert(id < (int) cache_info->number_threads);
1786 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001787}
1788
1789/*
1790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1791% %
1792% %
1793% %
1794% G e t A u t h e n t i c P i x e l s %
1795% %
1796% %
cristy4c08aed2011-07-01 19:47:50 +00001797% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001798%
1799% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001800% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001801% representing the region is returned, otherwise NULL is returned.
1802%
1803% The returned pointer may point to a temporary working copy of the pixels
1804% or it may point to the original pixels in memory. Performance is maximized
1805% if the selected region is part of one row, or one or more full rows, since
1806% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001807% if the image is in memory, or in a memory-mapped file. The returned pointer
1808% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001809%
1810% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001811% Quantum. If the image has corresponding metacontent,call
1812% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1813% meta-content corresponding to the region. Once the Quantum array has
1814% been updated, the changes must be saved back to the underlying image using
1815% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001816%
1817% The format of the GetAuthenticPixels() method is:
1818%
cristy4c08aed2011-07-01 19:47:50 +00001819% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001820% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001821% ExceptionInfo *exception)
1822%
1823% A description of each parameter follows:
1824%
1825% o image: the image.
1826%
1827% o x,y,columns,rows: These values define the perimeter of a region of
1828% pixels.
1829%
1830% o exception: return any errors or warnings in this structure.
1831%
1832*/
cristy4c08aed2011-07-01 19:47:50 +00001833MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001834 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001835 ExceptionInfo *exception)
1836{
1837 CacheInfo
1838 *cache_info;
1839
cristy2036f5c2010-09-19 21:18:17 +00001840 const int
1841 id = GetOpenMPThreadId();
1842
cristy4c08aed2011-07-01 19:47:50 +00001843 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001844 *q;
cristy4c08aed2011-07-01 19:47:50 +00001845
cristy3ed852e2009-09-05 21:47:34 +00001846 assert(image != (Image *) NULL);
1847 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001848 assert(image->cache != (Cache) NULL);
1849 cache_info=(CacheInfo *) image->cache;
1850 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001851 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001852 (GetAuthenticPixelsHandler) NULL)
1853 {
cristyacd2ed22011-08-30 01:44:23 +00001854 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1855 exception);
1856 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001857 }
cristy2036f5c2010-09-19 21:18:17 +00001858 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001859 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001860 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001861 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001862}
1863
1864/*
1865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1866% %
1867% %
1868% %
1869+ G e t A u t h e n t i c P i x e l s C a c h e %
1870% %
1871% %
1872% %
1873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1874%
1875% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1876% as defined by the geometry parameters. A pointer to the pixels is returned
1877% if the pixels are transferred, otherwise a NULL is returned.
1878%
1879% The format of the GetAuthenticPixelsCache() method is:
1880%
cristy4c08aed2011-07-01 19:47:50 +00001881% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001882% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001883% ExceptionInfo *exception)
1884%
1885% A description of each parameter follows:
1886%
1887% o image: the image.
1888%
1889% o x,y,columns,rows: These values define the perimeter of a region of
1890% pixels.
1891%
1892% o exception: return any errors or warnings in this structure.
1893%
1894*/
cristy4c08aed2011-07-01 19:47:50 +00001895static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001896 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001897 ExceptionInfo *exception)
1898{
1899 CacheInfo
1900 *cache_info;
1901
cristy5c9e6f22010-09-17 17:31:01 +00001902 const int
1903 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001904
cristy4c08aed2011-07-01 19:47:50 +00001905 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001906 *q;
cristy4c08aed2011-07-01 19:47:50 +00001907
cristye7cc7cf2010-09-21 13:26:47 +00001908 assert(image != (const Image *) NULL);
1909 assert(image->signature == MagickSignature);
1910 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001911 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001912 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001913 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001914 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001915 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001916 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001917 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001918 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001919}
1920
1921/*
1922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1923% %
1924% %
1925% %
1926+ G e t I m a g e E x t e n t %
1927% %
1928% %
1929% %
1930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1931%
cristy4c08aed2011-07-01 19:47:50 +00001932% GetImageExtent() returns the extent of the pixels associated corresponding
1933% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001934%
1935% The format of the GetImageExtent() method is:
1936%
1937% MagickSizeType GetImageExtent(const Image *image)
1938%
1939% A description of each parameter follows:
1940%
1941% o image: the image.
1942%
1943*/
1944MagickExport MagickSizeType GetImageExtent(const Image *image)
1945{
1946 CacheInfo
1947 *cache_info;
1948
cristy5c9e6f22010-09-17 17:31:01 +00001949 const int
1950 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001951
cristy3ed852e2009-09-05 21:47:34 +00001952 assert(image != (Image *) NULL);
1953 assert(image->signature == MagickSignature);
1954 if (image->debug != MagickFalse)
1955 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1956 assert(image->cache != (Cache) NULL);
1957 cache_info=(CacheInfo *) image->cache;
1958 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001959 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001960 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001961}
1962
1963/*
1964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965% %
1966% %
1967% %
1968+ G e t I m a g e P i x e l C a c h e %
1969% %
1970% %
1971% %
1972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1973%
1974% GetImagePixelCache() ensures that there is only a single reference to the
1975% pixel cache to be modified, updating the provided cache pointer to point to
1976% a clone of the original pixel cache if necessary.
1977%
1978% The format of the GetImagePixelCache method is:
1979%
1980% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1981% ExceptionInfo *exception)
1982%
1983% A description of each parameter follows:
1984%
1985% o image: the image.
1986%
1987% o clone: any value other than MagickFalse clones the cache pixels.
1988%
1989% o exception: return any errors or warnings in this structure.
1990%
1991*/
cristyaf894d72011-08-06 23:03:10 +00001992
cristy3ed852e2009-09-05 21:47:34 +00001993static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1994{
1995 CacheInfo
1996 *cache_info;
1997
cristy9e0719b2011-12-29 03:45:45 +00001998 PixelChannelMap
1999 *p,
2000 *q;
2001
cristy3ed852e2009-09-05 21:47:34 +00002002 /*
2003 Does the image match the pixel cache morphology?
2004 */
2005 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00002006 p=image->channel_map;
2007 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00002008 if ((image->storage_class != cache_info->storage_class) ||
2009 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002010 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002011 (image->columns != cache_info->columns) ||
2012 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002013 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002014 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002015 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002016 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2017 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2018 return(MagickFalse);
2019 return(MagickTrue);
2020}
2021
cristycd01fae2011-08-06 23:52:42 +00002022static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2023 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002024{
2025 CacheInfo
2026 *cache_info;
2027
cristy3ed852e2009-09-05 21:47:34 +00002028 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002029 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002030 status;
2031
cristy50a10922010-02-15 18:35:25 +00002032 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002033 cpu_throttle = 0,
2034 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002035 time_limit = 0;
2036
cristy1ea34962010-07-01 19:49:21 +00002037 static time_t
cristy208b1002011-08-07 18:51:50 +00002038 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002039
cristyc4f9f132010-03-04 18:50:01 +00002040 status=MagickTrue;
2041 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002042 if (cpu_throttle == 0)
2043 {
2044 char
2045 *limit;
2046
2047 /*
2048 Set CPU throttle in milleseconds.
2049 */
2050 cpu_throttle=MagickResourceInfinity;
2051 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2052 if (limit == (char *) NULL)
2053 limit=GetPolicyValue("throttle");
2054 if (limit != (char *) NULL)
2055 {
2056 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2057 limit=DestroyString(limit);
2058 }
2059 }
2060 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2061 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002062 if (time_limit == 0)
2063 {
cristy6ebe97c2010-07-03 01:17:28 +00002064 /*
2065 Set the exire time in seconds.
2066 */
cristy1ea34962010-07-01 19:49:21 +00002067 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002068 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002069 }
2070 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002071 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002072 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002073 assert(image->cache != (Cache) NULL);
2074 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002075 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002076 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002077 {
cristyceb55ee2010-11-06 16:05:49 +00002078 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002079 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002080 {
cristyceb55ee2010-11-06 16:05:49 +00002081 Image
2082 clone_image;
2083
2084 CacheInfo
2085 *clone_info;
2086
2087 /*
2088 Clone pixel cache.
2089 */
2090 clone_image=(*image);
2091 clone_image.semaphore=AllocateSemaphoreInfo();
2092 clone_image.reference_count=1;
2093 clone_image.cache=ClonePixelCache(cache_info);
2094 clone_info=(CacheInfo *) clone_image.cache;
2095 status=OpenPixelCache(&clone_image,IOMode,exception);
2096 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002097 {
cristy5a7fbfb2010-11-06 16:10:59 +00002098 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002099 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002100 if (status != MagickFalse)
2101 {
cristy979bf772011-08-08 00:04:15 +00002102 if (cache_info->mode == ReadMode)
2103 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002104 destroy=MagickTrue;
2105 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002106 }
2107 }
cristyceb55ee2010-11-06 16:05:49 +00002108 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002109 }
cristyceb55ee2010-11-06 16:05:49 +00002110 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002111 }
cristy4320e0e2009-09-10 15:00:08 +00002112 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002113 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002114 if (status != MagickFalse)
2115 {
2116 /*
2117 Ensure the image matches the pixel cache morphology.
2118 */
2119 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002120 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002121 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2122 status=OpenPixelCache(image,IOMode,exception);
2123 }
cristyf84a1932010-01-03 18:00:18 +00002124 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002125 if (status == MagickFalse)
2126 return((Cache) NULL);
2127 return(image->cache);
2128}
2129
2130/*
2131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2132% %
2133% %
2134% %
2135% G e t O n e A u t h e n t i c P i x e l %
2136% %
2137% %
2138% %
2139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2140%
2141% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2142% location. The image background color is returned if an error occurs.
2143%
2144% The format of the GetOneAuthenticPixel() method is:
2145%
cristybb503372010-05-27 20:51:26 +00002146% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002147% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002148%
2149% A description of each parameter follows:
2150%
2151% o image: the image.
2152%
2153% o x,y: These values define the location of the pixel to return.
2154%
2155% o pixel: return a pixel at the specified (x,y) location.
2156%
2157% o exception: return any errors or warnings in this structure.
2158%
2159*/
cristyacbbb7c2010-06-30 18:56:48 +00002160MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002161 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002162{
2163 CacheInfo
2164 *cache_info;
2165
cristy4c08aed2011-07-01 19:47:50 +00002166 register Quantum
2167 *q;
cristy2036f5c2010-09-19 21:18:17 +00002168
cristy2ed42f62011-10-02 19:49:57 +00002169 register ssize_t
2170 i;
2171
cristy3ed852e2009-09-05 21:47:34 +00002172 assert(image != (Image *) NULL);
2173 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002174 assert(image->cache != (Cache) NULL);
2175 cache_info=(CacheInfo *) image->cache;
2176 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002177 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002178 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2179 (GetOneAuthenticPixelFromHandler) NULL)
2180 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2181 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002182 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2183 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002184 {
cristy9e0719b2011-12-29 03:45:45 +00002185 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2186 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2187 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2188 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2189 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002190 return(MagickFalse);
2191 }
2192 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2193 {
2194 PixelChannel
2195 channel;
2196
cristye2a912b2011-12-05 20:02:07 +00002197 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002198 pixel[channel]=q[i];
2199 }
cristy2036f5c2010-09-19 21:18:17 +00002200 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002201}
2202
2203/*
2204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205% %
2206% %
2207% %
2208+ 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 %
2209% %
2210% %
2211% %
2212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2213%
2214% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2215% location. The image background color is returned if an error occurs.
2216%
2217% The format of the GetOneAuthenticPixelFromCache() method is:
2218%
2219% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002220% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002221% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002222%
2223% A description of each parameter follows:
2224%
2225% o image: the image.
2226%
2227% o x,y: These values define the location of the pixel to return.
2228%
2229% o pixel: return a pixel at the specified (x,y) location.
2230%
2231% o exception: return any errors or warnings in this structure.
2232%
2233*/
2234static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002235 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002236{
cristy098f78c2010-09-23 17:28:44 +00002237 CacheInfo
2238 *cache_info;
2239
2240 const int
2241 id = GetOpenMPThreadId();
2242
cristy4c08aed2011-07-01 19:47:50 +00002243 register Quantum
2244 *q;
cristy3ed852e2009-09-05 21:47:34 +00002245
cristy2ed42f62011-10-02 19:49:57 +00002246 register ssize_t
2247 i;
2248
cristy0158a4b2010-09-20 13:59:45 +00002249 assert(image != (const Image *) NULL);
2250 assert(image->signature == MagickSignature);
2251 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002252 cache_info=(CacheInfo *) image->cache;
2253 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002254 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002255 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002256 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2257 exception);
2258 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002259 {
cristy9e0719b2011-12-29 03:45:45 +00002260 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2261 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2262 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2263 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2264 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002265 return(MagickFalse);
2266 }
2267 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2268 {
2269 PixelChannel
2270 channel;
2271
cristye2a912b2011-12-05 20:02:07 +00002272 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002273 pixel[channel]=q[i];
2274 }
cristy3ed852e2009-09-05 21:47:34 +00002275 return(MagickTrue);
2276}
2277
2278/*
2279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2280% %
2281% %
2282% %
cristy3ed852e2009-09-05 21:47:34 +00002283% G e t O n e V i r t u a l P i x e l %
2284% %
2285% %
2286% %
2287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2288%
2289% GetOneVirtualPixel() returns a single virtual pixel at the specified
2290% (x,y) location. The image background color is returned if an error occurs.
2291% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2292%
2293% The format of the GetOneVirtualPixel() method is:
2294%
cristybb503372010-05-27 20:51:26 +00002295% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002296% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002297%
2298% A description of each parameter follows:
2299%
2300% o image: the image.
2301%
2302% o x,y: These values define the location of the pixel to return.
2303%
2304% o pixel: return a pixel at the specified (x,y) location.
2305%
2306% o exception: return any errors or warnings in this structure.
2307%
2308*/
2309MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002310 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002311{
cristy3ed852e2009-09-05 21:47:34 +00002312 CacheInfo
2313 *cache_info;
2314
cristy0158a4b2010-09-20 13:59:45 +00002315 const int
2316 id = GetOpenMPThreadId();
2317
cristy4c08aed2011-07-01 19:47:50 +00002318 const Quantum
2319 *p;
cristy2036f5c2010-09-19 21:18:17 +00002320
cristy2ed42f62011-10-02 19:49:57 +00002321 register ssize_t
2322 i;
2323
cristy3ed852e2009-09-05 21:47:34 +00002324 assert(image != (const Image *) NULL);
2325 assert(image->signature == MagickSignature);
2326 assert(image->cache != (Cache) NULL);
2327 cache_info=(CacheInfo *) image->cache;
2328 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002329 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002330 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2331 (GetOneVirtualPixelFromHandler) NULL)
2332 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2333 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002334 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002335 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002336 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002337 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002338 {
cristy9e0719b2011-12-29 03:45:45 +00002339 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2340 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2341 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2342 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2343 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002344 return(MagickFalse);
2345 }
2346 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2347 {
2348 PixelChannel
2349 channel;
2350
cristye2a912b2011-12-05 20:02:07 +00002351 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002352 pixel[channel]=p[i];
2353 }
cristy2036f5c2010-09-19 21:18:17 +00002354 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002355}
2356
2357/*
2358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2359% %
2360% %
2361% %
2362+ 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 %
2363% %
2364% %
2365% %
2366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367%
2368% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2369% specified (x,y) location. The image background color is returned if an
2370% error occurs.
2371%
2372% The format of the GetOneVirtualPixelFromCache() method is:
2373%
2374% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002375% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002376% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002377%
2378% A description of each parameter follows:
2379%
2380% o image: the image.
2381%
2382% o virtual_pixel_method: the virtual pixel method.
2383%
2384% o x,y: These values define the location of the pixel to return.
2385%
2386% o pixel: return a pixel at the specified (x,y) location.
2387%
2388% o exception: return any errors or warnings in this structure.
2389%
2390*/
2391static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002392 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002393 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002394{
cristy0158a4b2010-09-20 13:59:45 +00002395 CacheInfo
2396 *cache_info;
2397
2398 const int
2399 id = GetOpenMPThreadId();
2400
cristy4c08aed2011-07-01 19:47:50 +00002401 const Quantum
2402 *p;
cristy3ed852e2009-09-05 21:47:34 +00002403
cristy2ed42f62011-10-02 19:49:57 +00002404 register ssize_t
2405 i;
2406
cristye7cc7cf2010-09-21 13:26:47 +00002407 assert(image != (const Image *) NULL);
2408 assert(image->signature == MagickSignature);
2409 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002410 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002411 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002412 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002413 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002414 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002415 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002416 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002417 {
cristy9e0719b2011-12-29 03:45:45 +00002418 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2419 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2420 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2421 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2422 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002423 return(MagickFalse);
2424 }
2425 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2426 {
2427 PixelChannel
2428 channel;
2429
cristye2a912b2011-12-05 20:02:07 +00002430 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002431 pixel[channel]=p[i];
2432 }
cristy3ed852e2009-09-05 21:47:34 +00002433 return(MagickTrue);
2434}
2435
2436/*
2437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2438% %
2439% %
2440% %
cristy3aa93752011-12-18 15:54:24 +00002441% G e t O n e V i r t u a l P i x e l I n f o %
2442% %
2443% %
2444% %
2445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2446%
2447% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2448% location. The image background color is returned if an error occurs. If
2449% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2450%
2451% The format of the GetOneVirtualPixelInfo() method is:
2452%
2453% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2454% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2455% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2456%
2457% A description of each parameter follows:
2458%
2459% o image: the image.
2460%
2461% o virtual_pixel_method: the virtual pixel method.
2462%
2463% o x,y: these values define the location of the pixel to return.
2464%
2465% o pixel: return a pixel at the specified (x,y) location.
2466%
2467% o exception: return any errors or warnings in this structure.
2468%
2469*/
2470MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2471 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2472 PixelInfo *pixel,ExceptionInfo *exception)
2473{
2474 CacheInfo
2475 *cache_info;
2476
2477 const int
2478 id = GetOpenMPThreadId();
2479
2480 register const Quantum
2481 *p;
2482
2483 assert(image != (const Image *) NULL);
2484 assert(image->signature == MagickSignature);
2485 assert(image->cache != (Cache) NULL);
2486 cache_info=(CacheInfo *) image->cache;
2487 assert(cache_info->signature == MagickSignature);
2488 assert(id < (int) cache_info->number_threads);
2489 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2490 cache_info->nexus_info[id],exception);
2491 GetPixelInfo(image,pixel);
2492 if (p == (const Quantum *) NULL)
2493 return(MagickFalse);
2494 GetPixelInfoPixel(image,p,pixel);
2495 return(MagickTrue);
2496}
2497
2498/*
2499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2500% %
2501% %
2502% %
cristy3ed852e2009-09-05 21:47:34 +00002503+ G e t P i x e l C a c h e C o l o r s p a c e %
2504% %
2505% %
2506% %
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508%
2509% GetPixelCacheColorspace() returns the class type of the pixel cache.
2510%
2511% The format of the GetPixelCacheColorspace() method is:
2512%
2513% Colorspace GetPixelCacheColorspace(Cache cache)
2514%
2515% A description of each parameter follows:
2516%
2517% o cache: the pixel cache.
2518%
2519*/
cristya6577ff2011-09-02 19:54:26 +00002520MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002521{
2522 CacheInfo
2523 *cache_info;
2524
2525 assert(cache != (Cache) NULL);
2526 cache_info=(CacheInfo *) cache;
2527 assert(cache_info->signature == MagickSignature);
2528 if (cache_info->debug != MagickFalse)
2529 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2530 cache_info->filename);
2531 return(cache_info->colorspace);
2532}
2533
2534/*
2535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536% %
2537% %
2538% %
2539+ G e t P i x e l C a c h e M e t h o d s %
2540% %
2541% %
2542% %
2543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544%
2545% GetPixelCacheMethods() initializes the CacheMethods structure.
2546%
2547% The format of the GetPixelCacheMethods() method is:
2548%
2549% void GetPixelCacheMethods(CacheMethods *cache_methods)
2550%
2551% A description of each parameter follows:
2552%
2553% o cache_methods: Specifies a pointer to a CacheMethods structure.
2554%
2555*/
cristya6577ff2011-09-02 19:54:26 +00002556MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002557{
2558 assert(cache_methods != (CacheMethods *) NULL);
2559 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2560 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2561 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002562 cache_methods->get_virtual_metacontent_from_handler=
2563 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002564 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2565 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002566 cache_methods->get_authentic_metacontent_from_handler=
2567 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002568 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2569 cache_methods->get_one_authentic_pixel_from_handler=
2570 GetOneAuthenticPixelFromCache;
2571 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2572 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2573 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2574}
2575
2576/*
2577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578% %
2579% %
2580% %
2581+ G e t P i x e l C a c h e N e x u s E x t e n t %
2582% %
2583% %
2584% %
2585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2586%
cristy4c08aed2011-07-01 19:47:50 +00002587% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2588% corresponding with the last call to SetPixelCacheNexusPixels() or
2589% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002590%
2591% The format of the GetPixelCacheNexusExtent() method is:
2592%
2593% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2594% NexusInfo *nexus_info)
2595%
2596% A description of each parameter follows:
2597%
2598% o nexus_info: the nexus info.
2599%
2600*/
cristya6577ff2011-09-02 19:54:26 +00002601MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002602 NexusInfo *nexus_info)
2603{
2604 CacheInfo
2605 *cache_info;
2606
2607 MagickSizeType
2608 extent;
2609
cristy9f027d12011-09-21 01:17:17 +00002610 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002611 cache_info=(CacheInfo *) cache;
2612 assert(cache_info->signature == MagickSignature);
2613 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2614 if (extent == 0)
2615 return((MagickSizeType) cache_info->columns*cache_info->rows);
2616 return(extent);
2617}
2618
2619/*
2620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2621% %
2622% %
2623% %
cristy4c08aed2011-07-01 19:47:50 +00002624+ G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002625% %
2626% %
2627% %
2628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629%
cristy4c08aed2011-07-01 19:47:50 +00002630% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2631% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002632%
cristy4c08aed2011-07-01 19:47:50 +00002633% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002634%
cristy4c08aed2011-07-01 19:47:50 +00002635% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002636% NexusInfo *nexus_info)
2637%
2638% A description of each parameter follows:
2639%
2640% o cache: the pixel cache.
2641%
cristy4c08aed2011-07-01 19:47:50 +00002642% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002643%
2644*/
cristya6577ff2011-09-02 19:54:26 +00002645MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002646 NexusInfo *nexus_info)
2647{
2648 CacheInfo
2649 *cache_info;
2650
cristy9f027d12011-09-21 01:17:17 +00002651 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002652 cache_info=(CacheInfo *) cache;
2653 assert(cache_info->signature == MagickSignature);
2654 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002655 return((void *) NULL);
2656 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002657}
2658
2659/*
2660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2661% %
2662% %
2663% %
2664+ G e t P i x e l C a c h e N e x u s P i x e l s %
2665% %
2666% %
2667% %
2668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2669%
2670% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2671% cache nexus.
2672%
2673% The format of the GetPixelCacheNexusPixels() method is:
2674%
cristy4c08aed2011-07-01 19:47:50 +00002675% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002676% NexusInfo *nexus_info)
2677%
2678% A description of each parameter follows:
2679%
2680% o cache: the pixel cache.
2681%
2682% o nexus_info: the cache nexus to return the pixels.
2683%
2684*/
cristya6577ff2011-09-02 19:54:26 +00002685MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002686 NexusInfo *nexus_info)
2687{
2688 CacheInfo
2689 *cache_info;
2690
cristy9f027d12011-09-21 01:17:17 +00002691 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002692 cache_info=(CacheInfo *) cache;
2693 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002694 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002695 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002696 return(nexus_info->pixels);
2697}
2698
2699/*
2700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2701% %
2702% %
2703% %
cristy056ba772010-01-02 23:33:54 +00002704+ G e t P i x e l C a c h e P i x e l s %
2705% %
2706% %
2707% %
2708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709%
2710% GetPixelCachePixels() returns the pixels associated with the specified image.
2711%
2712% The format of the GetPixelCachePixels() method is:
2713%
cristyf84a1932010-01-03 18:00:18 +00002714% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2715% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002716%
2717% A description of each parameter follows:
2718%
2719% o image: the image.
2720%
2721% o length: the pixel cache length.
2722%
cristyf84a1932010-01-03 18:00:18 +00002723% o exception: return any errors or warnings in this structure.
2724%
cristy056ba772010-01-02 23:33:54 +00002725*/
cristyd1dd6e42011-09-04 01:46:08 +00002726MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002727 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002728{
2729 CacheInfo
2730 *cache_info;
2731
2732 assert(image != (const Image *) NULL);
2733 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002734 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002735 assert(length != (MagickSizeType *) NULL);
2736 assert(exception != (ExceptionInfo *) NULL);
2737 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002738 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002739 assert(cache_info->signature == MagickSignature);
2740 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002741 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002742 return((void *) NULL);
2743 *length=cache_info->length;
2744 return((void *) cache_info->pixels);
2745}
2746
2747/*
2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749% %
2750% %
2751% %
cristyb32b90a2009-09-07 21:45:48 +00002752+ 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 %
cristy3ed852e2009-09-05 21:47:34 +00002753% %
2754% %
2755% %
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757%
2758% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2759%
2760% The format of the GetPixelCacheStorageClass() method is:
2761%
2762% ClassType GetPixelCacheStorageClass(Cache cache)
2763%
2764% A description of each parameter follows:
2765%
2766% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2767%
2768% o cache: the pixel cache.
2769%
2770*/
cristya6577ff2011-09-02 19:54:26 +00002771MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002772{
2773 CacheInfo
2774 *cache_info;
2775
2776 assert(cache != (Cache) NULL);
2777 cache_info=(CacheInfo *) cache;
2778 assert(cache_info->signature == MagickSignature);
2779 if (cache_info->debug != MagickFalse)
2780 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2781 cache_info->filename);
2782 return(cache_info->storage_class);
2783}
2784
2785/*
2786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2787% %
2788% %
2789% %
cristyb32b90a2009-09-07 21:45:48 +00002790+ G e t P i x e l C a c h e T i l e S i z e %
2791% %
2792% %
2793% %
2794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2795%
2796% GetPixelCacheTileSize() returns the pixel cache tile size.
2797%
2798% The format of the GetPixelCacheTileSize() method is:
2799%
cristybb503372010-05-27 20:51:26 +00002800% void GetPixelCacheTileSize(const Image *image,size_t *width,
2801% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002802%
2803% A description of each parameter follows:
2804%
2805% o image: the image.
2806%
2807% o width: the optimize cache tile width in pixels.
2808%
2809% o height: the optimize cache tile height in pixels.
2810%
2811*/
cristya6577ff2011-09-02 19:54:26 +00002812MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002813 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002814{
cristy4c08aed2011-07-01 19:47:50 +00002815 CacheInfo
2816 *cache_info;
2817
cristyb32b90a2009-09-07 21:45:48 +00002818 assert(image != (Image *) NULL);
2819 assert(image->signature == MagickSignature);
2820 if (image->debug != MagickFalse)
2821 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002822 cache_info=(CacheInfo *) image->cache;
2823 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002824 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002825 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002826 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002827 *height=(*width);
2828}
2829
2830/*
2831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832% %
2833% %
2834% %
2835+ G e t P i x e l C a c h e T y p e %
2836% %
2837% %
2838% %
2839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2840%
2841% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2842%
2843% The format of the GetPixelCacheType() method is:
2844%
2845% CacheType GetPixelCacheType(const Image *image)
2846%
2847% A description of each parameter follows:
2848%
2849% o image: the image.
2850%
2851*/
cristya6577ff2011-09-02 19:54:26 +00002852MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002853{
2854 CacheInfo
2855 *cache_info;
2856
2857 assert(image != (Image *) NULL);
2858 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002859 assert(image->cache != (Cache) NULL);
2860 cache_info=(CacheInfo *) image->cache;
2861 assert(cache_info->signature == MagickSignature);
2862 return(cache_info->type);
2863}
2864
2865/*
2866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2867% %
2868% %
2869% %
cristy3ed852e2009-09-05 21:47:34 +00002870+ 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 %
2871% %
2872% %
2873% %
2874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875%
2876% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2877% pixel cache. A virtual pixel is any pixel access that is outside the
2878% boundaries of the image cache.
2879%
2880% The format of the GetPixelCacheVirtualMethod() method is:
2881%
2882% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2883%
2884% A description of each parameter follows:
2885%
2886% o image: the image.
2887%
2888*/
cristyd1dd6e42011-09-04 01:46:08 +00002889MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002890{
2891 CacheInfo
2892 *cache_info;
2893
2894 assert(image != (Image *) NULL);
2895 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002896 assert(image->cache != (Cache) NULL);
2897 cache_info=(CacheInfo *) image->cache;
2898 assert(cache_info->signature == MagickSignature);
2899 return(cache_info->virtual_pixel_method);
2900}
2901
2902/*
2903%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2904% %
2905% %
2906% %
cristy4c08aed2011-07-01 19:47:50 +00002907+ 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 %
cristy3ed852e2009-09-05 21:47:34 +00002908% %
2909% %
2910% %
2911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2912%
cristy4c08aed2011-07-01 19:47:50 +00002913% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2914% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002915%
cristy4c08aed2011-07-01 19:47:50 +00002916% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002917%
cristy4c08aed2011-07-01 19:47:50 +00002918% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002919%
2920% A description of each parameter follows:
2921%
2922% o image: the image.
2923%
2924*/
cristy4c08aed2011-07-01 19:47:50 +00002925static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002926{
2927 CacheInfo
2928 *cache_info;
2929
cristy5c9e6f22010-09-17 17:31:01 +00002930 const int
2931 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002932
cristy4c08aed2011-07-01 19:47:50 +00002933 const void
2934 *metacontent;
2935
cristye7cc7cf2010-09-21 13:26:47 +00002936 assert(image != (const Image *) NULL);
2937 assert(image->signature == MagickSignature);
2938 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002939 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002940 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002941 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002942 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2943 cache_info->nexus_info[id]);
2944 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002945}
2946
2947/*
2948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2949% %
2950% %
2951% %
cristy4c08aed2011-07-01 19:47:50 +00002952+ 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 %
cristy3ed852e2009-09-05 21:47:34 +00002953% %
2954% %
2955% %
2956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2957%
cristy4c08aed2011-07-01 19:47:50 +00002958% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2959% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002960%
cristy4c08aed2011-07-01 19:47:50 +00002961% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002962%
cristy4c08aed2011-07-01 19:47:50 +00002963% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002964% NexusInfo *nexus_info)
2965%
2966% A description of each parameter follows:
2967%
2968% o cache: the pixel cache.
2969%
cristy4c08aed2011-07-01 19:47:50 +00002970% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002971%
2972*/
cristya6577ff2011-09-02 19:54:26 +00002973MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002974 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002975{
2976 CacheInfo
2977 *cache_info;
2978
cristye7cc7cf2010-09-21 13:26:47 +00002979 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002980 cache_info=(CacheInfo *) cache;
2981 assert(cache_info->signature == MagickSignature);
2982 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002983 return((void *) NULL);
2984 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002985}
2986
2987/*
2988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2989% %
2990% %
2991% %
cristy4c08aed2011-07-01 19:47:50 +00002992% G e t V i r t u a l M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002993% %
2994% %
2995% %
2996%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2997%
cristy4c08aed2011-07-01 19:47:50 +00002998% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2999% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3000% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003001%
cristy4c08aed2011-07-01 19:47:50 +00003002% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003003%
cristy4c08aed2011-07-01 19:47:50 +00003004% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003005%
3006% A description of each parameter follows:
3007%
3008% o image: the image.
3009%
3010*/
cristy4c08aed2011-07-01 19:47:50 +00003011MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003012{
3013 CacheInfo
3014 *cache_info;
3015
cristy2036f5c2010-09-19 21:18:17 +00003016 const int
3017 id = GetOpenMPThreadId();
3018
cristy4c08aed2011-07-01 19:47:50 +00003019 const void
3020 *metacontent;
3021
cristy3ed852e2009-09-05 21:47:34 +00003022 assert(image != (const Image *) NULL);
3023 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003024 assert(image->cache != (Cache) NULL);
3025 cache_info=(CacheInfo *) image->cache;
3026 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003027 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3028 (GetVirtualMetacontentFromHandler) NULL)
3029 {
3030 metacontent=cache_info->methods.
3031 get_virtual_metacontent_from_handler(image);
3032 return(metacontent);
3033 }
cristy2036f5c2010-09-19 21:18:17 +00003034 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003035 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3036 cache_info->nexus_info[id]);
3037 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003038}
3039
3040/*
3041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3042% %
3043% %
3044% %
3045+ 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 %
3046% %
3047% %
3048% %
3049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3050%
3051% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3052% pixel cache as defined by the geometry parameters. A pointer to the pixels
3053% is returned if the pixels are transferred, otherwise a NULL is returned.
3054%
3055% The format of the GetVirtualPixelsFromNexus() method is:
3056%
cristy4c08aed2011-07-01 19:47:50 +00003057% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003058% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003059% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3060% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003061%
3062% A description of each parameter follows:
3063%
3064% o image: the image.
3065%
3066% o virtual_pixel_method: the virtual pixel method.
3067%
3068% o x,y,columns,rows: These values define the perimeter of a region of
3069% pixels.
3070%
3071% o nexus_info: the cache nexus to acquire.
3072%
3073% o exception: return any errors or warnings in this structure.
3074%
3075*/
3076
cristybb503372010-05-27 20:51:26 +00003077static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003078 DitherMatrix[64] =
3079 {
3080 0, 48, 12, 60, 3, 51, 15, 63,
3081 32, 16, 44, 28, 35, 19, 47, 31,
3082 8, 56, 4, 52, 11, 59, 7, 55,
3083 40, 24, 36, 20, 43, 27, 39, 23,
3084 2, 50, 14, 62, 1, 49, 13, 61,
3085 34, 18, 46, 30, 33, 17, 45, 29,
3086 10, 58, 6, 54, 9, 57, 5, 53,
3087 42, 26, 38, 22, 41, 25, 37, 21
3088 };
3089
cristybb503372010-05-27 20:51:26 +00003090static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003091{
cristybb503372010-05-27 20:51:26 +00003092 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003093 index;
3094
3095 index=x+DitherMatrix[x & 0x07]-32L;
3096 if (index < 0L)
3097 return(0L);
cristybb503372010-05-27 20:51:26 +00003098 if (index >= (ssize_t) columns)
3099 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003100 return(index);
3101}
3102
cristybb503372010-05-27 20:51:26 +00003103static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003104{
cristybb503372010-05-27 20:51:26 +00003105 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003106 index;
3107
3108 index=y+DitherMatrix[y & 0x07]-32L;
3109 if (index < 0L)
3110 return(0L);
cristybb503372010-05-27 20:51:26 +00003111 if (index >= (ssize_t) rows)
3112 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003113 return(index);
3114}
3115
cristybb503372010-05-27 20:51:26 +00003116static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003117{
3118 if (x < 0L)
3119 return(0L);
cristybb503372010-05-27 20:51:26 +00003120 if (x >= (ssize_t) columns)
3121 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003122 return(x);
3123}
3124
cristybb503372010-05-27 20:51:26 +00003125static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003126{
3127 if (y < 0L)
3128 return(0L);
cristybb503372010-05-27 20:51:26 +00003129 if (y >= (ssize_t) rows)
3130 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003131 return(y);
3132}
3133
cristybb503372010-05-27 20:51:26 +00003134static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003135{
cristybb503372010-05-27 20:51:26 +00003136 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003137}
3138
cristybb503372010-05-27 20:51:26 +00003139static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003140{
cristybb503372010-05-27 20:51:26 +00003141 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003142}
3143
cristybb503372010-05-27 20:51:26 +00003144static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3145 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003146{
3147 MagickModulo
3148 modulo;
3149
cristy6162bb42011-07-18 11:34:09 +00003150 /*
3151 Compute the remainder of dividing offset by extent. It returns not only
3152 the quotient (tile the offset falls in) but also the positive remainer
3153 within that tile such that 0 <= remainder < extent. This method is
3154 essentially a ldiv() using a floored modulo division rather than the
3155 normal default truncated modulo division.
3156 */
cristybb503372010-05-27 20:51:26 +00003157 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003158 if (offset < 0L)
3159 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003160 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003161 return(modulo);
3162}
3163
cristya6577ff2011-09-02 19:54:26 +00003164MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003165 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3166 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003167 ExceptionInfo *exception)
3168{
3169 CacheInfo
3170 *cache_info;
3171
3172 MagickOffsetType
3173 offset;
3174
3175 MagickSizeType
3176 length,
3177 number_pixels;
3178
3179 NexusInfo
3180 **virtual_nexus;
3181
cristy4c08aed2011-07-01 19:47:50 +00003182 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003183 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003184 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003185
3186 RectangleInfo
3187 region;
3188
cristy4c08aed2011-07-01 19:47:50 +00003189 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003190 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003191
cristy4c08aed2011-07-01 19:47:50 +00003192 register const void
3193 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003194
cristy4c08aed2011-07-01 19:47:50 +00003195 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003196 *restrict q;
3197
cristybb503372010-05-27 20:51:26 +00003198 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003199 i,
3200 u;
cristy3ed852e2009-09-05 21:47:34 +00003201
cristy4c08aed2011-07-01 19:47:50 +00003202 register unsigned char
3203 *restrict s;
3204
cristy105ba3c2011-07-18 02:28:38 +00003205 ssize_t
3206 v;
3207
cristy4c08aed2011-07-01 19:47:50 +00003208 void
cristy105ba3c2011-07-18 02:28:38 +00003209 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003210
cristy3ed852e2009-09-05 21:47:34 +00003211 /*
3212 Acquire pixels.
3213 */
cristye7cc7cf2010-09-21 13:26:47 +00003214 assert(image != (const Image *) NULL);
3215 assert(image->signature == MagickSignature);
3216 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003217 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003218 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003219 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003220 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003221 region.x=x;
3222 region.y=y;
3223 region.width=columns;
3224 region.height=rows;
3225 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003226 if (pixels == (Quantum *) NULL)
3227 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003228 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003229 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3230 nexus_info->region.x;
3231 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3232 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003233 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3234 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003235 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3236 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003237 {
3238 MagickBooleanType
3239 status;
3240
3241 /*
3242 Pixel request is inside cache extents.
3243 */
cristy4c08aed2011-07-01 19:47:50 +00003244 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003245 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003246 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3247 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003248 return((const Quantum *) NULL);
3249 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003250 {
cristy4c08aed2011-07-01 19:47:50 +00003251 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003252 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003253 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003254 }
cristyacd2ed22011-08-30 01:44:23 +00003255 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003256 }
3257 /*
3258 Pixel request is outside cache extents.
3259 */
cristy4c08aed2011-07-01 19:47:50 +00003260 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003261 virtual_nexus=AcquirePixelCacheNexus(1);
3262 if (virtual_nexus == (NexusInfo **) NULL)
3263 {
cristy4c08aed2011-07-01 19:47:50 +00003264 if (virtual_nexus != (NexusInfo **) NULL)
3265 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003266 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3267 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003268 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003269 }
cristy105ba3c2011-07-18 02:28:38 +00003270 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3271 sizeof(*virtual_pixel));
3272 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003273 switch (virtual_pixel_method)
3274 {
cristy4c08aed2011-07-01 19:47:50 +00003275 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003276 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003277 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003278 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003279 case MaskVirtualPixelMethod:
3280 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003281 case EdgeVirtualPixelMethod:
3282 case CheckerTileVirtualPixelMethod:
3283 case HorizontalTileVirtualPixelMethod:
3284 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003285 {
cristy4c08aed2011-07-01 19:47:50 +00003286 if (cache_info->metacontent_extent != 0)
3287 {
cristy6162bb42011-07-18 11:34:09 +00003288 /*
3289 Acquire a metacontent buffer.
3290 */
cristya64b85d2011-09-14 01:02:31 +00003291 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003292 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003293 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003294 {
cristy4c08aed2011-07-01 19:47:50 +00003295 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3296 (void) ThrowMagickException(exception,GetMagickModule(),
3297 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3298 return((const Quantum *) NULL);
3299 }
cristy105ba3c2011-07-18 02:28:38 +00003300 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003301 cache_info->metacontent_extent);
3302 }
3303 switch (virtual_pixel_method)
3304 {
3305 case BlackVirtualPixelMethod:
3306 {
cristy30301712011-07-18 15:06:51 +00003307 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3308 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003309 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3310 break;
3311 }
3312 case GrayVirtualPixelMethod:
3313 {
cristy30301712011-07-18 15:06:51 +00003314 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003315 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3316 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003317 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3318 break;
3319 }
3320 case TransparentVirtualPixelMethod:
3321 {
cristy30301712011-07-18 15:06:51 +00003322 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3323 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003324 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3325 break;
3326 }
3327 case MaskVirtualPixelMethod:
3328 case WhiteVirtualPixelMethod:
3329 {
cristy30301712011-07-18 15:06:51 +00003330 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3331 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003332 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3333 break;
3334 }
3335 default:
3336 {
cristy9e0719b2011-12-29 03:45:45 +00003337 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3338 virtual_pixel);
3339 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3340 virtual_pixel);
3341 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3342 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003343 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003344 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3345 virtual_pixel);
3346 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3347 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003348 break;
3349 }
3350 }
cristy3ed852e2009-09-05 21:47:34 +00003351 break;
3352 }
3353 default:
cristy3ed852e2009-09-05 21:47:34 +00003354 break;
cristy3ed852e2009-09-05 21:47:34 +00003355 }
cristybb503372010-05-27 20:51:26 +00003356 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003357 {
cristybb503372010-05-27 20:51:26 +00003358 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003359 {
3360 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003361 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003362 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3363 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003364 {
3365 MagickModulo
3366 x_modulo,
3367 y_modulo;
3368
3369 /*
3370 Transfer a single pixel.
3371 */
3372 length=(MagickSizeType) 1;
3373 switch (virtual_pixel_method)
3374 {
cristy3ed852e2009-09-05 21:47:34 +00003375 default:
3376 {
3377 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003378 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003379 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003380 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003381 break;
3382 }
3383 case RandomVirtualPixelMethod:
3384 {
3385 if (cache_info->random_info == (RandomInfo *) NULL)
3386 cache_info->random_info=AcquireRandomInfo();
3387 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003388 RandomX(cache_info->random_info,cache_info->columns),
3389 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003390 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003391 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003392 break;
3393 }
3394 case DitherVirtualPixelMethod:
3395 {
3396 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003397 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003398 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003399 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003400 break;
3401 }
3402 case TileVirtualPixelMethod:
3403 {
3404 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3405 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3406 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003407 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003408 exception);
cristy4c08aed2011-07-01 19:47:50 +00003409 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003410 break;
3411 }
3412 case MirrorVirtualPixelMethod:
3413 {
3414 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3415 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003416 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003417 x_modulo.remainder-1L;
3418 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3419 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003420 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003421 y_modulo.remainder-1L;
3422 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003423 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003424 exception);
cristy4c08aed2011-07-01 19:47:50 +00003425 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 case HorizontalTileEdgeVirtualPixelMethod:
3429 {
3430 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3431 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003432 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003433 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003434 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003435 break;
3436 }
3437 case VerticalTileEdgeVirtualPixelMethod:
3438 {
3439 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003441 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003442 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003443 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3444 break;
3445 }
3446 case BackgroundVirtualPixelMethod:
3447 case BlackVirtualPixelMethod:
3448 case GrayVirtualPixelMethod:
3449 case TransparentVirtualPixelMethod:
3450 case MaskVirtualPixelMethod:
3451 case WhiteVirtualPixelMethod:
3452 {
3453 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003454 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003455 break;
3456 }
3457 case EdgeVirtualPixelMethod:
3458 case CheckerTileVirtualPixelMethod:
3459 {
3460 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3461 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3462 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3463 {
3464 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003465 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003466 break;
3467 }
3468 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3469 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3470 exception);
3471 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3472 break;
3473 }
3474 case HorizontalTileVirtualPixelMethod:
3475 {
3476 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3477 {
3478 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003479 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003480 break;
3481 }
3482 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3483 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3484 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3485 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3486 exception);
3487 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3488 break;
3489 }
3490 case VerticalTileVirtualPixelMethod:
3491 {
3492 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3493 {
3494 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003495 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003496 break;
3497 }
3498 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3499 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3500 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3501 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3502 exception);
3503 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003504 break;
3505 }
3506 }
cristy4c08aed2011-07-01 19:47:50 +00003507 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003508 break;
cristyed231572011-07-14 02:18:59 +00003509 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003510 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003511 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003512 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003513 {
3514 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3515 s+=cache_info->metacontent_extent;
3516 }
cristy3ed852e2009-09-05 21:47:34 +00003517 continue;
3518 }
3519 /*
3520 Transfer a run of pixels.
3521 */
cristy4c08aed2011-07-01 19:47:50 +00003522 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3523 length,1UL,*virtual_nexus,exception);
3524 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003525 break;
cristy4c08aed2011-07-01 19:47:50 +00003526 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003527 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3528 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003529 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003530 {
cristy4c08aed2011-07-01 19:47:50 +00003531 (void) memcpy(s,r,(size_t) length);
3532 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003533 }
3534 }
3535 }
cristy4c08aed2011-07-01 19:47:50 +00003536 /*
3537 Free resources.
3538 */
cristy105ba3c2011-07-18 02:28:38 +00003539 if (virtual_metacontent != (void *) NULL)
3540 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003541 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3542 return(pixels);
3543}
3544
3545/*
3546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3547% %
3548% %
3549% %
3550+ G e t V i r t u a l P i x e l C a c h e %
3551% %
3552% %
3553% %
3554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3555%
3556% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3557% cache as defined by the geometry parameters. A pointer to the pixels
3558% is returned if the pixels are transferred, otherwise a NULL is returned.
3559%
3560% The format of the GetVirtualPixelCache() method is:
3561%
cristy4c08aed2011-07-01 19:47:50 +00003562% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003563% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3564% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003565% ExceptionInfo *exception)
3566%
3567% A description of each parameter follows:
3568%
3569% o image: the image.
3570%
3571% o virtual_pixel_method: the virtual pixel method.
3572%
3573% o x,y,columns,rows: These values define the perimeter of a region of
3574% pixels.
3575%
3576% o exception: return any errors or warnings in this structure.
3577%
3578*/
cristy4c08aed2011-07-01 19:47:50 +00003579static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003580 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3581 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003582{
3583 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003584 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003585
cristy5c9e6f22010-09-17 17:31:01 +00003586 const int
3587 id = GetOpenMPThreadId();
3588
cristy4c08aed2011-07-01 19:47:50 +00003589 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003590 *p;
cristy4c08aed2011-07-01 19:47:50 +00003591
cristye7cc7cf2010-09-21 13:26:47 +00003592 assert(image != (const Image *) NULL);
3593 assert(image->signature == MagickSignature);
3594 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003595 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003596 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003597 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003598 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003599 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003600 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003601}
3602
3603/*
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605% %
3606% %
3607% %
3608% G e t V i r t u a l P i x e l Q u e u e %
3609% %
3610% %
3611% %
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613%
cristy4c08aed2011-07-01 19:47:50 +00003614% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3615% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003616%
3617% The format of the GetVirtualPixelQueue() method is:
3618%
cristy4c08aed2011-07-01 19:47:50 +00003619% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003620%
3621% A description of each parameter follows:
3622%
3623% o image: the image.
3624%
3625*/
cristy4c08aed2011-07-01 19:47:50 +00003626MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003627{
3628 CacheInfo
3629 *cache_info;
3630
cristy2036f5c2010-09-19 21:18:17 +00003631 const int
3632 id = GetOpenMPThreadId();
3633
cristy3ed852e2009-09-05 21:47:34 +00003634 assert(image != (const Image *) NULL);
3635 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003636 assert(image->cache != (Cache) NULL);
3637 cache_info=(CacheInfo *) image->cache;
3638 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003639 if (cache_info->methods.get_virtual_pixels_handler !=
3640 (GetVirtualPixelsHandler) NULL)
3641 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003642 assert(id < (int) cache_info->number_threads);
3643 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003644}
3645
3646/*
3647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3648% %
3649% %
3650% %
3651% G e t V i r t u a l P i x e l s %
3652% %
3653% %
3654% %
3655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3656%
3657% GetVirtualPixels() returns an immutable pixel region. If the
3658% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003659% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003660% copy of the pixels or it may point to the original pixels in memory.
3661% Performance is maximized if the selected region is part of one row, or one
3662% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003663% (without a copy) if the image is in memory, or in a memory-mapped file. The
3664% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003665%
3666% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003667% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3668% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3669% access the meta-content (of type void) corresponding to the the
3670% region.
cristy3ed852e2009-09-05 21:47:34 +00003671%
3672% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3673%
3674% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3675% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3676% GetCacheViewAuthenticPixels() instead.
3677%
3678% The format of the GetVirtualPixels() method is:
3679%
cristy4c08aed2011-07-01 19:47:50 +00003680% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003681% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003682% ExceptionInfo *exception)
3683%
3684% A description of each parameter follows:
3685%
3686% o image: the image.
3687%
3688% o x,y,columns,rows: These values define the perimeter of a region of
3689% pixels.
3690%
3691% o exception: return any errors or warnings in this structure.
3692%
3693*/
cristy4c08aed2011-07-01 19:47:50 +00003694MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003695 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3696 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003697{
3698 CacheInfo
3699 *cache_info;
3700
cristy2036f5c2010-09-19 21:18:17 +00003701 const int
3702 id = GetOpenMPThreadId();
3703
cristy4c08aed2011-07-01 19:47:50 +00003704 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003705 *p;
cristy4c08aed2011-07-01 19:47:50 +00003706
cristy3ed852e2009-09-05 21:47:34 +00003707 assert(image != (const Image *) NULL);
3708 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003709 assert(image->cache != (Cache) NULL);
3710 cache_info=(CacheInfo *) image->cache;
3711 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003712 if (cache_info->methods.get_virtual_pixel_handler !=
3713 (GetVirtualPixelHandler) NULL)
3714 return(cache_info->methods.get_virtual_pixel_handler(image,
3715 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003716 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003717 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003718 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003719 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003720}
3721
3722/*
3723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3724% %
3725% %
3726% %
3727+ 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 %
3728% %
3729% %
3730% %
3731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3732%
cristy4c08aed2011-07-01 19:47:50 +00003733% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3734% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003735%
3736% The format of the GetVirtualPixelsCache() method is:
3737%
cristy4c08aed2011-07-01 19:47:50 +00003738% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003739%
3740% A description of each parameter follows:
3741%
3742% o image: the image.
3743%
3744*/
cristy4c08aed2011-07-01 19:47:50 +00003745static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003746{
3747 CacheInfo
3748 *cache_info;
3749
cristy5c9e6f22010-09-17 17:31:01 +00003750 const int
3751 id = GetOpenMPThreadId();
3752
cristye7cc7cf2010-09-21 13:26:47 +00003753 assert(image != (const Image *) NULL);
3754 assert(image->signature == MagickSignature);
3755 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003756 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003757 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003758 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003759 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003760}
3761
3762/*
3763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3764% %
3765% %
3766% %
3767+ G e t V i r t u a l P i x e l s N e x u s %
3768% %
3769% %
3770% %
3771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3772%
3773% GetVirtualPixelsNexus() returns the pixels associated with the specified
3774% cache nexus.
3775%
3776% The format of the GetVirtualPixelsNexus() method is:
3777%
cristy4c08aed2011-07-01 19:47:50 +00003778% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003779% NexusInfo *nexus_info)
3780%
3781% A description of each parameter follows:
3782%
3783% o cache: the pixel cache.
3784%
3785% o nexus_info: the cache nexus to return the colormap pixels.
3786%
3787*/
cristya6577ff2011-09-02 19:54:26 +00003788MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003789 NexusInfo *nexus_info)
3790{
3791 CacheInfo
3792 *cache_info;
3793
cristye7cc7cf2010-09-21 13:26:47 +00003794 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003795 cache_info=(CacheInfo *) cache;
3796 assert(cache_info->signature == MagickSignature);
3797 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003798 return((Quantum *) NULL);
3799 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003800}
3801
3802/*
3803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3804% %
3805% %
3806% %
3807+ M a s k P i x e l C a c h e N e x u s %
3808% %
3809% %
3810% %
3811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3812%
3813% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3814% The method returns MagickTrue if the pixel region is masked, otherwise
3815% MagickFalse.
3816%
3817% The format of the MaskPixelCacheNexus() method is:
3818%
3819% MagickBooleanType MaskPixelCacheNexus(Image *image,
3820% NexusInfo *nexus_info,ExceptionInfo *exception)
3821%
3822% A description of each parameter follows:
3823%
3824% o image: the image.
3825%
3826% o nexus_info: the cache nexus to clip.
3827%
3828% o exception: return any errors or warnings in this structure.
3829%
3830*/
cristy3ed852e2009-09-05 21:47:34 +00003831static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3832 ExceptionInfo *exception)
3833{
3834 CacheInfo
3835 *cache_info;
3836
cristy3ed852e2009-09-05 21:47:34 +00003837 MagickSizeType
3838 number_pixels;
3839
3840 NexusInfo
3841 **clip_nexus,
3842 **image_nexus;
3843
cristy4c08aed2011-07-01 19:47:50 +00003844 register const Quantum
3845 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003846 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003847
cristy4c08aed2011-07-01 19:47:50 +00003848 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003849 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003850
cristye076a6e2010-08-15 19:59:43 +00003851 register ssize_t
cristyc57486d2012-01-02 17:46:50 +00003852 x;
cristye076a6e2010-08-15 19:59:43 +00003853
cristy3ed852e2009-09-05 21:47:34 +00003854 /*
cristyc57486d2012-01-02 17:46:50 +00003855 Prevent updates to image pixels specified by the mask.
cristy3ed852e2009-09-05 21:47:34 +00003856 */
3857 if (image->debug != MagickFalse)
3858 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3859 if (image->mask == (Image *) NULL)
3860 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003861 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003862 if (cache_info == (Cache) NULL)
3863 return(MagickFalse);
3864 image_nexus=AcquirePixelCacheNexus(1);
3865 clip_nexus=AcquirePixelCacheNexus(1);
3866 if ((image_nexus == (NexusInfo **) NULL) ||
3867 (clip_nexus == (NexusInfo **) NULL))
3868 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003869 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3870 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3871 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003872 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003873 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3874 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003875 nexus_info->region.height,clip_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003876 number_pixels=(MagickSizeType) nexus_info->region.width*
3877 nexus_info->region.height;
cristyc57486d2012-01-02 17:46:50 +00003878 for (x=0; x < (ssize_t) number_pixels; x++)
cristy3ed852e2009-09-05 21:47:34 +00003879 {
cristyc57486d2012-01-02 17:46:50 +00003880 MagickRealType
3881 alpha,
3882 Da,
3883 gamma,
3884 Sa;
3885
3886 register ssize_t
3887 i;
3888
cristy4c08aed2011-07-01 19:47:50 +00003889 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003890 break;
cristyc57486d2012-01-02 17:46:50 +00003891 Sa=QuantumScale*GetPixelIntensity(image->mask,r);
3892 Da=QuantumScale*GetPixelAlpha(image,q);
3893 alpha=Sa*(-Da)+Sa+Da;
3894 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
3895 for (i=0; i < (ssize_t) image->number_channels; i++)
3896 {
3897 MagickRealType
3898 Dc,
3899 pixel,
3900 Sc;
3901
3902 PixelChannel
3903 channel;
3904
3905 PixelTrait
3906 traits;
3907
3908 channel=GetPixelChannelMapChannel(image,i);
3909 traits=GetPixelChannelMapTraits(image,channel);
3910 if (traits == UndefinedPixelTrait)
3911 continue;
3912 Sc=(MagickRealType) p[i];
3913 Dc=(MagickRealType) q[i];
cristya3bcb792012-01-10 19:39:28 +00003914 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
cristyc57486d2012-01-02 17:46:50 +00003915 q[i]=ClampToQuantum(pixel);
3916 }
3917 p+=GetPixelChannels(image);
3918 q+=GetPixelChannels(image);
cristy2e814ac2012-01-06 01:59:36 +00003919 r+=GetPixelChannels(image->mask);
cristy3ed852e2009-09-05 21:47:34 +00003920 }
3921 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3922 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristyc57486d2012-01-02 17:46:50 +00003923 if (x < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003924 return(MagickFalse);
3925 return(MagickTrue);
3926}
3927
3928/*
3929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3930% %
3931% %
3932% %
3933+ O p e n P i x e l C a c h e %
3934% %
3935% %
3936% %
3937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3938%
3939% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3940% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003941% metacontent, and memory mapping the cache if it is disk based. The cache
3942% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003943%
3944% The format of the OpenPixelCache() method is:
3945%
3946% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3947% ExceptionInfo *exception)
3948%
3949% A description of each parameter follows:
3950%
3951% o image: the image.
3952%
3953% o mode: ReadMode, WriteMode, or IOMode.
3954%
3955% o exception: return any errors or warnings in this structure.
3956%
3957*/
3958
cristyd43a46b2010-01-21 02:13:41 +00003959static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003960{
3961 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003962 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003963 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003964 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003965 {
3966 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003967 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003968 cache_info->length);
3969 }
3970}
3971
3972static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3973{
3974 CacheInfo
3975 *cache_info;
3976
3977 MagickOffsetType
3978 count,
3979 extent,
3980 offset;
3981
3982 cache_info=(CacheInfo *) image->cache;
3983 if (image->debug != MagickFalse)
3984 {
3985 char
3986 format[MaxTextExtent],
3987 message[MaxTextExtent];
3988
cristyb9080c92009-12-01 20:13:26 +00003989 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003990 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003991 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003992 cache_info->cache_filename,cache_info->file,format);
3993 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3994 }
3995 if (length != (MagickSizeType) ((MagickOffsetType) length))
3996 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003997 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003998 if (extent < 0)
3999 return(MagickFalse);
4000 if ((MagickSizeType) extent >= length)
4001 return(MagickTrue);
4002 offset=(MagickOffsetType) length-1;
4003 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4004 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4005}
4006
4007static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4008 ExceptionInfo *exception)
4009{
cristy3ed852e2009-09-05 21:47:34 +00004010 CacheInfo
4011 *cache_info,
4012 source_info;
4013
cristyf3a6a9d2010-11-07 21:02:56 +00004014 char
4015 format[MaxTextExtent],
4016 message[MaxTextExtent];
4017
cristy4c08aed2011-07-01 19:47:50 +00004018 MagickBooleanType
4019 status;
4020
cristy3ed852e2009-09-05 21:47:34 +00004021 MagickSizeType
4022 length,
4023 number_pixels;
4024
cristy3b8fe922011-12-29 18:56:23 +00004025 PixelChannelMap
4026 *p,
4027 *q;
4028
cristy3ed852e2009-09-05 21:47:34 +00004029 size_t
cristye076a6e2010-08-15 19:59:43 +00004030 columns,
cristy3ed852e2009-09-05 21:47:34 +00004031 packet_size;
4032
cristye7cc7cf2010-09-21 13:26:47 +00004033 assert(image != (const Image *) NULL);
4034 assert(image->signature == MagickSignature);
4035 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004036 if (image->debug != MagickFalse)
4037 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4038 if ((image->columns == 0) || (image->rows == 0))
4039 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4040 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004041 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004042 source_info=(*cache_info);
4043 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004044 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004045 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004046 cache_info->storage_class=image->storage_class;
4047 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004048 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004049 cache_info->rows=image->rows;
4050 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004051 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004052 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004053 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4054 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004055 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004056 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004057 if (image->ping != MagickFalse)
4058 {
cristy73724512010-04-12 14:43:14 +00004059 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004060 cache_info->pixels=(Quantum *) NULL;
4061 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004062 cache_info->length=0;
4063 return(MagickTrue);
4064 }
cristy3ed852e2009-09-05 21:47:34 +00004065 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004066 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004067 if (image->metacontent_extent != 0)
4068 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004069 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004070 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004071 if (cache_info->columns != columns)
4072 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4073 image->filename);
4074 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004075 p=cache_info->channel_map;
4076 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004077 if ((cache_info->type != UndefinedCache) &&
4078 (cache_info->columns <= source_info.columns) &&
4079 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004080 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004081 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004082 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4083 {
4084 /*
4085 Inline pixel cache clone optimization.
4086 */
4087 if ((cache_info->columns == source_info.columns) &&
4088 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004089 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004090 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004091 (cache_info->metacontent_extent == source_info.metacontent_extent))
4092 return(MagickTrue);
4093 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4094 }
cristy3ed852e2009-09-05 21:47:34 +00004095 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004096 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004097 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004098 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4099 {
4100 status=AcquireMagickResource(MemoryResource,cache_info->length);
4101 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4102 (cache_info->type == MemoryCache))
4103 {
cristyd43a46b2010-01-21 02:13:41 +00004104 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004105 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004106 cache_info->pixels=source_info.pixels;
4107 else
4108 {
4109 /*
4110 Create memory pixel cache.
4111 */
cristy4c08aed2011-07-01 19:47:50 +00004112 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004113 if (image->debug != MagickFalse)
4114 {
cristy32cacff2011-12-31 03:36:27 +00004115 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004116 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004117 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4118 cache_info->filename,cache_info->mapped != MagickFalse ?
4119 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004120 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004121 format);
cristy3ed852e2009-09-05 21:47:34 +00004122 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4123 message);
4124 }
cristy3ed852e2009-09-05 21:47:34 +00004125 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004126 cache_info->metacontent=(void *) NULL;
4127 if (cache_info->metacontent_extent != 0)
4128 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004129 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004130 if ((source_info.storage_class != UndefinedClass) &&
4131 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004132 {
cristy4c08aed2011-07-01 19:47:50 +00004133 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004134 exception);
4135 RelinquishPixelCachePixels(&source_info);
4136 }
cristy4c08aed2011-07-01 19:47:50 +00004137 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004138 }
4139 }
4140 RelinquishMagickResource(MemoryResource,cache_info->length);
4141 }
4142 /*
4143 Create pixel cache on disk.
4144 */
4145 status=AcquireMagickResource(DiskResource,cache_info->length);
4146 if (status == MagickFalse)
4147 {
4148 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4149 "CacheResourcesExhausted","`%s'",image->filename);
4150 return(MagickFalse);
4151 }
cristy413f1302012-01-01 17:48:27 +00004152 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4153 {
4154 (void) ClosePixelCacheOnDisk(cache_info);
4155 *cache_info->cache_filename='\0';
4156 }
cristy3ed852e2009-09-05 21:47:34 +00004157 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4158 {
4159 RelinquishMagickResource(DiskResource,cache_info->length);
4160 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4161 image->filename);
4162 return(MagickFalse);
4163 }
4164 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4165 cache_info->length);
4166 if (status == MagickFalse)
4167 {
4168 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4169 image->filename);
4170 return(MagickFalse);
4171 }
cristyed231572011-07-14 02:18:59 +00004172 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004173 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004174 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004175 cache_info->type=DiskCache;
4176 else
4177 {
4178 status=AcquireMagickResource(MapResource,cache_info->length);
4179 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4180 (cache_info->type != MemoryCache))
4181 cache_info->type=DiskCache;
4182 else
4183 {
cristy4c08aed2011-07-01 19:47:50 +00004184 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004185 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004186 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004187 {
cristy3ed852e2009-09-05 21:47:34 +00004188 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004189 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004190 }
4191 else
4192 {
4193 /*
4194 Create file-backed memory-mapped pixel cache.
4195 */
cristy4c08aed2011-07-01 19:47:50 +00004196 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004197 (void) ClosePixelCacheOnDisk(cache_info);
4198 cache_info->type=MapCache;
4199 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004200 cache_info->metacontent=(void *) NULL;
4201 if (cache_info->metacontent_extent != 0)
4202 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004203 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004204 if ((source_info.storage_class != UndefinedClass) &&
4205 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004206 {
4207 status=ClonePixelCachePixels(cache_info,&source_info,
4208 exception);
4209 RelinquishPixelCachePixels(&source_info);
4210 }
4211 if (image->debug != MagickFalse)
4212 {
cristy413f1302012-01-01 17:48:27 +00004213 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004214 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004215 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004216 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004217 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004218 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004219 format);
cristy3ed852e2009-09-05 21:47:34 +00004220 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4221 message);
4222 }
cristy4c08aed2011-07-01 19:47:50 +00004223 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004224 }
4225 }
4226 RelinquishMagickResource(MapResource,cache_info->length);
4227 }
cristy4c08aed2011-07-01 19:47:50 +00004228 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00004229 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004230 {
4231 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4232 RelinquishPixelCachePixels(&source_info);
4233 }
4234 if (image->debug != MagickFalse)
4235 {
cristyb9080c92009-12-01 20:13:26 +00004236 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004237 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004238 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004239 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004240 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004241 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004242 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4243 }
cristy4c08aed2011-07-01 19:47:50 +00004244 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004245}
4246
4247/*
4248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4249% %
4250% %
4251% %
4252+ P e r s i s t P i x e l C a c h e %
4253% %
4254% %
4255% %
4256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4257%
4258% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4259% persistent pixel cache is one that resides on disk and is not destroyed
4260% when the program exits.
4261%
4262% The format of the PersistPixelCache() method is:
4263%
4264% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4265% const MagickBooleanType attach,MagickOffsetType *offset,
4266% ExceptionInfo *exception)
4267%
4268% A description of each parameter follows:
4269%
4270% o image: the image.
4271%
4272% o filename: the persistent pixel cache filename.
4273%
cristyf3a6a9d2010-11-07 21:02:56 +00004274% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004275%
cristy3ed852e2009-09-05 21:47:34 +00004276% o initialize: A value other than zero initializes the persistent pixel
4277% cache.
4278%
4279% o offset: the offset in the persistent cache to store pixels.
4280%
4281% o exception: return any errors or warnings in this structure.
4282%
4283*/
4284MagickExport MagickBooleanType PersistPixelCache(Image *image,
4285 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4286 ExceptionInfo *exception)
4287{
4288 CacheInfo
4289 *cache_info,
4290 *clone_info;
4291
4292 Image
4293 clone_image;
4294
cristy3ed852e2009-09-05 21:47:34 +00004295 MagickBooleanType
4296 status;
4297
cristye076a6e2010-08-15 19:59:43 +00004298 ssize_t
4299 page_size;
4300
cristy3ed852e2009-09-05 21:47:34 +00004301 assert(image != (Image *) NULL);
4302 assert(image->signature == MagickSignature);
4303 if (image->debug != MagickFalse)
4304 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4305 assert(image->cache != (void *) NULL);
4306 assert(filename != (const char *) NULL);
4307 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004308 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004309 cache_info=(CacheInfo *) image->cache;
4310 assert(cache_info->signature == MagickSignature);
4311 if (attach != MagickFalse)
4312 {
4313 /*
cristy01b7eb02009-09-10 23:10:14 +00004314 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004315 */
4316 if (image->debug != MagickFalse)
4317 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004318 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004319 (void) CopyMagickString(cache_info->cache_filename,filename,
4320 MaxTextExtent);
4321 cache_info->type=DiskCache;
4322 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004323 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004324 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004325 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004326 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004327 }
cristy01b7eb02009-09-10 23:10:14 +00004328 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4329 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004330 {
cristyf84a1932010-01-03 18:00:18 +00004331 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004332 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004333 (cache_info->reference_count == 1))
4334 {
4335 int
4336 status;
4337
4338 /*
cristy01b7eb02009-09-10 23:10:14 +00004339 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004340 */
cristy320684d2011-09-23 14:55:47 +00004341 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004342 if (status == 0)
4343 {
4344 (void) CopyMagickString(cache_info->cache_filename,filename,
4345 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004346 *offset+=cache_info->length+page_size-(cache_info->length %
4347 page_size);
cristyf84a1932010-01-03 18:00:18 +00004348 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004349 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004350 if (image->debug != MagickFalse)
4351 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4352 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004353 return(MagickTrue);
4354 }
4355 }
cristyf84a1932010-01-03 18:00:18 +00004356 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004357 }
4358 /*
cristy01b7eb02009-09-10 23:10:14 +00004359 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004360 */
4361 clone_image=(*image);
4362 clone_info=(CacheInfo *) clone_image.cache;
4363 image->cache=ClonePixelCache(cache_info);
4364 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4365 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4366 cache_info->type=DiskCache;
4367 cache_info->offset=(*offset);
4368 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004369 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004370 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004371 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004372 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004373 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4374 return(status);
4375}
4376
4377/*
4378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4379% %
4380% %
4381% %
4382+ Q u e u e A u t h e n t i c N e x u s %
4383% %
4384% %
4385% %
4386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4387%
4388% QueueAuthenticNexus() allocates an region to store image pixels as defined
4389% by the region rectangle and returns a pointer to the region. This region is
4390% subsequently transferred from the pixel cache with
4391% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4392% pixels are transferred, otherwise a NULL is returned.
4393%
4394% The format of the QueueAuthenticNexus() method is:
4395%
cristy4c08aed2011-07-01 19:47:50 +00004396% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004397% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004398% const MagickBooleanType clone,NexusInfo *nexus_info,
4399% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004400%
4401% A description of each parameter follows:
4402%
4403% o image: the image.
4404%
4405% o x,y,columns,rows: These values define the perimeter of a region of
4406% pixels.
4407%
4408% o nexus_info: the cache nexus to set.
4409%
cristy65dbf172011-10-06 17:32:04 +00004410% o clone: clone the pixel cache.
4411%
cristy3ed852e2009-09-05 21:47:34 +00004412% o exception: return any errors or warnings in this structure.
4413%
4414*/
cristya6577ff2011-09-02 19:54:26 +00004415MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004416 const ssize_t y,const size_t columns,const size_t rows,
4417 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004418{
4419 CacheInfo
4420 *cache_info;
4421
4422 MagickOffsetType
4423 offset;
4424
4425 MagickSizeType
4426 number_pixels;
4427
4428 RectangleInfo
4429 region;
4430
4431 /*
4432 Validate pixel cache geometry.
4433 */
cristye7cc7cf2010-09-21 13:26:47 +00004434 assert(image != (const Image *) NULL);
4435 assert(image->signature == MagickSignature);
4436 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004437 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004438 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004439 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004440 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004441 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4442 {
4443 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4444 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004445 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004446 }
cristybb503372010-05-27 20:51:26 +00004447 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4448 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004449 {
4450 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4451 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004452 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004453 }
4454 offset=(MagickOffsetType) y*cache_info->columns+x;
4455 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004456 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004457 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4458 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4459 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004460 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004461 /*
4462 Return pixel cache.
4463 */
4464 region.x=x;
4465 region.y=y;
4466 region.width=columns;
4467 region.height=rows;
4468 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4469}
4470
4471/*
4472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4473% %
4474% %
4475% %
4476+ 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 %
4477% %
4478% %
4479% %
4480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4481%
4482% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4483% defined by the region rectangle and returns a pointer to the region. This
4484% region is subsequently transferred from the pixel cache with
4485% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4486% pixels are transferred, otherwise a NULL is returned.
4487%
4488% The format of the QueueAuthenticPixelsCache() method is:
4489%
cristy4c08aed2011-07-01 19:47:50 +00004490% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004491% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004492% ExceptionInfo *exception)
4493%
4494% A description of each parameter follows:
4495%
4496% o image: the image.
4497%
4498% o x,y,columns,rows: These values define the perimeter of a region of
4499% pixels.
4500%
4501% o exception: return any errors or warnings in this structure.
4502%
4503*/
cristy4c08aed2011-07-01 19:47:50 +00004504static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004505 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004506 ExceptionInfo *exception)
4507{
4508 CacheInfo
4509 *cache_info;
4510
cristy5c9e6f22010-09-17 17:31:01 +00004511 const int
4512 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004513
cristy4c08aed2011-07-01 19:47:50 +00004514 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004515 *q;
cristy4c08aed2011-07-01 19:47:50 +00004516
cristye7cc7cf2010-09-21 13:26:47 +00004517 assert(image != (const Image *) NULL);
4518 assert(image->signature == MagickSignature);
4519 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004520 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004521 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004522 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004523 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4524 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004525 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004526}
4527
4528/*
4529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4530% %
4531% %
4532% %
4533% Q u e u e A u t h e n t i c P i x e l s %
4534% %
4535% %
4536% %
4537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4538%
4539% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004540% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004541% region is returned, otherwise NULL is returned. The returned pointer may
4542% point to a temporary working buffer for the pixels or it may point to the
4543% final location of the pixels in memory.
4544%
4545% Write-only access means that any existing pixel values corresponding to
4546% the region are ignored. This is useful if the initial image is being
4547% created from scratch, or if the existing pixel values are to be
4548% completely replaced without need to refer to their pre-existing values.
4549% The application is free to read and write the pixel buffer returned by
4550% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4551% initialize the pixel array values. Initializing pixel array values is the
4552% application's responsibility.
4553%
4554% Performance is maximized if the selected region is part of one row, or
4555% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004556% pixels in-place (without a copy) if the image is in memory, or in a
4557% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004558% by the user.
4559%
4560% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004561% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4562% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4563% obtain the meta-content (of type void) corresponding to the region.
4564% Once the Quantum (and/or Quantum) array has been updated, the
4565% changes must be saved back to the underlying image using
4566% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004567%
4568% The format of the QueueAuthenticPixels() method is:
4569%
cristy4c08aed2011-07-01 19:47:50 +00004570% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004571% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004572% ExceptionInfo *exception)
4573%
4574% A description of each parameter follows:
4575%
4576% o image: the image.
4577%
4578% o x,y,columns,rows: These values define the perimeter of a region of
4579% pixels.
4580%
4581% o exception: return any errors or warnings in this structure.
4582%
4583*/
cristy4c08aed2011-07-01 19:47:50 +00004584MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004585 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004586 ExceptionInfo *exception)
4587{
4588 CacheInfo
4589 *cache_info;
4590
cristy2036f5c2010-09-19 21:18:17 +00004591 const int
4592 id = GetOpenMPThreadId();
4593
cristy4c08aed2011-07-01 19:47:50 +00004594 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004595 *q;
cristy4c08aed2011-07-01 19:47:50 +00004596
cristy3ed852e2009-09-05 21:47:34 +00004597 assert(image != (Image *) NULL);
4598 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004599 assert(image->cache != (Cache) NULL);
4600 cache_info=(CacheInfo *) image->cache;
4601 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004602 if (cache_info->methods.queue_authentic_pixels_handler !=
4603 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004604 {
cristyacd2ed22011-08-30 01:44:23 +00004605 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004606 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004607 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004608 }
cristy2036f5c2010-09-19 21:18:17 +00004609 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004610 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4611 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004612 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004613}
4614
4615/*
4616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4617% %
4618% %
4619% %
cristy4c08aed2011-07-01 19:47:50 +00004620+ 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 %
cristy3ed852e2009-09-05 21:47:34 +00004621% %
4622% %
4623% %
4624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4625%
cristy4c08aed2011-07-01 19:47:50 +00004626% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004627% the pixel cache.
4628%
cristy4c08aed2011-07-01 19:47:50 +00004629% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004630%
cristy4c08aed2011-07-01 19:47:50 +00004631% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004632% NexusInfo *nexus_info,ExceptionInfo *exception)
4633%
4634% A description of each parameter follows:
4635%
4636% o cache_info: the pixel cache.
4637%
cristy4c08aed2011-07-01 19:47:50 +00004638% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004639%
4640% o exception: return any errors or warnings in this structure.
4641%
4642*/
cristy4c08aed2011-07-01 19:47:50 +00004643static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004644 NexusInfo *nexus_info,ExceptionInfo *exception)
4645{
4646 MagickOffsetType
4647 count,
4648 offset;
4649
4650 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004651 extent,
4652 length;
cristy3ed852e2009-09-05 21:47:34 +00004653
cristybb503372010-05-27 20:51:26 +00004654 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004655 y;
4656
cristy4c08aed2011-07-01 19:47:50 +00004657 register unsigned char
4658 *restrict q;
4659
cristybb503372010-05-27 20:51:26 +00004660 size_t
cristy3ed852e2009-09-05 21:47:34 +00004661 rows;
4662
cristy4c08aed2011-07-01 19:47:50 +00004663 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004664 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004665 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004666 return(MagickTrue);
4667 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4668 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004669 length=(MagickSizeType) nexus_info->region.width*
4670 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004671 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004672 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004673 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004674 switch (cache_info->type)
4675 {
4676 case MemoryCache:
4677 case MapCache:
4678 {
cristy4c08aed2011-07-01 19:47:50 +00004679 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004680 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004681
4682 /*
cristy4c08aed2011-07-01 19:47:50 +00004683 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004684 */
cristydd341db2010-03-04 19:06:38 +00004685 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004686 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004687 {
cristy48078b12010-09-23 17:11:01 +00004688 length=extent;
cristydd341db2010-03-04 19:06:38 +00004689 rows=1UL;
4690 }
cristy4c08aed2011-07-01 19:47:50 +00004691 p=(unsigned char *) cache_info->metacontent+offset*
4692 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004693 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004694 {
cristy8f036fe2010-09-18 02:02:00 +00004695 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004696 p+=cache_info->metacontent_extent*cache_info->columns;
4697 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004698 }
4699 break;
4700 }
4701 case DiskCache:
4702 {
4703 /*
cristy4c08aed2011-07-01 19:47:50 +00004704 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004705 */
4706 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4707 {
4708 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4709 cache_info->cache_filename);
4710 return(MagickFalse);
4711 }
cristydd341db2010-03-04 19:06:38 +00004712 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004713 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004714 {
cristy48078b12010-09-23 17:11:01 +00004715 length=extent;
cristydd341db2010-03-04 19:06:38 +00004716 rows=1UL;
4717 }
cristy48078b12010-09-23 17:11:01 +00004718 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004719 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004720 {
cristy48078b12010-09-23 17:11:01 +00004721 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004722 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004723 cache_info->metacontent_extent,length,(unsigned char *) q);
4724 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004725 break;
4726 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004727 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004728 }
cristybb503372010-05-27 20:51:26 +00004729 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004730 {
4731 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4732 cache_info->cache_filename);
4733 return(MagickFalse);
4734 }
4735 break;
4736 }
4737 default:
4738 break;
4739 }
4740 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004741 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004742 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004743 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004744 nexus_info->region.width,(double) nexus_info->region.height,(double)
4745 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004746 return(MagickTrue);
4747}
4748
4749/*
4750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4751% %
4752% %
4753% %
4754+ R e a d P i x e l C a c h e P i x e l s %
4755% %
4756% %
4757% %
4758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4759%
4760% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4761% cache.
4762%
4763% The format of the ReadPixelCachePixels() method is:
4764%
4765% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4766% NexusInfo *nexus_info,ExceptionInfo *exception)
4767%
4768% A description of each parameter follows:
4769%
4770% o cache_info: the pixel cache.
4771%
4772% o nexus_info: the cache nexus to read the pixels.
4773%
4774% o exception: return any errors or warnings in this structure.
4775%
4776*/
4777static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4778 NexusInfo *nexus_info,ExceptionInfo *exception)
4779{
4780 MagickOffsetType
4781 count,
4782 offset;
4783
4784 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004785 extent,
4786 length;
cristy3ed852e2009-09-05 21:47:34 +00004787
cristy4c08aed2011-07-01 19:47:50 +00004788 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004789 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004790
cristye076a6e2010-08-15 19:59:43 +00004791 register ssize_t
4792 y;
4793
cristybb503372010-05-27 20:51:26 +00004794 size_t
cristy3ed852e2009-09-05 21:47:34 +00004795 rows;
4796
cristy4c08aed2011-07-01 19:47:50 +00004797 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004798 return(MagickTrue);
4799 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4800 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004801 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004802 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004803 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004804 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004805 q=nexus_info->pixels;
4806 switch (cache_info->type)
4807 {
4808 case MemoryCache:
4809 case MapCache:
4810 {
cristy4c08aed2011-07-01 19:47:50 +00004811 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004812 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004813
4814 /*
4815 Read pixels from memory.
4816 */
cristydd341db2010-03-04 19:06:38 +00004817 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004818 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004819 {
cristy48078b12010-09-23 17:11:01 +00004820 length=extent;
cristydd341db2010-03-04 19:06:38 +00004821 rows=1UL;
4822 }
cristyed231572011-07-14 02:18:59 +00004823 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004824 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004825 {
cristy8f036fe2010-09-18 02:02:00 +00004826 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004827 p+=cache_info->number_channels*cache_info->columns;
4828 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004829 }
4830 break;
4831 }
4832 case DiskCache:
4833 {
4834 /*
4835 Read pixels from disk.
4836 */
4837 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4838 {
4839 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4840 cache_info->cache_filename);
4841 return(MagickFalse);
4842 }
cristydd341db2010-03-04 19:06:38 +00004843 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004844 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004845 {
cristy48078b12010-09-23 17:11:01 +00004846 length=extent;
cristydd341db2010-03-04 19:06:38 +00004847 rows=1UL;
4848 }
cristybb503372010-05-27 20:51:26 +00004849 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004850 {
4851 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004852 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004853 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004854 break;
4855 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004856 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004857 }
cristybb503372010-05-27 20:51:26 +00004858 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004859 {
4860 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4861 cache_info->cache_filename);
4862 return(MagickFalse);
4863 }
4864 break;
4865 }
4866 default:
4867 break;
4868 }
4869 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004870 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004871 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004872 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004873 nexus_info->region.width,(double) nexus_info->region.height,(double)
4874 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004875 return(MagickTrue);
4876}
4877
4878/*
4879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4880% %
4881% %
4882% %
4883+ R e f e r e n c e P i x e l C a c h e %
4884% %
4885% %
4886% %
4887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4888%
4889% ReferencePixelCache() increments the reference count associated with the
4890% pixel cache returning a pointer to the cache.
4891%
4892% The format of the ReferencePixelCache method is:
4893%
4894% Cache ReferencePixelCache(Cache cache_info)
4895%
4896% A description of each parameter follows:
4897%
4898% o cache_info: the pixel cache.
4899%
4900*/
cristya6577ff2011-09-02 19:54:26 +00004901MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004902{
4903 CacheInfo
4904 *cache_info;
4905
4906 assert(cache != (Cache *) NULL);
4907 cache_info=(CacheInfo *) cache;
4908 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004909 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004910 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004911 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004912 return(cache_info);
4913}
4914
4915/*
4916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4917% %
4918% %
4919% %
4920+ S e t P i x e l C a c h e M e t h o d s %
4921% %
4922% %
4923% %
4924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4925%
4926% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4927%
4928% The format of the SetPixelCacheMethods() method is:
4929%
4930% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4931%
4932% A description of each parameter follows:
4933%
4934% o cache: the pixel cache.
4935%
4936% o cache_methods: Specifies a pointer to a CacheMethods structure.
4937%
4938*/
cristya6577ff2011-09-02 19:54:26 +00004939MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004940{
4941 CacheInfo
4942 *cache_info;
4943
4944 GetOneAuthenticPixelFromHandler
4945 get_one_authentic_pixel_from_handler;
4946
4947 GetOneVirtualPixelFromHandler
4948 get_one_virtual_pixel_from_handler;
4949
4950 /*
4951 Set cache pixel methods.
4952 */
4953 assert(cache != (Cache) NULL);
4954 assert(cache_methods != (CacheMethods *) NULL);
4955 cache_info=(CacheInfo *) cache;
4956 assert(cache_info->signature == MagickSignature);
4957 if (cache_info->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4959 cache_info->filename);
4960 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4961 cache_info->methods.get_virtual_pixel_handler=
4962 cache_methods->get_virtual_pixel_handler;
4963 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4964 cache_info->methods.destroy_pixel_handler=
4965 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004966 if (cache_methods->get_virtual_metacontent_from_handler !=
4967 (GetVirtualMetacontentFromHandler) NULL)
4968 cache_info->methods.get_virtual_metacontent_from_handler=
4969 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004970 if (cache_methods->get_authentic_pixels_handler !=
4971 (GetAuthenticPixelsHandler) NULL)
4972 cache_info->methods.get_authentic_pixels_handler=
4973 cache_methods->get_authentic_pixels_handler;
4974 if (cache_methods->queue_authentic_pixels_handler !=
4975 (QueueAuthenticPixelsHandler) NULL)
4976 cache_info->methods.queue_authentic_pixels_handler=
4977 cache_methods->queue_authentic_pixels_handler;
4978 if (cache_methods->sync_authentic_pixels_handler !=
4979 (SyncAuthenticPixelsHandler) NULL)
4980 cache_info->methods.sync_authentic_pixels_handler=
4981 cache_methods->sync_authentic_pixels_handler;
4982 if (cache_methods->get_authentic_pixels_from_handler !=
4983 (GetAuthenticPixelsFromHandler) NULL)
4984 cache_info->methods.get_authentic_pixels_from_handler=
4985 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004986 if (cache_methods->get_authentic_metacontent_from_handler !=
4987 (GetAuthenticMetacontentFromHandler) NULL)
4988 cache_info->methods.get_authentic_metacontent_from_handler=
4989 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004990 get_one_virtual_pixel_from_handler=
4991 cache_info->methods.get_one_virtual_pixel_from_handler;
4992 if (get_one_virtual_pixel_from_handler !=
4993 (GetOneVirtualPixelFromHandler) NULL)
4994 cache_info->methods.get_one_virtual_pixel_from_handler=
4995 cache_methods->get_one_virtual_pixel_from_handler;
4996 get_one_authentic_pixel_from_handler=
4997 cache_methods->get_one_authentic_pixel_from_handler;
4998 if (get_one_authentic_pixel_from_handler !=
4999 (GetOneAuthenticPixelFromHandler) NULL)
5000 cache_info->methods.get_one_authentic_pixel_from_handler=
5001 cache_methods->get_one_authentic_pixel_from_handler;
5002}
5003
5004/*
5005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5006% %
5007% %
5008% %
5009+ S e t P i x e l C a c h e N e x u s P i x e l s %
5010% %
5011% %
5012% %
5013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5014%
5015% SetPixelCacheNexusPixels() defines the region of the cache for the
5016% specified cache nexus.
5017%
5018% The format of the SetPixelCacheNexusPixels() method is:
5019%
cristy4c08aed2011-07-01 19:47:50 +00005020% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005021% const RectangleInfo *region,NexusInfo *nexus_info,
5022% ExceptionInfo *exception)
5023%
5024% A description of each parameter follows:
5025%
5026% o image: the image.
5027%
5028% o region: A pointer to the RectangleInfo structure that defines the
5029% region of this particular cache nexus.
5030%
5031% o nexus_info: the cache nexus to set.
5032%
5033% o exception: return any errors or warnings in this structure.
5034%
5035*/
cristyabd6e372010-09-15 19:11:26 +00005036
5037static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5038 NexusInfo *nexus_info,ExceptionInfo *exception)
5039{
5040 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5041 return(MagickFalse);
5042 nexus_info->mapped=MagickFalse;
cristy7dc8ac52012-01-10 20:14:52 +00005043 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005044 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005045 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005046 {
5047 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005048 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005049 nexus_info->length);
5050 }
cristy4c08aed2011-07-01 19:47:50 +00005051 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005052 {
5053 (void) ThrowMagickException(exception,GetMagickModule(),
5054 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5055 cache_info->filename);
5056 return(MagickFalse);
5057 }
5058 return(MagickTrue);
5059}
5060
cristy4c08aed2011-07-01 19:47:50 +00005061static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005062 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5063{
5064 CacheInfo
5065 *cache_info;
5066
5067 MagickBooleanType
5068 status;
5069
cristy3ed852e2009-09-05 21:47:34 +00005070 MagickSizeType
5071 length,
5072 number_pixels;
5073
cristy3ed852e2009-09-05 21:47:34 +00005074 cache_info=(CacheInfo *) image->cache;
5075 assert(cache_info->signature == MagickSignature);
5076 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005077 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005078 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005079 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5080 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005081 {
cristybb503372010-05-27 20:51:26 +00005082 ssize_t
cristybad067a2010-02-15 17:20:55 +00005083 x,
5084 y;
cristy3ed852e2009-09-05 21:47:34 +00005085
cristyeaedf062010-05-29 22:36:02 +00005086 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5087 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005088 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5089 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005090 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005091 ((nexus_info->region.width == cache_info->columns) ||
5092 ((nexus_info->region.width % cache_info->columns) == 0)))))
5093 {
5094 MagickOffsetType
5095 offset;
5096
5097 /*
5098 Pixels are accessed directly from memory.
5099 */
5100 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5101 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005102 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005103 offset;
5104 nexus_info->metacontent=(void *) NULL;
5105 if (cache_info->metacontent_extent != 0)
5106 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5107 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005108 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005109 }
5110 }
5111 /*
5112 Pixels are stored in a cache region until they are synced to the cache.
5113 */
5114 number_pixels=(MagickSizeType) nexus_info->region.width*
5115 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005116 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005117 if (cache_info->metacontent_extent != 0)
5118 length+=number_pixels*cache_info->metacontent_extent;
5119 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005120 {
5121 nexus_info->length=length;
5122 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5123 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005124 {
5125 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005126 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005127 }
cristy3ed852e2009-09-05 21:47:34 +00005128 }
5129 else
5130 if (nexus_info->length != length)
5131 {
5132 RelinquishCacheNexusPixels(nexus_info);
5133 nexus_info->length=length;
5134 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5135 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005136 {
5137 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005138 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005139 }
cristy3ed852e2009-09-05 21:47:34 +00005140 }
5141 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005142 nexus_info->metacontent=(void *) NULL;
5143 if (cache_info->metacontent_extent != 0)
5144 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005145 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005146 return(nexus_info->pixels);
5147}
5148
5149/*
5150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151% %
5152% %
5153% %
5154% 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 %
5155% %
5156% %
5157% %
5158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5159%
5160% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5161% pixel cache and returns the previous setting. A virtual pixel is any pixel
5162% access that is outside the boundaries of the image cache.
5163%
5164% The format of the SetPixelCacheVirtualMethod() method is:
5165%
5166% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5167% const VirtualPixelMethod virtual_pixel_method)
5168%
5169% A description of each parameter follows:
5170%
5171% o image: the image.
5172%
5173% o virtual_pixel_method: choose the type of virtual pixel.
5174%
5175*/
cristyd1dd6e42011-09-04 01:46:08 +00005176MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005177 const VirtualPixelMethod virtual_pixel_method)
5178{
5179 CacheInfo
5180 *cache_info;
5181
5182 VirtualPixelMethod
5183 method;
5184
5185 assert(image != (Image *) NULL);
5186 assert(image->signature == MagickSignature);
5187 if (image->debug != MagickFalse)
5188 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5189 assert(image->cache != (Cache) NULL);
5190 cache_info=(CacheInfo *) image->cache;
5191 assert(cache_info->signature == MagickSignature);
5192 method=cache_info->virtual_pixel_method;
5193 cache_info->virtual_pixel_method=virtual_pixel_method;
5194 return(method);
5195}
5196
5197/*
5198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5199% %
5200% %
5201% %
5202+ 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 %
5203% %
5204% %
5205% %
5206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5207%
5208% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5209% in-memory or disk cache. The method returns MagickTrue if the pixel region
5210% is synced, otherwise MagickFalse.
5211%
5212% The format of the SyncAuthenticPixelCacheNexus() method is:
5213%
5214% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5215% NexusInfo *nexus_info,ExceptionInfo *exception)
5216%
5217% A description of each parameter follows:
5218%
5219% o image: the image.
5220%
5221% o nexus_info: the cache nexus to sync.
5222%
5223% o exception: return any errors or warnings in this structure.
5224%
5225*/
cristya6577ff2011-09-02 19:54:26 +00005226MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005227 NexusInfo *nexus_info,ExceptionInfo *exception)
5228{
5229 CacheInfo
5230 *cache_info;
5231
5232 MagickBooleanType
5233 status;
5234
5235 /*
5236 Transfer pixels to the cache.
5237 */
5238 assert(image != (Image *) NULL);
5239 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005240 if (image->cache == (Cache) NULL)
5241 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5242 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005243 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005244 if (cache_info->type == UndefinedCache)
5245 return(MagickFalse);
5246 if ((image->clip_mask != (Image *) NULL) &&
5247 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5248 return(MagickFalse);
5249 if ((image->mask != (Image *) NULL) &&
5250 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5251 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005252 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005253 return(MagickTrue);
5254 assert(cache_info->signature == MagickSignature);
5255 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005256 if ((cache_info->metacontent_extent != 0) &&
5257 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005258 return(MagickFalse);
5259 return(status);
5260}
5261
5262/*
5263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5264% %
5265% %
5266% %
5267+ S y n c A u t h e n t i c P i x e l C a c h e %
5268% %
5269% %
5270% %
5271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5272%
5273% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5274% or disk cache. The method returns MagickTrue if the pixel region is synced,
5275% otherwise MagickFalse.
5276%
5277% The format of the SyncAuthenticPixelsCache() method is:
5278%
5279% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5280% ExceptionInfo *exception)
5281%
5282% A description of each parameter follows:
5283%
5284% o image: the image.
5285%
5286% o exception: return any errors or warnings in this structure.
5287%
5288*/
5289static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5290 ExceptionInfo *exception)
5291{
5292 CacheInfo
5293 *cache_info;
5294
cristy5c9e6f22010-09-17 17:31:01 +00005295 const int
5296 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005297
cristy4c08aed2011-07-01 19:47:50 +00005298 MagickBooleanType
5299 status;
5300
cristye7cc7cf2010-09-21 13:26:47 +00005301 assert(image != (Image *) NULL);
5302 assert(image->signature == MagickSignature);
5303 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005304 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005305 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005306 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005307 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5308 exception);
5309 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005310}
5311
5312/*
5313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5314% %
5315% %
5316% %
5317% S y n c A u t h e n t i c P i x e l s %
5318% %
5319% %
5320% %
5321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5322%
5323% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5324% The method returns MagickTrue if the pixel region is flushed, otherwise
5325% MagickFalse.
5326%
5327% The format of the SyncAuthenticPixels() method is:
5328%
5329% MagickBooleanType SyncAuthenticPixels(Image *image,
5330% ExceptionInfo *exception)
5331%
5332% A description of each parameter follows:
5333%
5334% o image: the image.
5335%
5336% o exception: return any errors or warnings in this structure.
5337%
5338*/
5339MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5340 ExceptionInfo *exception)
5341{
5342 CacheInfo
5343 *cache_info;
5344
cristy2036f5c2010-09-19 21:18:17 +00005345 const int
5346 id = GetOpenMPThreadId();
5347
cristy4c08aed2011-07-01 19:47:50 +00005348 MagickBooleanType
5349 status;
5350
cristy3ed852e2009-09-05 21:47:34 +00005351 assert(image != (Image *) NULL);
5352 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005353 assert(image->cache != (Cache) NULL);
5354 cache_info=(CacheInfo *) image->cache;
5355 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005356 if (cache_info->methods.sync_authentic_pixels_handler !=
5357 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005358 {
5359 status=cache_info->methods.sync_authentic_pixels_handler(image,
5360 exception);
5361 return(status);
5362 }
cristy2036f5c2010-09-19 21:18:17 +00005363 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005364 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5365 exception);
5366 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005367}
5368
5369/*
5370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5371% %
5372% %
5373% %
cristyd1dd6e42011-09-04 01:46:08 +00005374+ S y n c I m a g e P i x e l C a c h e %
cristy6e437132011-08-12 13:02:19 +00005375% %
5376% %
5377% %
5378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5379%
5380% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5381% The method returns MagickTrue if the pixel region is flushed, otherwise
5382% MagickFalse.
5383%
5384% The format of the SyncImagePixelCache() method is:
5385%
5386% MagickBooleanType SyncImagePixelCache(Image *image,
5387% ExceptionInfo *exception)
5388%
5389% A description of each parameter follows:
5390%
5391% o image: the image.
5392%
5393% o exception: return any errors or warnings in this structure.
5394%
5395*/
cristyd1dd6e42011-09-04 01:46:08 +00005396MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005397 ExceptionInfo *exception)
5398{
5399 CacheInfo
5400 *cache_info;
5401
5402 assert(image != (Image *) NULL);
5403 assert(exception != (ExceptionInfo *) NULL);
5404 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5405 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5406}
5407
5408/*
5409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5410% %
5411% %
5412% %
cristy4c08aed2011-07-01 19:47:50 +00005413+ 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 %
cristy3ed852e2009-09-05 21:47:34 +00005414% %
5415% %
5416% %
5417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5418%
cristy4c08aed2011-07-01 19:47:50 +00005419% WritePixelCacheMetacontent() writes the meta-content to the specified region
5420% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005421%
cristy4c08aed2011-07-01 19:47:50 +00005422% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005423%
cristy4c08aed2011-07-01 19:47:50 +00005424% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005425% NexusInfo *nexus_info,ExceptionInfo *exception)
5426%
5427% A description of each parameter follows:
5428%
5429% o cache_info: the pixel cache.
5430%
cristy4c08aed2011-07-01 19:47:50 +00005431% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005432%
5433% o exception: return any errors or warnings in this structure.
5434%
5435*/
cristy4c08aed2011-07-01 19:47:50 +00005436static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005437 NexusInfo *nexus_info,ExceptionInfo *exception)
5438{
5439 MagickOffsetType
5440 count,
5441 offset;
5442
5443 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005444 extent,
5445 length;
cristy3ed852e2009-09-05 21:47:34 +00005446
cristy4c08aed2011-07-01 19:47:50 +00005447 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005448 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005449
cristybb503372010-05-27 20:51:26 +00005450 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005451 y;
5452
cristybb503372010-05-27 20:51:26 +00005453 size_t
cristy3ed852e2009-09-05 21:47:34 +00005454 rows;
5455
cristy4c08aed2011-07-01 19:47:50 +00005456 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005457 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005458 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005459 return(MagickTrue);
5460 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5461 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005462 length=(MagickSizeType) nexus_info->region.width*
5463 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005464 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005465 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005466 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005467 switch (cache_info->type)
5468 {
5469 case MemoryCache:
5470 case MapCache:
5471 {
cristy4c08aed2011-07-01 19:47:50 +00005472 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005473 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005474
5475 /*
cristy4c08aed2011-07-01 19:47:50 +00005476 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005477 */
cristydd341db2010-03-04 19:06:38 +00005478 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005479 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005480 {
cristy48078b12010-09-23 17:11:01 +00005481 length=extent;
cristydd341db2010-03-04 19:06:38 +00005482 rows=1UL;
5483 }
cristy4c08aed2011-07-01 19:47:50 +00005484 q=(unsigned char *) cache_info->metacontent+offset*
5485 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005486 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005487 {
cristy8f036fe2010-09-18 02:02:00 +00005488 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005489 p+=nexus_info->region.width*cache_info->metacontent_extent;
5490 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005491 }
5492 break;
5493 }
5494 case DiskCache:
5495 {
5496 /*
cristy4c08aed2011-07-01 19:47:50 +00005497 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005498 */
5499 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5500 {
5501 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5502 cache_info->cache_filename);
5503 return(MagickFalse);
5504 }
cristydd341db2010-03-04 19:06:38 +00005505 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005506 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005507 {
cristy48078b12010-09-23 17:11:01 +00005508 length=extent;
cristydd341db2010-03-04 19:06:38 +00005509 rows=1UL;
5510 }
cristy48078b12010-09-23 17:11:01 +00005511 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005512 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005513 {
cristy48078b12010-09-23 17:11:01 +00005514 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005515 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005516 cache_info->metacontent_extent,length,(const unsigned char *) p);
5517 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005518 break;
cristy4c08aed2011-07-01 19:47:50 +00005519 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005520 offset+=cache_info->columns;
5521 }
cristybb503372010-05-27 20:51:26 +00005522 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005523 {
5524 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5525 cache_info->cache_filename);
5526 return(MagickFalse);
5527 }
5528 break;
5529 }
5530 default:
5531 break;
5532 }
5533 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005534 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005535 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005536 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005537 nexus_info->region.width,(double) nexus_info->region.height,(double)
5538 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005539 return(MagickTrue);
5540}
5541
5542/*
5543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5544% %
5545% %
5546% %
5547+ W r i t e C a c h e P i x e l s %
5548% %
5549% %
5550% %
5551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5552%
5553% WritePixelCachePixels() writes image pixels to the specified region of the
5554% pixel cache.
5555%
5556% The format of the WritePixelCachePixels() method is:
5557%
5558% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5559% NexusInfo *nexus_info,ExceptionInfo *exception)
5560%
5561% A description of each parameter follows:
5562%
5563% o cache_info: the pixel cache.
5564%
5565% o nexus_info: the cache nexus to write the pixels.
5566%
5567% o exception: return any errors or warnings in this structure.
5568%
5569*/
5570static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5571 NexusInfo *nexus_info,ExceptionInfo *exception)
5572{
5573 MagickOffsetType
5574 count,
5575 offset;
5576
5577 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005578 extent,
5579 length;
cristy3ed852e2009-09-05 21:47:34 +00005580
cristy4c08aed2011-07-01 19:47:50 +00005581 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005582 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005583
cristybb503372010-05-27 20:51:26 +00005584 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005585 y;
5586
cristybb503372010-05-27 20:51:26 +00005587 size_t
cristy3ed852e2009-09-05 21:47:34 +00005588 rows;
5589
cristy4c08aed2011-07-01 19:47:50 +00005590 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005591 return(MagickTrue);
5592 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5593 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005594 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005595 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005596 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005597 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005598 p=nexus_info->pixels;
5599 switch (cache_info->type)
5600 {
5601 case MemoryCache:
5602 case MapCache:
5603 {
cristy4c08aed2011-07-01 19:47:50 +00005604 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005605 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005606
5607 /*
5608 Write pixels to memory.
5609 */
cristydd341db2010-03-04 19:06:38 +00005610 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005611 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005612 {
cristy48078b12010-09-23 17:11:01 +00005613 length=extent;
cristydd341db2010-03-04 19:06:38 +00005614 rows=1UL;
5615 }
cristyed231572011-07-14 02:18:59 +00005616 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005617 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005618 {
cristy8f036fe2010-09-18 02:02:00 +00005619 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005620 p+=nexus_info->region.width*cache_info->number_channels;
5621 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005622 }
5623 break;
5624 }
5625 case DiskCache:
5626 {
5627 /*
5628 Write pixels to disk.
5629 */
5630 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5631 {
5632 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5633 cache_info->cache_filename);
5634 return(MagickFalse);
5635 }
cristydd341db2010-03-04 19:06:38 +00005636 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005637 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005638 {
cristy48078b12010-09-23 17:11:01 +00005639 length=extent;
cristydd341db2010-03-04 19:06:38 +00005640 rows=1UL;
5641 }
cristybb503372010-05-27 20:51:26 +00005642 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005643 {
5644 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005645 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005646 p);
5647 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005648 break;
cristyed231572011-07-14 02:18:59 +00005649 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005650 offset+=cache_info->columns;
5651 }
cristybb503372010-05-27 20:51:26 +00005652 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005653 {
5654 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5655 cache_info->cache_filename);
5656 return(MagickFalse);
5657 }
5658 break;
5659 }
5660 default:
5661 break;
5662 }
5663 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005664 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005665 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005666 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005667 nexus_info->region.width,(double) nexus_info->region.height,(double)
5668 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005669 return(MagickTrue);
5670}