blob: f59dd567f410b72d86cc6c5a7f525fe2230cd378 [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 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(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 /*
428 Apply clip mask.
429 */
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);
469 if (traits != UndefinedPixelTrait)
470 q[i]=p[i];
cristy3ed852e2009-09-05 21:47:34 +0000471 }
cristyed231572011-07-14 02:18:59 +0000472 p+=GetPixelChannels(image);
473 q+=GetPixelChannels(image);
474 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000475 }
476 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
477 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristy12006112012-01-02 17:06:42 +0000478 if (x < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000479 return(MagickFalse);
480 return(MagickTrue);
481}
482
483/*
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485% %
486% %
487% %
488+ C l o n e P i x e l C a c h e %
489% %
490% %
491% %
492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493%
494% ClonePixelCache() clones a pixel cache.
495%
496% The format of the ClonePixelCache() method is:
497%
498% Cache ClonePixelCache(const Cache cache)
499%
500% A description of each parameter follows:
501%
502% o cache: the pixel cache.
503%
504*/
cristya6577ff2011-09-02 19:54:26 +0000505MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000506{
507 CacheInfo
508 *clone_info;
509
510 const CacheInfo
511 *cache_info;
512
cristy9f027d12011-09-21 01:17:17 +0000513 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000514 cache_info=(const CacheInfo *) cache;
515 assert(cache_info->signature == MagickSignature);
516 if (cache_info->debug != MagickFalse)
517 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
518 cache_info->filename);
519 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
520 if (clone_info == (Cache) NULL)
521 return((Cache) NULL);
522 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
523 return((Cache ) clone_info);
524}
525
526/*
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
528% %
529% %
530% %
cristy60c44a82009-10-07 00:58:49 +0000531+ 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 +0000532% %
533% %
534% %
535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
536% ClonePixelCachePixels() clones the source pixel cache to the destination
537% cache.
538%
539% The format of the ClonePixelCachePixels() method is:
540%
541% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
542% CacheInfo *source_info,ExceptionInfo *exception)
543%
544% A description of each parameter follows:
545%
546% o cache_info: the pixel cache.
547%
548% o source_info: the source pixel cache.
549%
550% o exception: return any errors or warnings in this structure.
551%
552*/
553
554static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
555{
556 int
557 status;
558
cristy5ee247a2010-02-12 15:42:34 +0000559 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000560 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000561 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000562 {
563 status=close(cache_info->file);
564 cache_info->file=(-1);
565 RelinquishMagickResource(FileResource,1);
566 }
cristyf84a1932010-01-03 18:00:18 +0000567 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000568 return(status == -1 ? MagickFalse : MagickTrue);
569}
570
571static void LimitPixelCacheDescriptors(void)
572{
573 register CacheInfo
574 *p,
575 *q;
576
577 /*
578 Limit # of open file descriptors.
579 */
580 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
581 return;
cristyf84a1932010-01-03 18:00:18 +0000582 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000583 if (cache_resources == (SplayTreeInfo *) NULL)
584 {
cristyf84a1932010-01-03 18:00:18 +0000585 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000586 return;
587 }
588 ResetSplayTreeIterator(cache_resources);
589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 while (p != (CacheInfo *) NULL)
591 {
592 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000593 break;
cristy3ed852e2009-09-05 21:47:34 +0000594 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
595 }
596 for (q=p; p != (CacheInfo *) NULL; )
597 {
598 if ((p->type == DiskCache) && (p->file != -1) &&
599 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000600 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000601 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
602 }
603 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000604 {
605 /*
606 Close least recently used cache.
607 */
608 (void) close(q->file);
609 q->file=(-1);
610 }
cristyf84a1932010-01-03 18:00:18 +0000611 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000612}
613
614static inline MagickSizeType MagickMax(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x > y)
618 return(x);
619 return(y);
620}
621
622static inline MagickSizeType MagickMin(const MagickSizeType x,
623 const MagickSizeType y)
624{
625 if (x < y)
626 return(x);
627 return(y);
628}
629
630static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
631 const MapMode mode)
632{
633 int
634 file;
635
636 /*
637 Open pixel cache on disk.
638 */
cristyf84a1932010-01-03 18:00:18 +0000639 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000640 if (cache_info->file != -1)
641 {
cristyf84a1932010-01-03 18:00:18 +0000642 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000643 return(MagickTrue); /* cache already open */
644 }
645 LimitPixelCacheDescriptors();
646 if (*cache_info->cache_filename == '\0')
647 file=AcquireUniqueFileResource(cache_info->cache_filename);
648 else
649 switch (mode)
650 {
651 case ReadMode:
652 {
cristy18c6c272011-09-23 14:40:37 +0000653 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case WriteMode:
657 {
cristy18c6c272011-09-23 14:40:37 +0000658 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
659 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000660 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000661 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000662 break;
663 }
664 case IOMode:
665 default:
666 {
cristy18c6c272011-09-23 14:40:37 +0000667 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000668 O_EXCL,S_MODE);
669 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000670 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000671 break;
672 }
673 }
674 if (file == -1)
675 {
cristyf84a1932010-01-03 18:00:18 +0000676 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000677 return(MagickFalse);
678 }
679 (void) AcquireMagickResource(FileResource,1);
680 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000681 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000682 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000683 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000684 return(MagickTrue);
685}
686
687static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
688 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000689 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000690{
691 register MagickOffsetType
692 i;
693
694 ssize_t
695 count;
696
cristy08a88202010-03-04 19:18:05 +0000697 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000698#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000699 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000700 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000701 {
cristyf84a1932010-01-03 18:00:18 +0000702 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000703 return((MagickOffsetType) -1);
704 }
705#endif
706 count=0;
707 for (i=0; i < (MagickOffsetType) length; i+=count)
708 {
709#if !defined(MAGICKCORE_HAVE_PREAD)
710 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
711 (MagickSizeType) SSIZE_MAX));
712#else
713 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000714 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000715#endif
716 if (count > 0)
717 continue;
718 count=0;
719 if (errno != EINTR)
720 {
721 i=(-1);
722 break;
723 }
724 }
725#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000726 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000727#endif
728 return(i);
729}
730
731static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
732 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000733 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000734{
735 register MagickOffsetType
736 i;
737
738 ssize_t
739 count;
740
cristy08a88202010-03-04 19:18:05 +0000741 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000742#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000743 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000744 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000745 {
cristyf84a1932010-01-03 18:00:18 +0000746 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000747 return((MagickOffsetType) -1);
748 }
749#endif
750 count=0;
751 for (i=0; i < (MagickOffsetType) length; i+=count)
752 {
753#if !defined(MAGICKCORE_HAVE_PWRITE)
754 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
755 (MagickSizeType) SSIZE_MAX));
756#else
757 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000758 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000759#endif
760 if (count > 0)
761 continue;
762 count=0;
763 if (errno != EINTR)
764 {
765 i=(-1);
766 break;
767 }
768 }
769#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000770 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000771#endif
772 return(i);
773}
774
cristy4c08aed2011-07-01 19:47:50 +0000775static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000776 CacheInfo *cache_info,ExceptionInfo *exception)
777{
778 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000779 count;
cristy3ed852e2009-09-05 21:47:34 +0000780
cristy4c08aed2011-07-01 19:47:50 +0000781 register MagickOffsetType
782 i;
cristye076a6e2010-08-15 19:59:43 +0000783
cristybb503372010-05-27 20:51:26 +0000784 size_t
cristy4c08aed2011-07-01 19:47:50 +0000785 length;
cristy3ed852e2009-09-05 21:47:34 +0000786
cristy4c08aed2011-07-01 19:47:50 +0000787 unsigned char
788 *blob;
789
790 /*
791 Clone pixel cache (both caches on disk).
792 */
cristy3ed852e2009-09-05 21:47:34 +0000793 if (cache_info->debug != MagickFalse)
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000795 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000796 sizeof(*blob));
797 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000798 {
cristy4c08aed2011-07-01 19:47:50 +0000799 (void) ThrowMagickException(exception,GetMagickModule(),
800 ResourceLimitError,"MemoryAllocationFailed","`%s'",
801 cache_info->filename);
802 return(MagickFalse);
803 }
cristy3dedf062011-07-02 14:07:40 +0000804 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000805 {
806 blob=(unsigned char *) RelinquishMagickMemory(blob);
807 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
808 cache_info->cache_filename);
809 return(MagickFalse);
810 }
cristy3dedf062011-07-02 14:07:40 +0000811 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000812 {
813 (void) ClosePixelCacheOnDisk(cache_info);
814 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000815 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
816 clone_info->cache_filename);
817 return(MagickFalse);
818 }
cristy4c08aed2011-07-01 19:47:50 +0000819 count=0;
820 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000821 {
cristy4c08aed2011-07-01 19:47:50 +0000822 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
823 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
824 blob);
825 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000826 {
cristy4c08aed2011-07-01 19:47:50 +0000827 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
828 cache_info->cache_filename);
829 break;
cristy3ed852e2009-09-05 21:47:34 +0000830 }
cristy4c08aed2011-07-01 19:47:50 +0000831 length=(size_t) count;
832 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
833 if ((MagickSizeType) count != length)
834 {
835 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
836 clone_info->cache_filename);
837 break;
838 }
839 }
840 (void) ClosePixelCacheOnDisk(clone_info);
841 (void) ClosePixelCacheOnDisk(cache_info);
842 blob=(unsigned char *) RelinquishMagickMemory(blob);
843 if (i < (MagickOffsetType) cache_info->length)
844 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000845 return(MagickTrue);
846}
847
cristyfd24a062012-01-02 14:46:34 +0000848static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000849 CacheInfo *cache_info,ExceptionInfo *exception)
850{
851 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000852 count;
cristy3ed852e2009-09-05 21:47:34 +0000853
cristy4c08aed2011-07-01 19:47:50 +0000854 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000855 {
cristy3ed852e2009-09-05 21:47:34 +0000856 /*
cristy4c08aed2011-07-01 19:47:50 +0000857 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000858 */
cristy4c08aed2011-07-01 19:47:50 +0000859 if (cache_info->debug != MagickFalse)
860 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
861 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
862 cache_info->length);
863 return(MagickTrue);
864 }
865 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
866 {
867 /*
868 Clone pixel cache (one cache on disk, one in memory).
869 */
870 if (cache_info->debug != MagickFalse)
871 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
872 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000873 {
cristy4c08aed2011-07-01 19:47:50 +0000874 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000875 cache_info->cache_filename);
876 return(MagickFalse);
877 }
cristy4c08aed2011-07-01 19:47:50 +0000878 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
879 cache_info->length,(unsigned char *) clone_info->pixels);
880 (void) ClosePixelCacheOnDisk(cache_info);
881 if ((MagickSizeType) count != cache_info->length)
882 {
883 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
884 cache_info->cache_filename);
885 return(MagickFalse);
886 }
887 return(MagickTrue);
888 }
889 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
890 {
891 /*
892 Clone pixel cache (one cache on disk, one in memory).
893 */
894 if (clone_info->debug != MagickFalse)
895 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
896 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
897 {
898 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
899 clone_info->cache_filename);
900 return(MagickFalse);
901 }
902 count=WritePixelCacheRegion(clone_info,clone_info->offset,
903 clone_info->length,(unsigned char *) cache_info->pixels);
904 (void) ClosePixelCacheOnDisk(clone_info);
905 if ((MagickSizeType) count != clone_info->length)
906 {
907 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
908 clone_info->cache_filename);
909 return(MagickFalse);
910 }
911 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000912 }
913 /*
cristy4c08aed2011-07-01 19:47:50 +0000914 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000915 */
cristy4c08aed2011-07-01 19:47:50 +0000916 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000917}
918
cristyfd24a062012-01-02 14:46:34 +0000919static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000920 CacheInfo *cache_info,ExceptionInfo *exception)
921{
cristy4c08aed2011-07-01 19:47:50 +0000922 MagickBooleanType
923 status;
cristy3ed852e2009-09-05 21:47:34 +0000924
cristy4c08aed2011-07-01 19:47:50 +0000925 MagickOffsetType
926 cache_offset,
927 clone_offset,
928 count;
929
930 register ssize_t
931 x;
932
cristyfd24a062012-01-02 14:46:34 +0000933 register unsigned char
934 *p;
935
cristy4c08aed2011-07-01 19:47:50 +0000936 size_t
cristy3ed852e2009-09-05 21:47:34 +0000937 length;
938
cristy4c08aed2011-07-01 19:47:50 +0000939 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000940 y;
941
cristy4c08aed2011-07-01 19:47:50 +0000942 unsigned char
943 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000944
cristy4c08aed2011-07-01 19:47:50 +0000945 /*
946 Clone pixel cache (unoptimized).
947 */
cristy3ed852e2009-09-05 21:47:34 +0000948 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000949 {
cristy4c08aed2011-07-01 19:47:50 +0000950 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
952 else
953 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
954 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
955 else
956 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
958 else
959 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
960 }
cristyed231572011-07-14 02:18:59 +0000961 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
962 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000963 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000964 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000965 if (blob == (unsigned char *) NULL)
966 {
967 (void) ThrowMagickException(exception,GetMagickModule(),
968 ResourceLimitError,"MemoryAllocationFailed","`%s'",
969 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000970 return(MagickFalse);
971 }
cristy4c08aed2011-07-01 19:47:50 +0000972 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
973 cache_offset=0;
974 clone_offset=0;
975 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000976 {
cristy4c08aed2011-07-01 19:47:50 +0000977 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000978 {
cristy4c08aed2011-07-01 19:47:50 +0000979 blob=(unsigned char *) RelinquishMagickMemory(blob);
980 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000981 cache_info->cache_filename);
982 return(MagickFalse);
983 }
cristy4c08aed2011-07-01 19:47:50 +0000984 cache_offset=cache_info->offset;
985 }
986 if (clone_info->type == DiskCache)
987 {
cristy3dedf062011-07-02 14:07:40 +0000988 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000989 {
cristy4c08aed2011-07-01 19:47:50 +0000990 blob=(unsigned char *) RelinquishMagickMemory(blob);
991 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
992 clone_info->cache_filename);
993 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000994 }
cristy4c08aed2011-07-01 19:47:50 +0000995 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000996 }
997 /*
cristy4c08aed2011-07-01 19:47:50 +0000998 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000999 */
cristy4c08aed2011-07-01 19:47:50 +00001000 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +00001001 p=blob;
cristy4c08aed2011-07-01 19:47:50 +00001002 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
cristy4c08aed2011-07-01 19:47:50 +00001004 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001005 {
cristy9e0719b2011-12-29 03:45:45 +00001006 register ssize_t
1007 i;
1008
cristy3ed852e2009-09-05 21:47:34 +00001009 /*
cristy4c08aed2011-07-01 19:47:50 +00001010 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001011 */
cristyed231572011-07-14 02:18:59 +00001012 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001013 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001014 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +00001015 else
1016 {
cristyfd24a062012-01-02 14:46:34 +00001017 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001018 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001019 {
cristy4c08aed2011-07-01 19:47:50 +00001020 status=MagickFalse;
1021 break;
cristy3ed852e2009-09-05 21:47:34 +00001022 }
1023 }
cristy4c08aed2011-07-01 19:47:50 +00001024 cache_offset+=length;
1025 if ((y < (ssize_t) clone_info->rows) &&
1026 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001027 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001028 {
cristy9e0719b2011-12-29 03:45:45 +00001029 PixelChannel
1030 channel;
1031
1032 PixelTrait
1033 traits;
1034
1035 ssize_t
1036 offset;
1037
cristy4c08aed2011-07-01 19:47:50 +00001038 /*
cristy3b8fe922011-12-29 18:56:23 +00001039 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001040 */
cristy9e0719b2011-12-29 03:45:45 +00001041 channel=clone_info->channel_map[i].channel;
1042 traits=cache_info->channel_map[channel].traits;
1043 if (traits == UndefinedPixelTrait)
1044 {
cristy0f4425e2011-12-31 20:33:02 +00001045 clone_offset+=sizeof(Quantum);
1046 continue;
cristy9e0719b2011-12-29 03:45:45 +00001047 }
cristy0f4425e2011-12-31 20:33:02 +00001048 offset=cache_info->channel_map[channel].offset;
1049 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001050 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
1051 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +00001052 else
1053 {
cristy0f4425e2011-12-31 20:33:02 +00001054 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +00001055 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +00001056 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +00001057 {
cristy0f4425e2011-12-31 20:33:02 +00001058 status=MagickFalse;
1059 break;
cristy4c08aed2011-07-01 19:47:50 +00001060 }
1061 }
cristy9e0719b2011-12-29 03:45:45 +00001062 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001063 }
1064 }
cristyed231572011-07-14 02:18:59 +00001065 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001066 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1067 for ( ; x < (ssize_t) clone_info->columns; x++)
1068 {
1069 /*
cristy9e0719b2011-12-29 03:45:45 +00001070 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001071 */
1072 if (clone_info->type != DiskCache)
1073 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1074 length);
1075 else
1076 {
1077 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1078 if ((MagickSizeType) count != length)
1079 {
1080 status=MagickFalse;
1081 break;
1082 }
1083 }
1084 clone_offset+=length;
1085 }
1086 }
cristyed231572011-07-14 02:18:59 +00001087 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001088 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1089 for ( ; y < (ssize_t) clone_info->rows; y++)
1090 {
1091 /*
cristy9e0719b2011-12-29 03:45:45 +00001092 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001093 */
1094 for (x=0; x < (ssize_t) clone_info->columns; x++)
1095 {
1096 if (clone_info->type != DiskCache)
1097 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1098 length);
1099 else
1100 {
1101 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1102 if ((MagickSizeType) count != length)
1103 {
1104 status=MagickFalse;
1105 break;
1106 }
1107 }
1108 clone_offset+=length;
1109 }
1110 }
cristy9e0719b2011-12-29 03:45:45 +00001111 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001112 (clone_info->metacontent_extent != 0))
1113 {
1114 /*
1115 Clone metacontent.
1116 */
1117 for (y=0; y < (ssize_t) cache_info->rows; y++)
1118 {
1119 for (x=0; x < (ssize_t) cache_info->columns; x++)
1120 {
1121 /*
1122 Read a set of metacontent.
1123 */
1124 length=cache_info->metacontent_extent;
1125 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001126 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +00001127 else
1128 {
cristyfd24a062012-01-02 14:46:34 +00001129 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001130 if ((MagickSizeType) count != length)
1131 {
1132 status=MagickFalse;
1133 break;
1134 }
1135 }
1136 cache_offset+=length;
1137 if ((y < (ssize_t) clone_info->rows) &&
1138 (x < (ssize_t) clone_info->columns))
1139 {
1140 /*
1141 Write a set of metacontent.
1142 */
1143 length=clone_info->metacontent_extent;
1144 if (clone_info->type != DiskCache)
1145 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +00001146 p,length);
cristy4c08aed2011-07-01 19:47:50 +00001147 else
1148 {
cristyfd24a062012-01-02 14:46:34 +00001149 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001150 if ((MagickSizeType) count != length)
1151 {
1152 status=MagickFalse;
1153 break;
1154 }
1155 }
1156 clone_offset+=length;
1157 }
1158 }
1159 length=clone_info->metacontent_extent;
1160 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1161 for ( ; x < (ssize_t) clone_info->columns; x++)
1162 {
1163 /*
cristy9e0719b2011-12-29 03:45:45 +00001164 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001165 */
1166 if (clone_info->type != DiskCache)
1167 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1168 blob,length);
1169 else
1170 {
cristy208b1002011-08-07 18:51:50 +00001171 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001172 if ((MagickSizeType) count != length)
1173 {
1174 status=MagickFalse;
1175 break;
1176 }
1177 }
1178 clone_offset+=length;
1179 }
1180 }
1181 length=clone_info->metacontent_extent;
1182 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1183 for ( ; y < (ssize_t) clone_info->rows; y++)
1184 {
1185 /*
cristy9e0719b2011-12-29 03:45:45 +00001186 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001187 */
1188 for (x=0; x < (ssize_t) clone_info->columns; x++)
1189 {
1190 if (clone_info->type != DiskCache)
1191 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1192 blob,length);
1193 else
1194 {
1195 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1196 if ((MagickSizeType) count != length)
1197 {
1198 status=MagickFalse;
1199 break;
1200 }
1201 }
1202 clone_offset+=length;
1203 }
1204 }
1205 }
1206 if (clone_info->type == DiskCache)
1207 (void) ClosePixelCacheOnDisk(clone_info);
1208 if (cache_info->type == DiskCache)
1209 (void) ClosePixelCacheOnDisk(cache_info);
1210 blob=(unsigned char *) RelinquishMagickMemory(blob);
1211 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001212}
1213
1214static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1215 CacheInfo *cache_info,ExceptionInfo *exception)
1216{
cristy3dfccb22011-12-28 21:47:20 +00001217 PixelChannelMap
1218 *p,
1219 *q;
1220
cristy5a7fbfb2010-11-06 16:10:59 +00001221 if (cache_info->type == PingCache)
1222 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001223 p=cache_info->channel_map;
1224 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001225 if ((cache_info->columns == clone_info->columns) &&
1226 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001227 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001228 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001229 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001230 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1231 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001232}
1233
1234/*
1235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1236% %
1237% %
1238% %
1239+ C l o n e P i x e l C a c h e M e t h o d s %
1240% %
1241% %
1242% %
1243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1244%
1245% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1246% another.
1247%
1248% The format of the ClonePixelCacheMethods() method is:
1249%
1250% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1251%
1252% A description of each parameter follows:
1253%
1254% o clone: Specifies a pointer to a Cache structure.
1255%
1256% o cache: the pixel cache.
1257%
1258*/
cristya6577ff2011-09-02 19:54:26 +00001259MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001260{
1261 CacheInfo
1262 *cache_info,
1263 *source_info;
1264
1265 assert(clone != (Cache) NULL);
1266 source_info=(CacheInfo *) clone;
1267 assert(source_info->signature == MagickSignature);
1268 if (source_info->debug != MagickFalse)
1269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1270 source_info->filename);
1271 assert(cache != (Cache) NULL);
1272 cache_info=(CacheInfo *) cache;
1273 assert(cache_info->signature == MagickSignature);
1274 source_info->methods=cache_info->methods;
1275}
1276
1277/*
1278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1279% %
1280% %
1281% %
1282+ D e s t r o y I m a g e P i x e l C a c h e %
1283% %
1284% %
1285% %
1286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1287%
1288% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1289%
1290% The format of the DestroyImagePixelCache() method is:
1291%
1292% void DestroyImagePixelCache(Image *image)
1293%
1294% A description of each parameter follows:
1295%
1296% o image: the image.
1297%
1298*/
1299static void DestroyImagePixelCache(Image *image)
1300{
1301 assert(image != (Image *) NULL);
1302 assert(image->signature == MagickSignature);
1303 if (image->debug != MagickFalse)
1304 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1305 if (image->cache == (void *) NULL)
1306 return;
1307 image->cache=DestroyPixelCache(image->cache);
1308}
1309
1310/*
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312% %
1313% %
1314% %
1315+ D e s t r o y I m a g e P i x e l s %
1316% %
1317% %
1318% %
1319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1320%
1321% DestroyImagePixels() deallocates memory associated with the pixel cache.
1322%
1323% The format of the DestroyImagePixels() method is:
1324%
1325% void DestroyImagePixels(Image *image)
1326%
1327% A description of each parameter follows:
1328%
1329% o image: the image.
1330%
1331*/
1332MagickExport void DestroyImagePixels(Image *image)
1333{
1334 CacheInfo
1335 *cache_info;
1336
1337 assert(image != (const Image *) NULL);
1338 assert(image->signature == MagickSignature);
1339 if (image->debug != MagickFalse)
1340 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1341 assert(image->cache != (Cache) NULL);
1342 cache_info=(CacheInfo *) image->cache;
1343 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001344 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1345 {
1346 cache_info->methods.destroy_pixel_handler(image);
1347 return;
1348 }
cristy2036f5c2010-09-19 21:18:17 +00001349 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001350}
1351
1352/*
1353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354% %
1355% %
1356% %
1357+ D e s t r o y P i x e l C a c h e %
1358% %
1359% %
1360% %
1361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362%
1363% DestroyPixelCache() deallocates memory associated with the pixel cache.
1364%
1365% The format of the DestroyPixelCache() method is:
1366%
1367% Cache DestroyPixelCache(Cache cache)
1368%
1369% A description of each parameter follows:
1370%
1371% o cache: the pixel cache.
1372%
1373*/
1374
1375static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1376{
1377 switch (cache_info->type)
1378 {
1379 case MemoryCache:
1380 {
1381 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001382 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001383 cache_info->pixels);
1384 else
cristy4c08aed2011-07-01 19:47:50 +00001385 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001386 (size_t) cache_info->length);
1387 RelinquishMagickResource(MemoryResource,cache_info->length);
1388 break;
1389 }
1390 case MapCache:
1391 {
cristy4c08aed2011-07-01 19:47:50 +00001392 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001393 cache_info->length);
1394 RelinquishMagickResource(MapResource,cache_info->length);
1395 }
1396 case DiskCache:
1397 {
1398 if (cache_info->file != -1)
1399 (void) ClosePixelCacheOnDisk(cache_info);
1400 RelinquishMagickResource(DiskResource,cache_info->length);
1401 break;
1402 }
1403 default:
1404 break;
1405 }
1406 cache_info->type=UndefinedCache;
1407 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001408 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001409}
1410
cristya6577ff2011-09-02 19:54:26 +00001411MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001412{
1413 CacheInfo
1414 *cache_info;
1415
cristy3ed852e2009-09-05 21:47:34 +00001416 assert(cache != (Cache) NULL);
1417 cache_info=(CacheInfo *) cache;
1418 assert(cache_info->signature == MagickSignature);
1419 if (cache_info->debug != MagickFalse)
1420 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1421 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001422 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001423 cache_info->reference_count--;
1424 if (cache_info->reference_count != 0)
1425 {
cristyf84a1932010-01-03 18:00:18 +00001426 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001427 return((Cache) NULL);
1428 }
cristyf84a1932010-01-03 18:00:18 +00001429 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001430 if (cache_resources != (SplayTreeInfo *) NULL)
1431 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001432 if (cache_info->debug != MagickFalse)
1433 {
1434 char
1435 message[MaxTextExtent];
1436
cristyb51dff52011-05-19 16:55:47 +00001437 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001438 cache_info->filename);
1439 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1440 }
cristyc2e1bdd2009-09-10 23:43:34 +00001441 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1442 (cache_info->type != DiskCache)))
1443 RelinquishPixelCachePixels(cache_info);
1444 else
1445 {
1446 RelinquishPixelCachePixels(cache_info);
1447 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1448 }
cristy3ed852e2009-09-05 21:47:34 +00001449 *cache_info->cache_filename='\0';
1450 if (cache_info->nexus_info != (NexusInfo **) NULL)
1451 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1452 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001453 if (cache_info->random_info != (RandomInfo *) NULL)
1454 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001455 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1456 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1457 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1458 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001459 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001460 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001461 cache=(Cache) NULL;
1462 return(cache);
1463}
1464
1465/*
1466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467% %
1468% %
1469% %
1470+ D e s t r o y P i x e l C a c h e N e x u s %
1471% %
1472% %
1473% %
1474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475%
1476% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1477%
1478% The format of the DestroyPixelCacheNexus() method is:
1479%
1480% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001481% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001482%
1483% A description of each parameter follows:
1484%
1485% o nexus_info: the nexus to destroy.
1486%
1487% o number_threads: the number of nexus threads.
1488%
1489*/
1490
1491static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1492{
1493 if (nexus_info->mapped == MagickFalse)
1494 (void) RelinquishMagickMemory(nexus_info->cache);
1495 else
1496 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001497 nexus_info->cache=(Quantum *) NULL;
1498 nexus_info->pixels=(Quantum *) NULL;
1499 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001500 nexus_info->length=0;
1501 nexus_info->mapped=MagickFalse;
1502}
1503
cristya6577ff2011-09-02 19:54:26 +00001504MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001505 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001506{
cristybb503372010-05-27 20:51:26 +00001507 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001508 i;
1509
1510 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001511 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001512 {
cristy4c08aed2011-07-01 19:47:50 +00001513 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001514 RelinquishCacheNexusPixels(nexus_info[i]);
1515 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001516 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001517 }
cristyb41ee102010-10-04 16:46:15 +00001518 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001519 return(nexus_info);
1520}
1521
1522/*
1523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1524% %
1525% %
1526% %
cristy4c08aed2011-07-01 19:47:50 +00001527% 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 +00001528% %
1529% %
1530% %
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532%
cristy4c08aed2011-07-01 19:47:50 +00001533% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1534% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1535% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001536%
cristy4c08aed2011-07-01 19:47:50 +00001537% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001538%
cristy4c08aed2011-07-01 19:47:50 +00001539% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001540%
1541% A description of each parameter follows:
1542%
1543% o image: the image.
1544%
1545*/
cristy4c08aed2011-07-01 19:47:50 +00001546MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001547{
1548 CacheInfo
1549 *cache_info;
1550
cristy5c9e6f22010-09-17 17:31:01 +00001551 const int
1552 id = GetOpenMPThreadId();
1553
cristy4c08aed2011-07-01 19:47:50 +00001554 void
1555 *metacontent;
1556
cristye7cc7cf2010-09-21 13:26:47 +00001557 assert(image != (const Image *) NULL);
1558 assert(image->signature == MagickSignature);
1559 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001560 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001561 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001562 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1563 (GetAuthenticMetacontentFromHandler) NULL)
1564 {
1565 metacontent=cache_info->methods.
1566 get_authentic_metacontent_from_handler(image);
1567 return(metacontent);
1568 }
cristy6ebe97c2010-07-03 01:17:28 +00001569 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001570 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1571 cache_info->nexus_info[id]);
1572 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001573}
1574
1575/*
1576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577% %
1578% %
1579% %
cristy4c08aed2011-07-01 19:47:50 +00001580+ 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 +00001581% %
1582% %
1583% %
1584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585%
cristy4c08aed2011-07-01 19:47:50 +00001586% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1587% with the last call to QueueAuthenticPixelsCache() or
1588% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001589%
cristy4c08aed2011-07-01 19:47:50 +00001590% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001591%
cristy4c08aed2011-07-01 19:47:50 +00001592% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001593%
1594% A description of each parameter follows:
1595%
1596% o image: the image.
1597%
1598*/
cristy4c08aed2011-07-01 19:47:50 +00001599static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001600{
1601 CacheInfo
1602 *cache_info;
1603
cristy2036f5c2010-09-19 21:18:17 +00001604 const int
1605 id = GetOpenMPThreadId();
1606
cristy4c08aed2011-07-01 19:47:50 +00001607 void
1608 *metacontent;
1609
cristy3ed852e2009-09-05 21:47:34 +00001610 assert(image != (const Image *) NULL);
1611 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001612 assert(image->cache != (Cache) NULL);
1613 cache_info=(CacheInfo *) image->cache;
1614 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001615 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001616 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1617 cache_info->nexus_info[id]);
1618 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001619}
1620
1621/*
1622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623% %
1624% %
1625% %
1626+ 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 %
1627% %
1628% %
1629% %
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631%
1632% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1633% disk pixel cache as defined by the geometry parameters. A pointer to the
1634% pixels is returned if the pixels are transferred, otherwise a NULL is
1635% returned.
1636%
1637% The format of the GetAuthenticPixelCacheNexus() method is:
1638%
cristy4c08aed2011-07-01 19:47:50 +00001639% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001640% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001641% NexusInfo *nexus_info,ExceptionInfo *exception)
1642%
1643% A description of each parameter follows:
1644%
1645% o image: the image.
1646%
1647% o x,y,columns,rows: These values define the perimeter of a region of
1648% pixels.
1649%
1650% o nexus_info: the cache nexus to return.
1651%
1652% o exception: return any errors or warnings in this structure.
1653%
1654*/
1655
cristy4c08aed2011-07-01 19:47:50 +00001656static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001657 NexusInfo *nexus_info)
1658{
cristy4c08aed2011-07-01 19:47:50 +00001659 MagickBooleanType
1660 status;
1661
cristy3ed852e2009-09-05 21:47:34 +00001662 MagickOffsetType
1663 offset;
1664
cristy73724512010-04-12 14:43:14 +00001665 if (cache_info->type == PingCache)
1666 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001667 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1668 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001669 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001670 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001671 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001672}
1673
cristya6577ff2011-09-02 19:54:26 +00001674MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001675 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001676 NexusInfo *nexus_info,ExceptionInfo *exception)
1677{
1678 CacheInfo
1679 *cache_info;
1680
cristy4c08aed2011-07-01 19:47:50 +00001681 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001682 *q;
cristy3ed852e2009-09-05 21:47:34 +00001683
1684 /*
1685 Transfer pixels from the cache.
1686 */
1687 assert(image != (Image *) NULL);
1688 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001689 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001690 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001691 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001692 cache_info=(CacheInfo *) image->cache;
1693 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001694 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001695 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001696 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001697 return((Quantum *) NULL);
1698 if (cache_info->metacontent_extent != 0)
1699 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1700 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001701 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001702}
1703
1704/*
1705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1706% %
1707% %
1708% %
1709+ 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 %
1710% %
1711% %
1712% %
1713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1714%
1715% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1716% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1717%
1718% The format of the GetAuthenticPixelsFromCache() method is:
1719%
cristy4c08aed2011-07-01 19:47:50 +00001720% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001721%
1722% A description of each parameter follows:
1723%
1724% o image: the image.
1725%
1726*/
cristy4c08aed2011-07-01 19:47:50 +00001727static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001728{
1729 CacheInfo
1730 *cache_info;
1731
cristy5c9e6f22010-09-17 17:31:01 +00001732 const int
1733 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001734
cristye7cc7cf2010-09-21 13:26:47 +00001735 assert(image != (const Image *) NULL);
1736 assert(image->signature == MagickSignature);
1737 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001738 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001739 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001740 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001741 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001742}
1743
1744/*
1745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1746% %
1747% %
1748% %
1749% G e t A u t h e n t i c P i x e l Q u e u e %
1750% %
1751% %
1752% %
1753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754%
cristy4c08aed2011-07-01 19:47:50 +00001755% GetAuthenticPixelQueue() returns the authentic pixels associated
1756% corresponding with the last call to QueueAuthenticPixels() or
1757% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001758%
1759% The format of the GetAuthenticPixelQueue() method is:
1760%
cristy4c08aed2011-07-01 19:47:50 +00001761% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001762%
1763% A description of each parameter follows:
1764%
1765% o image: the image.
1766%
1767*/
cristy4c08aed2011-07-01 19:47:50 +00001768MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001769{
1770 CacheInfo
1771 *cache_info;
1772
cristy2036f5c2010-09-19 21:18:17 +00001773 const int
1774 id = GetOpenMPThreadId();
1775
cristy3ed852e2009-09-05 21:47:34 +00001776 assert(image != (const Image *) NULL);
1777 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001778 assert(image->cache != (Cache) NULL);
1779 cache_info=(CacheInfo *) image->cache;
1780 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001781 if (cache_info->methods.get_authentic_pixels_from_handler !=
1782 (GetAuthenticPixelsFromHandler) NULL)
1783 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001784 assert(id < (int) cache_info->number_threads);
1785 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001786}
1787
1788/*
1789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790% %
1791% %
1792% %
1793% G e t A u t h e n t i c P i x e l s %
1794% %
1795% %
cristy4c08aed2011-07-01 19:47:50 +00001796% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001797%
1798% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001799% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001800% representing the region is returned, otherwise NULL is returned.
1801%
1802% The returned pointer may point to a temporary working copy of the pixels
1803% or it may point to the original pixels in memory. Performance is maximized
1804% if the selected region is part of one row, or one or more full rows, since
1805% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001806% if the image is in memory, or in a memory-mapped file. The returned pointer
1807% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001808%
1809% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001810% Quantum. If the image has corresponding metacontent,call
1811% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1812% meta-content corresponding to the region. Once the Quantum array has
1813% been updated, the changes must be saved back to the underlying image using
1814% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001815%
1816% The format of the GetAuthenticPixels() method is:
1817%
cristy4c08aed2011-07-01 19:47:50 +00001818% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001819% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001820% ExceptionInfo *exception)
1821%
1822% A description of each parameter follows:
1823%
1824% o image: the image.
1825%
1826% o x,y,columns,rows: These values define the perimeter of a region of
1827% pixels.
1828%
1829% o exception: return any errors or warnings in this structure.
1830%
1831*/
cristy4c08aed2011-07-01 19:47:50 +00001832MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001833 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001834 ExceptionInfo *exception)
1835{
1836 CacheInfo
1837 *cache_info;
1838
cristy2036f5c2010-09-19 21:18:17 +00001839 const int
1840 id = GetOpenMPThreadId();
1841
cristy4c08aed2011-07-01 19:47:50 +00001842 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001843 *q;
cristy4c08aed2011-07-01 19:47:50 +00001844
cristy3ed852e2009-09-05 21:47:34 +00001845 assert(image != (Image *) NULL);
1846 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001847 assert(image->cache != (Cache) NULL);
1848 cache_info=(CacheInfo *) image->cache;
1849 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001850 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001851 (GetAuthenticPixelsHandler) NULL)
1852 {
cristyacd2ed22011-08-30 01:44:23 +00001853 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1854 exception);
1855 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001856 }
cristy2036f5c2010-09-19 21:18:17 +00001857 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001858 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001859 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001860 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001861}
1862
1863/*
1864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1865% %
1866% %
1867% %
1868+ G e t A u t h e n t i c P i x e l s C a c h e %
1869% %
1870% %
1871% %
1872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1873%
1874% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1875% as defined by the geometry parameters. A pointer to the pixels is returned
1876% if the pixels are transferred, otherwise a NULL is returned.
1877%
1878% The format of the GetAuthenticPixelsCache() method is:
1879%
cristy4c08aed2011-07-01 19:47:50 +00001880% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001881% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001882% ExceptionInfo *exception)
1883%
1884% A description of each parameter follows:
1885%
1886% o image: the image.
1887%
1888% o x,y,columns,rows: These values define the perimeter of a region of
1889% pixels.
1890%
1891% o exception: return any errors or warnings in this structure.
1892%
1893*/
cristy4c08aed2011-07-01 19:47:50 +00001894static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001895 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001896 ExceptionInfo *exception)
1897{
1898 CacheInfo
1899 *cache_info;
1900
cristy5c9e6f22010-09-17 17:31:01 +00001901 const int
1902 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001903
cristy4c08aed2011-07-01 19:47:50 +00001904 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001905 *q;
cristy4c08aed2011-07-01 19:47:50 +00001906
cristye7cc7cf2010-09-21 13:26:47 +00001907 assert(image != (const Image *) NULL);
1908 assert(image->signature == MagickSignature);
1909 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001910 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001911 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001912 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001913 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001914 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001915 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001916 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001917 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001918}
1919
1920/*
1921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1922% %
1923% %
1924% %
1925+ G e t I m a g e E x t e n t %
1926% %
1927% %
1928% %
1929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1930%
cristy4c08aed2011-07-01 19:47:50 +00001931% GetImageExtent() returns the extent of the pixels associated corresponding
1932% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001933%
1934% The format of the GetImageExtent() method is:
1935%
1936% MagickSizeType GetImageExtent(const Image *image)
1937%
1938% A description of each parameter follows:
1939%
1940% o image: the image.
1941%
1942*/
1943MagickExport MagickSizeType GetImageExtent(const Image *image)
1944{
1945 CacheInfo
1946 *cache_info;
1947
cristy5c9e6f22010-09-17 17:31:01 +00001948 const int
1949 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001950
cristy3ed852e2009-09-05 21:47:34 +00001951 assert(image != (Image *) NULL);
1952 assert(image->signature == MagickSignature);
1953 if (image->debug != MagickFalse)
1954 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1955 assert(image->cache != (Cache) NULL);
1956 cache_info=(CacheInfo *) image->cache;
1957 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001958 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001959 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001960}
1961
1962/*
1963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964% %
1965% %
1966% %
1967+ G e t I m a g e P i x e l C a c h e %
1968% %
1969% %
1970% %
1971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1972%
1973% GetImagePixelCache() ensures that there is only a single reference to the
1974% pixel cache to be modified, updating the provided cache pointer to point to
1975% a clone of the original pixel cache if necessary.
1976%
1977% The format of the GetImagePixelCache method is:
1978%
1979% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1980% ExceptionInfo *exception)
1981%
1982% A description of each parameter follows:
1983%
1984% o image: the image.
1985%
1986% o clone: any value other than MagickFalse clones the cache pixels.
1987%
1988% o exception: return any errors or warnings in this structure.
1989%
1990*/
cristyaf894d72011-08-06 23:03:10 +00001991
cristy3ed852e2009-09-05 21:47:34 +00001992static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1993{
1994 CacheInfo
1995 *cache_info;
1996
cristy9e0719b2011-12-29 03:45:45 +00001997 PixelChannelMap
1998 *p,
1999 *q;
2000
cristy3ed852e2009-09-05 21:47:34 +00002001 /*
2002 Does the image match the pixel cache morphology?
2003 */
2004 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00002005 p=image->channel_map;
2006 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00002007 if ((image->storage_class != cache_info->storage_class) ||
2008 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002009 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002010 (image->columns != cache_info->columns) ||
2011 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002012 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002013 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002014 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002015 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2016 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2017 return(MagickFalse);
2018 return(MagickTrue);
2019}
2020
cristycd01fae2011-08-06 23:52:42 +00002021static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2022 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002023{
2024 CacheInfo
2025 *cache_info;
2026
cristy3ed852e2009-09-05 21:47:34 +00002027 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002028 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002029 status;
2030
cristy50a10922010-02-15 18:35:25 +00002031 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002032 cpu_throttle = 0,
2033 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002034 time_limit = 0;
2035
cristy1ea34962010-07-01 19:49:21 +00002036 static time_t
cristy208b1002011-08-07 18:51:50 +00002037 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002038
cristyc4f9f132010-03-04 18:50:01 +00002039 status=MagickTrue;
2040 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002041 if (cpu_throttle == 0)
2042 {
2043 char
2044 *limit;
2045
2046 /*
2047 Set CPU throttle in milleseconds.
2048 */
2049 cpu_throttle=MagickResourceInfinity;
2050 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2051 if (limit == (char *) NULL)
2052 limit=GetPolicyValue("throttle");
2053 if (limit != (char *) NULL)
2054 {
2055 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2056 limit=DestroyString(limit);
2057 }
2058 }
2059 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2060 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002061 if (time_limit == 0)
2062 {
cristy6ebe97c2010-07-03 01:17:28 +00002063 /*
2064 Set the exire time in seconds.
2065 */
cristy1ea34962010-07-01 19:49:21 +00002066 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002067 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002068 }
2069 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002070 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002071 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002072 assert(image->cache != (Cache) NULL);
2073 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002074 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002075 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002076 {
cristyceb55ee2010-11-06 16:05:49 +00002077 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002078 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002079 {
cristyceb55ee2010-11-06 16:05:49 +00002080 Image
2081 clone_image;
2082
2083 CacheInfo
2084 *clone_info;
2085
2086 /*
2087 Clone pixel cache.
2088 */
2089 clone_image=(*image);
2090 clone_image.semaphore=AllocateSemaphoreInfo();
2091 clone_image.reference_count=1;
2092 clone_image.cache=ClonePixelCache(cache_info);
2093 clone_info=(CacheInfo *) clone_image.cache;
2094 status=OpenPixelCache(&clone_image,IOMode,exception);
2095 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002096 {
cristy5a7fbfb2010-11-06 16:10:59 +00002097 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002098 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002099 if (status != MagickFalse)
2100 {
cristy979bf772011-08-08 00:04:15 +00002101 if (cache_info->mode == ReadMode)
2102 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002103 destroy=MagickTrue;
2104 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002105 }
2106 }
cristyceb55ee2010-11-06 16:05:49 +00002107 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002108 }
cristyceb55ee2010-11-06 16:05:49 +00002109 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002110 }
cristy4320e0e2009-09-10 15:00:08 +00002111 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002112 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002113 if (status != MagickFalse)
2114 {
2115 /*
2116 Ensure the image matches the pixel cache morphology.
2117 */
2118 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002119 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002120 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2121 status=OpenPixelCache(image,IOMode,exception);
2122 }
cristyf84a1932010-01-03 18:00:18 +00002123 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002124 if (status == MagickFalse)
2125 return((Cache) NULL);
2126 return(image->cache);
2127}
2128
2129/*
2130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2131% %
2132% %
2133% %
2134% G e t O n e A u t h e n t i c P i x e l %
2135% %
2136% %
2137% %
2138%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2139%
2140% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2141% location. The image background color is returned if an error occurs.
2142%
2143% The format of the GetOneAuthenticPixel() method is:
2144%
cristybb503372010-05-27 20:51:26 +00002145% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002146% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002147%
2148% A description of each parameter follows:
2149%
2150% o image: the image.
2151%
2152% o x,y: These values define the location of the pixel to return.
2153%
2154% o pixel: return a pixel at the specified (x,y) location.
2155%
2156% o exception: return any errors or warnings in this structure.
2157%
2158*/
cristyacbbb7c2010-06-30 18:56:48 +00002159MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002160 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002161{
2162 CacheInfo
2163 *cache_info;
2164
cristy4c08aed2011-07-01 19:47:50 +00002165 register Quantum
2166 *q;
cristy2036f5c2010-09-19 21:18:17 +00002167
cristy2ed42f62011-10-02 19:49:57 +00002168 register ssize_t
2169 i;
2170
cristy3ed852e2009-09-05 21:47:34 +00002171 assert(image != (Image *) NULL);
2172 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002173 assert(image->cache != (Cache) NULL);
2174 cache_info=(CacheInfo *) image->cache;
2175 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002176 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002177 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2178 (GetOneAuthenticPixelFromHandler) NULL)
2179 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2180 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002181 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2182 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002183 {
cristy9e0719b2011-12-29 03:45:45 +00002184 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2185 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2186 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2187 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2188 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002189 return(MagickFalse);
2190 }
2191 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2192 {
2193 PixelChannel
2194 channel;
2195
cristye2a912b2011-12-05 20:02:07 +00002196 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002197 pixel[channel]=q[i];
2198 }
cristy2036f5c2010-09-19 21:18:17 +00002199 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002200}
2201
2202/*
2203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204% %
2205% %
2206% %
2207+ 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 %
2208% %
2209% %
2210% %
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212%
2213% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2214% location. The image background color is returned if an error occurs.
2215%
2216% The format of the GetOneAuthenticPixelFromCache() method is:
2217%
2218% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002219% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002220% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002221%
2222% A description of each parameter follows:
2223%
2224% o image: the image.
2225%
2226% o x,y: These values define the location of the pixel to return.
2227%
2228% o pixel: return a pixel at the specified (x,y) location.
2229%
2230% o exception: return any errors or warnings in this structure.
2231%
2232*/
2233static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002234 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002235{
cristy098f78c2010-09-23 17:28:44 +00002236 CacheInfo
2237 *cache_info;
2238
2239 const int
2240 id = GetOpenMPThreadId();
2241
cristy4c08aed2011-07-01 19:47:50 +00002242 register Quantum
2243 *q;
cristy3ed852e2009-09-05 21:47:34 +00002244
cristy2ed42f62011-10-02 19:49:57 +00002245 register ssize_t
2246 i;
2247
cristy0158a4b2010-09-20 13:59:45 +00002248 assert(image != (const Image *) NULL);
2249 assert(image->signature == MagickSignature);
2250 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002251 cache_info=(CacheInfo *) image->cache;
2252 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002253 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002254 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002255 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2256 exception);
2257 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002258 {
cristy9e0719b2011-12-29 03:45:45 +00002259 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2260 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2261 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2262 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2263 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002264 return(MagickFalse);
2265 }
2266 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2267 {
2268 PixelChannel
2269 channel;
2270
cristye2a912b2011-12-05 20:02:07 +00002271 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002272 pixel[channel]=q[i];
2273 }
cristy3ed852e2009-09-05 21:47:34 +00002274 return(MagickTrue);
2275}
2276
2277/*
2278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279% %
2280% %
2281% %
cristy3ed852e2009-09-05 21:47:34 +00002282% G e t O n e V i r t u a l P i x e l %
2283% %
2284% %
2285% %
2286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2287%
2288% GetOneVirtualPixel() returns a single virtual pixel at the specified
2289% (x,y) location. The image background color is returned if an error occurs.
2290% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2291%
2292% The format of the GetOneVirtualPixel() method is:
2293%
cristybb503372010-05-27 20:51:26 +00002294% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002295% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002296%
2297% A description of each parameter follows:
2298%
2299% o image: the image.
2300%
2301% o x,y: These values define the location of the pixel to return.
2302%
2303% o pixel: return a pixel at the specified (x,y) location.
2304%
2305% o exception: return any errors or warnings in this structure.
2306%
2307*/
2308MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002309 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002310{
cristy3ed852e2009-09-05 21:47:34 +00002311 CacheInfo
2312 *cache_info;
2313
cristy0158a4b2010-09-20 13:59:45 +00002314 const int
2315 id = GetOpenMPThreadId();
2316
cristy4c08aed2011-07-01 19:47:50 +00002317 const Quantum
2318 *p;
cristy2036f5c2010-09-19 21:18:17 +00002319
cristy2ed42f62011-10-02 19:49:57 +00002320 register ssize_t
2321 i;
2322
cristy3ed852e2009-09-05 21:47:34 +00002323 assert(image != (const Image *) NULL);
2324 assert(image->signature == MagickSignature);
2325 assert(image->cache != (Cache) NULL);
2326 cache_info=(CacheInfo *) image->cache;
2327 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002328 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002329 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2330 (GetOneVirtualPixelFromHandler) NULL)
2331 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2332 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002333 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002334 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002335 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002336 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002337 {
cristy9e0719b2011-12-29 03:45:45 +00002338 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2339 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2340 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2341 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2342 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002343 return(MagickFalse);
2344 }
2345 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2346 {
2347 PixelChannel
2348 channel;
2349
cristye2a912b2011-12-05 20:02:07 +00002350 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002351 pixel[channel]=p[i];
2352 }
cristy2036f5c2010-09-19 21:18:17 +00002353 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002354}
2355
2356/*
2357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358% %
2359% %
2360% %
2361+ 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 %
2362% %
2363% %
2364% %
2365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2366%
2367% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2368% specified (x,y) location. The image background color is returned if an
2369% error occurs.
2370%
2371% The format of the GetOneVirtualPixelFromCache() method is:
2372%
2373% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002374% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002375% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002376%
2377% A description of each parameter follows:
2378%
2379% o image: the image.
2380%
2381% o virtual_pixel_method: the virtual pixel method.
2382%
2383% o x,y: These values define the location of the pixel to return.
2384%
2385% o pixel: return a pixel at the specified (x,y) location.
2386%
2387% o exception: return any errors or warnings in this structure.
2388%
2389*/
2390static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002391 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002392 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002393{
cristy0158a4b2010-09-20 13:59:45 +00002394 CacheInfo
2395 *cache_info;
2396
2397 const int
2398 id = GetOpenMPThreadId();
2399
cristy4c08aed2011-07-01 19:47:50 +00002400 const Quantum
2401 *p;
cristy3ed852e2009-09-05 21:47:34 +00002402
cristy2ed42f62011-10-02 19:49:57 +00002403 register ssize_t
2404 i;
2405
cristye7cc7cf2010-09-21 13:26:47 +00002406 assert(image != (const Image *) NULL);
2407 assert(image->signature == MagickSignature);
2408 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002409 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002410 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002411 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002412 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002413 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002414 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002415 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002416 {
cristy9e0719b2011-12-29 03:45:45 +00002417 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2418 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2419 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2420 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2421 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002422 return(MagickFalse);
2423 }
2424 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2425 {
2426 PixelChannel
2427 channel;
2428
cristye2a912b2011-12-05 20:02:07 +00002429 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002430 pixel[channel]=p[i];
2431 }
cristy3ed852e2009-09-05 21:47:34 +00002432 return(MagickTrue);
2433}
2434
2435/*
2436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2437% %
2438% %
2439% %
cristy3aa93752011-12-18 15:54:24 +00002440% G e t O n e V i r t u a l P i x e l I n f o %
2441% %
2442% %
2443% %
2444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2445%
2446% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2447% location. The image background color is returned if an error occurs. If
2448% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2449%
2450% The format of the GetOneVirtualPixelInfo() method is:
2451%
2452% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2453% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2454% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2455%
2456% A description of each parameter follows:
2457%
2458% o image: the image.
2459%
2460% o virtual_pixel_method: the virtual pixel method.
2461%
2462% o x,y: these values define the location of the pixel to return.
2463%
2464% o pixel: return a pixel at the specified (x,y) location.
2465%
2466% o exception: return any errors or warnings in this structure.
2467%
2468*/
2469MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2470 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2471 PixelInfo *pixel,ExceptionInfo *exception)
2472{
2473 CacheInfo
2474 *cache_info;
2475
2476 const int
2477 id = GetOpenMPThreadId();
2478
2479 register const Quantum
2480 *p;
2481
2482 assert(image != (const Image *) NULL);
2483 assert(image->signature == MagickSignature);
2484 assert(image->cache != (Cache) NULL);
2485 cache_info=(CacheInfo *) image->cache;
2486 assert(cache_info->signature == MagickSignature);
2487 assert(id < (int) cache_info->number_threads);
2488 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2489 cache_info->nexus_info[id],exception);
2490 GetPixelInfo(image,pixel);
2491 if (p == (const Quantum *) NULL)
2492 return(MagickFalse);
2493 GetPixelInfoPixel(image,p,pixel);
2494 return(MagickTrue);
2495}
2496
2497/*
2498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2499% %
2500% %
2501% %
cristy3ed852e2009-09-05 21:47:34 +00002502+ G e t P i x e l C a c h e C o l o r s p a c e %
2503% %
2504% %
2505% %
2506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2507%
2508% GetPixelCacheColorspace() returns the class type of the pixel cache.
2509%
2510% The format of the GetPixelCacheColorspace() method is:
2511%
2512% Colorspace GetPixelCacheColorspace(Cache cache)
2513%
2514% A description of each parameter follows:
2515%
2516% o cache: the pixel cache.
2517%
2518*/
cristya6577ff2011-09-02 19:54:26 +00002519MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002520{
2521 CacheInfo
2522 *cache_info;
2523
2524 assert(cache != (Cache) NULL);
2525 cache_info=(CacheInfo *) cache;
2526 assert(cache_info->signature == MagickSignature);
2527 if (cache_info->debug != MagickFalse)
2528 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2529 cache_info->filename);
2530 return(cache_info->colorspace);
2531}
2532
2533/*
2534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535% %
2536% %
2537% %
2538+ G e t P i x e l C a c h e M e t h o d s %
2539% %
2540% %
2541% %
2542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543%
2544% GetPixelCacheMethods() initializes the CacheMethods structure.
2545%
2546% The format of the GetPixelCacheMethods() method is:
2547%
2548% void GetPixelCacheMethods(CacheMethods *cache_methods)
2549%
2550% A description of each parameter follows:
2551%
2552% o cache_methods: Specifies a pointer to a CacheMethods structure.
2553%
2554*/
cristya6577ff2011-09-02 19:54:26 +00002555MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002556{
2557 assert(cache_methods != (CacheMethods *) NULL);
2558 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2559 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2560 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002561 cache_methods->get_virtual_metacontent_from_handler=
2562 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002563 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2564 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002565 cache_methods->get_authentic_metacontent_from_handler=
2566 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002567 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2568 cache_methods->get_one_authentic_pixel_from_handler=
2569 GetOneAuthenticPixelFromCache;
2570 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2571 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2572 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2573}
2574
2575/*
2576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2577% %
2578% %
2579% %
2580+ G e t P i x e l C a c h e N e x u s E x t e n t %
2581% %
2582% %
2583% %
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585%
cristy4c08aed2011-07-01 19:47:50 +00002586% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2587% corresponding with the last call to SetPixelCacheNexusPixels() or
2588% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002589%
2590% The format of the GetPixelCacheNexusExtent() method is:
2591%
2592% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2593% NexusInfo *nexus_info)
2594%
2595% A description of each parameter follows:
2596%
2597% o nexus_info: the nexus info.
2598%
2599*/
cristya6577ff2011-09-02 19:54:26 +00002600MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002601 NexusInfo *nexus_info)
2602{
2603 CacheInfo
2604 *cache_info;
2605
2606 MagickSizeType
2607 extent;
2608
cristy9f027d12011-09-21 01:17:17 +00002609 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002610 cache_info=(CacheInfo *) cache;
2611 assert(cache_info->signature == MagickSignature);
2612 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2613 if (extent == 0)
2614 return((MagickSizeType) cache_info->columns*cache_info->rows);
2615 return(extent);
2616}
2617
2618/*
2619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620% %
2621% %
2622% %
cristy4c08aed2011-07-01 19:47:50 +00002623+ 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 +00002624% %
2625% %
2626% %
2627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2628%
cristy4c08aed2011-07-01 19:47:50 +00002629% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2630% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002631%
cristy4c08aed2011-07-01 19:47:50 +00002632% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002633%
cristy4c08aed2011-07-01 19:47:50 +00002634% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002635% NexusInfo *nexus_info)
2636%
2637% A description of each parameter follows:
2638%
2639% o cache: the pixel cache.
2640%
cristy4c08aed2011-07-01 19:47:50 +00002641% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002642%
2643*/
cristya6577ff2011-09-02 19:54:26 +00002644MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002645 NexusInfo *nexus_info)
2646{
2647 CacheInfo
2648 *cache_info;
2649
cristy9f027d12011-09-21 01:17:17 +00002650 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002651 cache_info=(CacheInfo *) cache;
2652 assert(cache_info->signature == MagickSignature);
2653 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002654 return((void *) NULL);
2655 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002656}
2657
2658/*
2659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2660% %
2661% %
2662% %
2663+ G e t P i x e l C a c h e N e x u s P i x e l s %
2664% %
2665% %
2666% %
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668%
2669% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2670% cache nexus.
2671%
2672% The format of the GetPixelCacheNexusPixels() method is:
2673%
cristy4c08aed2011-07-01 19:47:50 +00002674% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002675% NexusInfo *nexus_info)
2676%
2677% A description of each parameter follows:
2678%
2679% o cache: the pixel cache.
2680%
2681% o nexus_info: the cache nexus to return the pixels.
2682%
2683*/
cristya6577ff2011-09-02 19:54:26 +00002684MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002685 NexusInfo *nexus_info)
2686{
2687 CacheInfo
2688 *cache_info;
2689
cristy9f027d12011-09-21 01:17:17 +00002690 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002691 cache_info=(CacheInfo *) cache;
2692 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002693 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002694 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002695 return(nexus_info->pixels);
2696}
2697
2698/*
2699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700% %
2701% %
2702% %
cristy056ba772010-01-02 23:33:54 +00002703+ G e t P i x e l C a c h e P i x e l s %
2704% %
2705% %
2706% %
2707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2708%
2709% GetPixelCachePixels() returns the pixels associated with the specified image.
2710%
2711% The format of the GetPixelCachePixels() method is:
2712%
cristyf84a1932010-01-03 18:00:18 +00002713% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2714% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002715%
2716% A description of each parameter follows:
2717%
2718% o image: the image.
2719%
2720% o length: the pixel cache length.
2721%
cristyf84a1932010-01-03 18:00:18 +00002722% o exception: return any errors or warnings in this structure.
2723%
cristy056ba772010-01-02 23:33:54 +00002724*/
cristyd1dd6e42011-09-04 01:46:08 +00002725MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002726 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002727{
2728 CacheInfo
2729 *cache_info;
2730
2731 assert(image != (const Image *) NULL);
2732 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002733 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002734 assert(length != (MagickSizeType *) NULL);
2735 assert(exception != (ExceptionInfo *) NULL);
2736 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002737 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002738 assert(cache_info->signature == MagickSignature);
2739 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002740 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002741 return((void *) NULL);
2742 *length=cache_info->length;
2743 return((void *) cache_info->pixels);
2744}
2745
2746/*
2747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2748% %
2749% %
2750% %
cristyb32b90a2009-09-07 21:45:48 +00002751+ 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 +00002752% %
2753% %
2754% %
2755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2756%
2757% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2758%
2759% The format of the GetPixelCacheStorageClass() method is:
2760%
2761% ClassType GetPixelCacheStorageClass(Cache cache)
2762%
2763% A description of each parameter follows:
2764%
2765% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2766%
2767% o cache: the pixel cache.
2768%
2769*/
cristya6577ff2011-09-02 19:54:26 +00002770MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002771{
2772 CacheInfo
2773 *cache_info;
2774
2775 assert(cache != (Cache) NULL);
2776 cache_info=(CacheInfo *) cache;
2777 assert(cache_info->signature == MagickSignature);
2778 if (cache_info->debug != MagickFalse)
2779 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2780 cache_info->filename);
2781 return(cache_info->storage_class);
2782}
2783
2784/*
2785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2786% %
2787% %
2788% %
cristyb32b90a2009-09-07 21:45:48 +00002789+ G e t P i x e l C a c h e T i l e S i z e %
2790% %
2791% %
2792% %
2793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794%
2795% GetPixelCacheTileSize() returns the pixel cache tile size.
2796%
2797% The format of the GetPixelCacheTileSize() method is:
2798%
cristybb503372010-05-27 20:51:26 +00002799% void GetPixelCacheTileSize(const Image *image,size_t *width,
2800% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002801%
2802% A description of each parameter follows:
2803%
2804% o image: the image.
2805%
2806% o width: the optimize cache tile width in pixels.
2807%
2808% o height: the optimize cache tile height in pixels.
2809%
2810*/
cristya6577ff2011-09-02 19:54:26 +00002811MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002812 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002813{
cristy4c08aed2011-07-01 19:47:50 +00002814 CacheInfo
2815 *cache_info;
2816
cristyb32b90a2009-09-07 21:45:48 +00002817 assert(image != (Image *) NULL);
2818 assert(image->signature == MagickSignature);
2819 if (image->debug != MagickFalse)
2820 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002821 cache_info=(CacheInfo *) image->cache;
2822 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002823 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002824 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002825 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002826 *height=(*width);
2827}
2828
2829/*
2830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831% %
2832% %
2833% %
2834+ G e t P i x e l C a c h e T y p e %
2835% %
2836% %
2837% %
2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839%
2840% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2841%
2842% The format of the GetPixelCacheType() method is:
2843%
2844% CacheType GetPixelCacheType(const Image *image)
2845%
2846% A description of each parameter follows:
2847%
2848% o image: the image.
2849%
2850*/
cristya6577ff2011-09-02 19:54:26 +00002851MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002852{
2853 CacheInfo
2854 *cache_info;
2855
2856 assert(image != (Image *) NULL);
2857 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002858 assert(image->cache != (Cache) NULL);
2859 cache_info=(CacheInfo *) image->cache;
2860 assert(cache_info->signature == MagickSignature);
2861 return(cache_info->type);
2862}
2863
2864/*
2865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866% %
2867% %
2868% %
cristy3ed852e2009-09-05 21:47:34 +00002869+ 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 %
2870% %
2871% %
2872% %
2873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874%
2875% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2876% pixel cache. A virtual pixel is any pixel access that is outside the
2877% boundaries of the image cache.
2878%
2879% The format of the GetPixelCacheVirtualMethod() method is:
2880%
2881% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2882%
2883% A description of each parameter follows:
2884%
2885% o image: the image.
2886%
2887*/
cristyd1dd6e42011-09-04 01:46:08 +00002888MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002889{
2890 CacheInfo
2891 *cache_info;
2892
2893 assert(image != (Image *) NULL);
2894 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002895 assert(image->cache != (Cache) NULL);
2896 cache_info=(CacheInfo *) image->cache;
2897 assert(cache_info->signature == MagickSignature);
2898 return(cache_info->virtual_pixel_method);
2899}
2900
2901/*
2902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903% %
2904% %
2905% %
cristy4c08aed2011-07-01 19:47:50 +00002906+ 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 +00002907% %
2908% %
2909% %
2910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911%
cristy4c08aed2011-07-01 19:47:50 +00002912% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2913% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002914%
cristy4c08aed2011-07-01 19:47:50 +00002915% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002916%
cristy4c08aed2011-07-01 19:47:50 +00002917% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002918%
2919% A description of each parameter follows:
2920%
2921% o image: the image.
2922%
2923*/
cristy4c08aed2011-07-01 19:47:50 +00002924static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002925{
2926 CacheInfo
2927 *cache_info;
2928
cristy5c9e6f22010-09-17 17:31:01 +00002929 const int
2930 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002931
cristy4c08aed2011-07-01 19:47:50 +00002932 const void
2933 *metacontent;
2934
cristye7cc7cf2010-09-21 13:26:47 +00002935 assert(image != (const Image *) NULL);
2936 assert(image->signature == MagickSignature);
2937 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002938 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002939 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002940 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002941 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2942 cache_info->nexus_info[id]);
2943 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002944}
2945
2946/*
2947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2948% %
2949% %
2950% %
cristy4c08aed2011-07-01 19:47:50 +00002951+ 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 +00002952% %
2953% %
2954% %
2955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2956%
cristy4c08aed2011-07-01 19:47:50 +00002957% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2958% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002959%
cristy4c08aed2011-07-01 19:47:50 +00002960% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002961%
cristy4c08aed2011-07-01 19:47:50 +00002962% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002963% NexusInfo *nexus_info)
2964%
2965% A description of each parameter follows:
2966%
2967% o cache: the pixel cache.
2968%
cristy4c08aed2011-07-01 19:47:50 +00002969% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002970%
2971*/
cristya6577ff2011-09-02 19:54:26 +00002972MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002973 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002974{
2975 CacheInfo
2976 *cache_info;
2977
cristye7cc7cf2010-09-21 13:26:47 +00002978 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002979 cache_info=(CacheInfo *) cache;
2980 assert(cache_info->signature == MagickSignature);
2981 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002982 return((void *) NULL);
2983 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002984}
2985
2986/*
2987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988% %
2989% %
2990% %
cristy4c08aed2011-07-01 19:47:50 +00002991% 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 +00002992% %
2993% %
2994% %
2995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2996%
cristy4c08aed2011-07-01 19:47:50 +00002997% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2998% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2999% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003000%
cristy4c08aed2011-07-01 19:47:50 +00003001% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003002%
cristy4c08aed2011-07-01 19:47:50 +00003003% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003004%
3005% A description of each parameter follows:
3006%
3007% o image: the image.
3008%
3009*/
cristy4c08aed2011-07-01 19:47:50 +00003010MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003011{
3012 CacheInfo
3013 *cache_info;
3014
cristy2036f5c2010-09-19 21:18:17 +00003015 const int
3016 id = GetOpenMPThreadId();
3017
cristy4c08aed2011-07-01 19:47:50 +00003018 const void
3019 *metacontent;
3020
cristy3ed852e2009-09-05 21:47:34 +00003021 assert(image != (const Image *) NULL);
3022 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003023 assert(image->cache != (Cache) NULL);
3024 cache_info=(CacheInfo *) image->cache;
3025 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003026 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3027 (GetVirtualMetacontentFromHandler) NULL)
3028 {
3029 metacontent=cache_info->methods.
3030 get_virtual_metacontent_from_handler(image);
3031 return(metacontent);
3032 }
cristy2036f5c2010-09-19 21:18:17 +00003033 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003034 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3035 cache_info->nexus_info[id]);
3036 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003037}
3038
3039/*
3040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3041% %
3042% %
3043% %
3044+ 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 %
3045% %
3046% %
3047% %
3048%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049%
3050% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3051% pixel cache as defined by the geometry parameters. A pointer to the pixels
3052% is returned if the pixels are transferred, otherwise a NULL is returned.
3053%
3054% The format of the GetVirtualPixelsFromNexus() method is:
3055%
cristy4c08aed2011-07-01 19:47:50 +00003056% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003057% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003058% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3059% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003060%
3061% A description of each parameter follows:
3062%
3063% o image: the image.
3064%
3065% o virtual_pixel_method: the virtual pixel method.
3066%
3067% o x,y,columns,rows: These values define the perimeter of a region of
3068% pixels.
3069%
3070% o nexus_info: the cache nexus to acquire.
3071%
3072% o exception: return any errors or warnings in this structure.
3073%
3074*/
3075
cristybb503372010-05-27 20:51:26 +00003076static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003077 DitherMatrix[64] =
3078 {
3079 0, 48, 12, 60, 3, 51, 15, 63,
3080 32, 16, 44, 28, 35, 19, 47, 31,
3081 8, 56, 4, 52, 11, 59, 7, 55,
3082 40, 24, 36, 20, 43, 27, 39, 23,
3083 2, 50, 14, 62, 1, 49, 13, 61,
3084 34, 18, 46, 30, 33, 17, 45, 29,
3085 10, 58, 6, 54, 9, 57, 5, 53,
3086 42, 26, 38, 22, 41, 25, 37, 21
3087 };
3088
cristybb503372010-05-27 20:51:26 +00003089static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003090{
cristybb503372010-05-27 20:51:26 +00003091 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003092 index;
3093
3094 index=x+DitherMatrix[x & 0x07]-32L;
3095 if (index < 0L)
3096 return(0L);
cristybb503372010-05-27 20:51:26 +00003097 if (index >= (ssize_t) columns)
3098 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003099 return(index);
3100}
3101
cristybb503372010-05-27 20:51:26 +00003102static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003103{
cristybb503372010-05-27 20:51:26 +00003104 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003105 index;
3106
3107 index=y+DitherMatrix[y & 0x07]-32L;
3108 if (index < 0L)
3109 return(0L);
cristybb503372010-05-27 20:51:26 +00003110 if (index >= (ssize_t) rows)
3111 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003112 return(index);
3113}
3114
cristybb503372010-05-27 20:51:26 +00003115static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003116{
3117 if (x < 0L)
3118 return(0L);
cristybb503372010-05-27 20:51:26 +00003119 if (x >= (ssize_t) columns)
3120 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003121 return(x);
3122}
3123
cristybb503372010-05-27 20:51:26 +00003124static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003125{
3126 if (y < 0L)
3127 return(0L);
cristybb503372010-05-27 20:51:26 +00003128 if (y >= (ssize_t) rows)
3129 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003130 return(y);
3131}
3132
cristybb503372010-05-27 20:51:26 +00003133static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003134{
cristybb503372010-05-27 20:51:26 +00003135 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003136}
3137
cristybb503372010-05-27 20:51:26 +00003138static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003139{
cristybb503372010-05-27 20:51:26 +00003140 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003141}
3142
cristybb503372010-05-27 20:51:26 +00003143static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3144 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003145{
3146 MagickModulo
3147 modulo;
3148
cristy6162bb42011-07-18 11:34:09 +00003149 /*
3150 Compute the remainder of dividing offset by extent. It returns not only
3151 the quotient (tile the offset falls in) but also the positive remainer
3152 within that tile such that 0 <= remainder < extent. This method is
3153 essentially a ldiv() using a floored modulo division rather than the
3154 normal default truncated modulo division.
3155 */
cristybb503372010-05-27 20:51:26 +00003156 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003157 if (offset < 0L)
3158 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003159 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003160 return(modulo);
3161}
3162
cristya6577ff2011-09-02 19:54:26 +00003163MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003164 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3165 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003166 ExceptionInfo *exception)
3167{
3168 CacheInfo
3169 *cache_info;
3170
3171 MagickOffsetType
3172 offset;
3173
3174 MagickSizeType
3175 length,
3176 number_pixels;
3177
3178 NexusInfo
3179 **virtual_nexus;
3180
cristy4c08aed2011-07-01 19:47:50 +00003181 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003182 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003183 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003184
3185 RectangleInfo
3186 region;
3187
cristy4c08aed2011-07-01 19:47:50 +00003188 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003189 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003190
cristy4c08aed2011-07-01 19:47:50 +00003191 register const void
3192 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003193
cristy4c08aed2011-07-01 19:47:50 +00003194 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003195 *restrict q;
3196
cristybb503372010-05-27 20:51:26 +00003197 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003198 i,
3199 u;
cristy3ed852e2009-09-05 21:47:34 +00003200
cristy4c08aed2011-07-01 19:47:50 +00003201 register unsigned char
3202 *restrict s;
3203
cristy105ba3c2011-07-18 02:28:38 +00003204 ssize_t
3205 v;
3206
cristy4c08aed2011-07-01 19:47:50 +00003207 void
cristy105ba3c2011-07-18 02:28:38 +00003208 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003209
cristy3ed852e2009-09-05 21:47:34 +00003210 /*
3211 Acquire pixels.
3212 */
cristye7cc7cf2010-09-21 13:26:47 +00003213 assert(image != (const Image *) NULL);
3214 assert(image->signature == MagickSignature);
3215 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003216 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003217 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003218 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003219 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003220 region.x=x;
3221 region.y=y;
3222 region.width=columns;
3223 region.height=rows;
3224 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003225 if (pixels == (Quantum *) NULL)
3226 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003227 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003228 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3229 nexus_info->region.x;
3230 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3231 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003232 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3233 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003234 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3235 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003236 {
3237 MagickBooleanType
3238 status;
3239
3240 /*
3241 Pixel request is inside cache extents.
3242 */
cristy4c08aed2011-07-01 19:47:50 +00003243 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003244 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003245 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3246 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003247 return((const Quantum *) NULL);
3248 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003249 {
cristy4c08aed2011-07-01 19:47:50 +00003250 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003251 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003252 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003253 }
cristyacd2ed22011-08-30 01:44:23 +00003254 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003255 }
3256 /*
3257 Pixel request is outside cache extents.
3258 */
cristy4c08aed2011-07-01 19:47:50 +00003259 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003260 virtual_nexus=AcquirePixelCacheNexus(1);
3261 if (virtual_nexus == (NexusInfo **) NULL)
3262 {
cristy4c08aed2011-07-01 19:47:50 +00003263 if (virtual_nexus != (NexusInfo **) NULL)
3264 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003265 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3266 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003267 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003268 }
cristy105ba3c2011-07-18 02:28:38 +00003269 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3270 sizeof(*virtual_pixel));
3271 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003272 switch (virtual_pixel_method)
3273 {
cristy4c08aed2011-07-01 19:47:50 +00003274 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003275 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003276 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003277 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003278 case MaskVirtualPixelMethod:
3279 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003280 case EdgeVirtualPixelMethod:
3281 case CheckerTileVirtualPixelMethod:
3282 case HorizontalTileVirtualPixelMethod:
3283 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003284 {
cristy4c08aed2011-07-01 19:47:50 +00003285 if (cache_info->metacontent_extent != 0)
3286 {
cristy6162bb42011-07-18 11:34:09 +00003287 /*
3288 Acquire a metacontent buffer.
3289 */
cristya64b85d2011-09-14 01:02:31 +00003290 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003291 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003292 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003293 {
cristy4c08aed2011-07-01 19:47:50 +00003294 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3295 (void) ThrowMagickException(exception,GetMagickModule(),
3296 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3297 return((const Quantum *) NULL);
3298 }
cristy105ba3c2011-07-18 02:28:38 +00003299 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003300 cache_info->metacontent_extent);
3301 }
3302 switch (virtual_pixel_method)
3303 {
3304 case BlackVirtualPixelMethod:
3305 {
cristy30301712011-07-18 15:06:51 +00003306 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3307 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003308 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3309 break;
3310 }
3311 case GrayVirtualPixelMethod:
3312 {
cristy30301712011-07-18 15:06:51 +00003313 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003314 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3315 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003316 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3317 break;
3318 }
3319 case TransparentVirtualPixelMethod:
3320 {
cristy30301712011-07-18 15:06:51 +00003321 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3322 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003323 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3324 break;
3325 }
3326 case MaskVirtualPixelMethod:
3327 case WhiteVirtualPixelMethod:
3328 {
cristy30301712011-07-18 15:06:51 +00003329 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3330 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003331 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3332 break;
3333 }
3334 default:
3335 {
cristy9e0719b2011-12-29 03:45:45 +00003336 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3337 virtual_pixel);
3338 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3339 virtual_pixel);
3340 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3341 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003342 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003343 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3344 virtual_pixel);
3345 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3346 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003347 break;
3348 }
3349 }
cristy3ed852e2009-09-05 21:47:34 +00003350 break;
3351 }
3352 default:
cristy3ed852e2009-09-05 21:47:34 +00003353 break;
cristy3ed852e2009-09-05 21:47:34 +00003354 }
cristybb503372010-05-27 20:51:26 +00003355 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003356 {
cristybb503372010-05-27 20:51:26 +00003357 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003358 {
3359 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003360 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003361 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3362 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003363 {
3364 MagickModulo
3365 x_modulo,
3366 y_modulo;
3367
3368 /*
3369 Transfer a single pixel.
3370 */
3371 length=(MagickSizeType) 1;
3372 switch (virtual_pixel_method)
3373 {
cristy3ed852e2009-09-05 21:47:34 +00003374 default:
3375 {
3376 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003377 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003378 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003379 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003380 break;
3381 }
3382 case RandomVirtualPixelMethod:
3383 {
3384 if (cache_info->random_info == (RandomInfo *) NULL)
3385 cache_info->random_info=AcquireRandomInfo();
3386 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003387 RandomX(cache_info->random_info,cache_info->columns),
3388 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003389 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003390 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003391 break;
3392 }
3393 case DitherVirtualPixelMethod:
3394 {
3395 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003396 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003397 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003398 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003399 break;
3400 }
3401 case TileVirtualPixelMethod:
3402 {
3403 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3404 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3405 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003406 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003407 exception);
cristy4c08aed2011-07-01 19:47:50 +00003408 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003409 break;
3410 }
3411 case MirrorVirtualPixelMethod:
3412 {
3413 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3414 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003415 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003416 x_modulo.remainder-1L;
3417 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3418 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003419 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003420 y_modulo.remainder-1L;
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003422 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003423 exception);
cristy4c08aed2011-07-01 19:47:50 +00003424 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003425 break;
3426 }
3427 case HorizontalTileEdgeVirtualPixelMethod:
3428 {
3429 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003431 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003432 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003433 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003434 break;
3435 }
3436 case VerticalTileEdgeVirtualPixelMethod:
3437 {
3438 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003440 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003441 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003442 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3443 break;
3444 }
3445 case BackgroundVirtualPixelMethod:
3446 case BlackVirtualPixelMethod:
3447 case GrayVirtualPixelMethod:
3448 case TransparentVirtualPixelMethod:
3449 case MaskVirtualPixelMethod:
3450 case WhiteVirtualPixelMethod:
3451 {
3452 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003453 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003454 break;
3455 }
3456 case EdgeVirtualPixelMethod:
3457 case CheckerTileVirtualPixelMethod:
3458 {
3459 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3460 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3461 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3462 {
3463 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003464 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003465 break;
3466 }
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3468 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3469 exception);
3470 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3471 break;
3472 }
3473 case HorizontalTileVirtualPixelMethod:
3474 {
3475 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3476 {
3477 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003478 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003479 break;
3480 }
3481 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3482 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3483 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3484 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3485 exception);
3486 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3487 break;
3488 }
3489 case VerticalTileVirtualPixelMethod:
3490 {
3491 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3492 {
3493 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003494 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003495 break;
3496 }
3497 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3498 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3499 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3500 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3501 exception);
3502 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003503 break;
3504 }
3505 }
cristy4c08aed2011-07-01 19:47:50 +00003506 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003507 break;
cristyed231572011-07-14 02:18:59 +00003508 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003509 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003510 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003511 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003512 {
3513 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3514 s+=cache_info->metacontent_extent;
3515 }
cristy3ed852e2009-09-05 21:47:34 +00003516 continue;
3517 }
3518 /*
3519 Transfer a run of pixels.
3520 */
cristy4c08aed2011-07-01 19:47:50 +00003521 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3522 length,1UL,*virtual_nexus,exception);
3523 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003524 break;
cristy4c08aed2011-07-01 19:47:50 +00003525 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003526 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3527 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003528 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003529 {
cristy4c08aed2011-07-01 19:47:50 +00003530 (void) memcpy(s,r,(size_t) length);
3531 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003532 }
3533 }
3534 }
cristy4c08aed2011-07-01 19:47:50 +00003535 /*
3536 Free resources.
3537 */
cristy105ba3c2011-07-18 02:28:38 +00003538 if (virtual_metacontent != (void *) NULL)
3539 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003540 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3541 return(pixels);
3542}
3543
3544/*
3545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3546% %
3547% %
3548% %
3549+ G e t V i r t u a l P i x e l C a c h e %
3550% %
3551% %
3552% %
3553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3554%
3555% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3556% cache as defined by the geometry parameters. A pointer to the pixels
3557% is returned if the pixels are transferred, otherwise a NULL is returned.
3558%
3559% The format of the GetVirtualPixelCache() method is:
3560%
cristy4c08aed2011-07-01 19:47:50 +00003561% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003562% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3563% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003564% ExceptionInfo *exception)
3565%
3566% A description of each parameter follows:
3567%
3568% o image: the image.
3569%
3570% o virtual_pixel_method: the virtual pixel method.
3571%
3572% o x,y,columns,rows: These values define the perimeter of a region of
3573% pixels.
3574%
3575% o exception: return any errors or warnings in this structure.
3576%
3577*/
cristy4c08aed2011-07-01 19:47:50 +00003578static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003579 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3580 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003581{
3582 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003583 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003584
cristy5c9e6f22010-09-17 17:31:01 +00003585 const int
3586 id = GetOpenMPThreadId();
3587
cristy4c08aed2011-07-01 19:47:50 +00003588 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003589 *p;
cristy4c08aed2011-07-01 19:47:50 +00003590
cristye7cc7cf2010-09-21 13:26:47 +00003591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
3593 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003594 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003595 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003596 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003597 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003598 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003599 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003600}
3601
3602/*
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604% %
3605% %
3606% %
3607% G e t V i r t u a l P i x e l Q u e u e %
3608% %
3609% %
3610% %
3611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612%
cristy4c08aed2011-07-01 19:47:50 +00003613% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3614% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003615%
3616% The format of the GetVirtualPixelQueue() method is:
3617%
cristy4c08aed2011-07-01 19:47:50 +00003618% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003619%
3620% A description of each parameter follows:
3621%
3622% o image: the image.
3623%
3624*/
cristy4c08aed2011-07-01 19:47:50 +00003625MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003626{
3627 CacheInfo
3628 *cache_info;
3629
cristy2036f5c2010-09-19 21:18:17 +00003630 const int
3631 id = GetOpenMPThreadId();
3632
cristy3ed852e2009-09-05 21:47:34 +00003633 assert(image != (const Image *) NULL);
3634 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003635 assert(image->cache != (Cache) NULL);
3636 cache_info=(CacheInfo *) image->cache;
3637 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003638 if (cache_info->methods.get_virtual_pixels_handler !=
3639 (GetVirtualPixelsHandler) NULL)
3640 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003641 assert(id < (int) cache_info->number_threads);
3642 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003643}
3644
3645/*
3646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647% %
3648% %
3649% %
3650% G e t V i r t u a l P i x e l s %
3651% %
3652% %
3653% %
3654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3655%
3656% GetVirtualPixels() returns an immutable pixel region. If the
3657% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003658% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003659% copy of the pixels or it may point to the original pixels in memory.
3660% Performance is maximized if the selected region is part of one row, or one
3661% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003662% (without a copy) if the image is in memory, or in a memory-mapped file. The
3663% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003664%
3665% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003666% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3667% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3668% access the meta-content (of type void) corresponding to the the
3669% region.
cristy3ed852e2009-09-05 21:47:34 +00003670%
3671% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3672%
3673% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3674% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3675% GetCacheViewAuthenticPixels() instead.
3676%
3677% The format of the GetVirtualPixels() method is:
3678%
cristy4c08aed2011-07-01 19:47:50 +00003679% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003680% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003681% ExceptionInfo *exception)
3682%
3683% A description of each parameter follows:
3684%
3685% o image: the image.
3686%
3687% o x,y,columns,rows: These values define the perimeter of a region of
3688% pixels.
3689%
3690% o exception: return any errors or warnings in this structure.
3691%
3692*/
cristy4c08aed2011-07-01 19:47:50 +00003693MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003694 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3695 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003696{
3697 CacheInfo
3698 *cache_info;
3699
cristy2036f5c2010-09-19 21:18:17 +00003700 const int
3701 id = GetOpenMPThreadId();
3702
cristy4c08aed2011-07-01 19:47:50 +00003703 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003704 *p;
cristy4c08aed2011-07-01 19:47:50 +00003705
cristy3ed852e2009-09-05 21:47:34 +00003706 assert(image != (const Image *) NULL);
3707 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003708 assert(image->cache != (Cache) NULL);
3709 cache_info=(CacheInfo *) image->cache;
3710 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003711 if (cache_info->methods.get_virtual_pixel_handler !=
3712 (GetVirtualPixelHandler) NULL)
3713 return(cache_info->methods.get_virtual_pixel_handler(image,
3714 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003715 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003716 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003717 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003718 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003719}
3720
3721/*
3722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3723% %
3724% %
3725% %
3726+ 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 %
3727% %
3728% %
3729% %
3730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3731%
cristy4c08aed2011-07-01 19:47:50 +00003732% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3733% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003734%
3735% The format of the GetVirtualPixelsCache() method is:
3736%
cristy4c08aed2011-07-01 19:47:50 +00003737% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003738%
3739% A description of each parameter follows:
3740%
3741% o image: the image.
3742%
3743*/
cristy4c08aed2011-07-01 19:47:50 +00003744static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003745{
3746 CacheInfo
3747 *cache_info;
3748
cristy5c9e6f22010-09-17 17:31:01 +00003749 const int
3750 id = GetOpenMPThreadId();
3751
cristye7cc7cf2010-09-21 13:26:47 +00003752 assert(image != (const Image *) NULL);
3753 assert(image->signature == MagickSignature);
3754 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003755 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003756 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003757 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003758 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003759}
3760
3761/*
3762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3763% %
3764% %
3765% %
3766+ G e t V i r t u a l P i x e l s N e x u s %
3767% %
3768% %
3769% %
3770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3771%
3772% GetVirtualPixelsNexus() returns the pixels associated with the specified
3773% cache nexus.
3774%
3775% The format of the GetVirtualPixelsNexus() method is:
3776%
cristy4c08aed2011-07-01 19:47:50 +00003777% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003778% NexusInfo *nexus_info)
3779%
3780% A description of each parameter follows:
3781%
3782% o cache: the pixel cache.
3783%
3784% o nexus_info: the cache nexus to return the colormap pixels.
3785%
3786*/
cristya6577ff2011-09-02 19:54:26 +00003787MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003788 NexusInfo *nexus_info)
3789{
3790 CacheInfo
3791 *cache_info;
3792
cristye7cc7cf2010-09-21 13:26:47 +00003793 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003794 cache_info=(CacheInfo *) cache;
3795 assert(cache_info->signature == MagickSignature);
3796 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003797 return((Quantum *) NULL);
3798 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003799}
3800
3801/*
3802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803% %
3804% %
3805% %
3806+ M a s k P i x e l C a c h e N e x u s %
3807% %
3808% %
3809% %
3810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3811%
3812% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3813% The method returns MagickTrue if the pixel region is masked, otherwise
3814% MagickFalse.
3815%
3816% The format of the MaskPixelCacheNexus() method is:
3817%
3818% MagickBooleanType MaskPixelCacheNexus(Image *image,
3819% NexusInfo *nexus_info,ExceptionInfo *exception)
3820%
3821% A description of each parameter follows:
3822%
3823% o image: the image.
3824%
3825% o nexus_info: the cache nexus to clip.
3826%
3827% o exception: return any errors or warnings in this structure.
3828%
3829*/
3830
cristy3aa93752011-12-18 15:54:24 +00003831static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3832 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003833{
3834 MagickRealType
3835 gamma;
3836
cristyaa83c2c2011-09-21 13:36:25 +00003837 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003838 {
3839 *composite=(*q);
3840 return;
3841 }
3842 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3843 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003844 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3845 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3846 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003847 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003848 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003849}
3850
3851static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3852 ExceptionInfo *exception)
3853{
3854 CacheInfo
3855 *cache_info;
3856
cristy4c08aed2011-07-01 19:47:50 +00003857 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003858 alpha,
3859 beta;
3860
3861 MagickSizeType
3862 number_pixels;
3863
3864 NexusInfo
3865 **clip_nexus,
3866 **image_nexus;
3867
cristy4c08aed2011-07-01 19:47:50 +00003868 register const Quantum
3869 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003870 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003871
cristy4c08aed2011-07-01 19:47:50 +00003872 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003873 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003874
cristye076a6e2010-08-15 19:59:43 +00003875 register ssize_t
3876 i;
3877
cristy3ed852e2009-09-05 21:47:34 +00003878 /*
3879 Apply clip mask.
3880 */
3881 if (image->debug != MagickFalse)
3882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3883 if (image->mask == (Image *) NULL)
3884 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003885 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003886 if (cache_info == (Cache) NULL)
3887 return(MagickFalse);
3888 image_nexus=AcquirePixelCacheNexus(1);
3889 clip_nexus=AcquirePixelCacheNexus(1);
3890 if ((image_nexus == (NexusInfo **) NULL) ||
3891 (clip_nexus == (NexusInfo **) NULL))
3892 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003893 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3894 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3895 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003896 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003897 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3898 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003899 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003900 GetPixelInfo(image,&alpha);
3901 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003902 number_pixels=(MagickSizeType) nexus_info->region.width*
3903 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003904 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003905 {
cristy4c08aed2011-07-01 19:47:50 +00003906 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003907 break;
cristy803640d2011-11-17 02:11:32 +00003908 GetPixelInfoPixel(image,p,&alpha);
3909 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003910 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003911 &alpha,alpha.alpha,&beta);
3912 SetPixelRed(image,ClampToQuantum(beta.red),q);
3913 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3914 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3915 if (cache_info->colorspace == CMYKColorspace)
3916 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3917 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003918 p++;
3919 q++;
3920 r++;
3921 }
3922 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3923 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003924 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003925 return(MagickFalse);
3926 return(MagickTrue);
3927}
3928
3929/*
3930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3931% %
3932% %
3933% %
3934+ O p e n P i x e l C a c h e %
3935% %
3936% %
3937% %
3938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3939%
3940% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3941% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003942% metacontent, and memory mapping the cache if it is disk based. The cache
3943% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003944%
3945% The format of the OpenPixelCache() method is:
3946%
3947% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3948% ExceptionInfo *exception)
3949%
3950% A description of each parameter follows:
3951%
3952% o image: the image.
3953%
3954% o mode: ReadMode, WriteMode, or IOMode.
3955%
3956% o exception: return any errors or warnings in this structure.
3957%
3958*/
3959
cristyd43a46b2010-01-21 02:13:41 +00003960static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003961{
3962 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003963 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003964 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003965 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003966 {
3967 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003968 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003969 cache_info->length);
3970 }
3971}
3972
3973static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3974{
3975 CacheInfo
3976 *cache_info;
3977
3978 MagickOffsetType
3979 count,
3980 extent,
3981 offset;
3982
3983 cache_info=(CacheInfo *) image->cache;
3984 if (image->debug != MagickFalse)
3985 {
3986 char
3987 format[MaxTextExtent],
3988 message[MaxTextExtent];
3989
cristyb9080c92009-12-01 20:13:26 +00003990 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003991 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003992 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003993 cache_info->cache_filename,cache_info->file,format);
3994 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3995 }
3996 if (length != (MagickSizeType) ((MagickOffsetType) length))
3997 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003998 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003999 if (extent < 0)
4000 return(MagickFalse);
4001 if ((MagickSizeType) extent >= length)
4002 return(MagickTrue);
4003 offset=(MagickOffsetType) length-1;
4004 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4005 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4006}
4007
4008static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4009 ExceptionInfo *exception)
4010{
cristy3ed852e2009-09-05 21:47:34 +00004011 CacheInfo
4012 *cache_info,
4013 source_info;
4014
cristyf3a6a9d2010-11-07 21:02:56 +00004015 char
4016 format[MaxTextExtent],
4017 message[MaxTextExtent];
4018
cristy4c08aed2011-07-01 19:47:50 +00004019 MagickBooleanType
4020 status;
4021
cristy3ed852e2009-09-05 21:47:34 +00004022 MagickSizeType
4023 length,
4024 number_pixels;
4025
cristy3b8fe922011-12-29 18:56:23 +00004026 PixelChannelMap
4027 *p,
4028 *q;
4029
cristy3ed852e2009-09-05 21:47:34 +00004030 size_t
cristye076a6e2010-08-15 19:59:43 +00004031 columns,
cristy3ed852e2009-09-05 21:47:34 +00004032 packet_size;
4033
cristye7cc7cf2010-09-21 13:26:47 +00004034 assert(image != (const Image *) NULL);
4035 assert(image->signature == MagickSignature);
4036 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004037 if (image->debug != MagickFalse)
4038 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4039 if ((image->columns == 0) || (image->rows == 0))
4040 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4041 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004042 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004043 source_info=(*cache_info);
4044 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004045 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004046 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004047 cache_info->storage_class=image->storage_class;
4048 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004049 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004050 cache_info->rows=image->rows;
4051 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004052 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004053 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004054 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4055 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004056 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004057 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004058 if (image->ping != MagickFalse)
4059 {
cristy73724512010-04-12 14:43:14 +00004060 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004061 cache_info->pixels=(Quantum *) NULL;
4062 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004063 cache_info->length=0;
4064 return(MagickTrue);
4065 }
cristy3ed852e2009-09-05 21:47:34 +00004066 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004067 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004068 if (image->metacontent_extent != 0)
4069 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004070 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004071 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004072 if (cache_info->columns != columns)
4073 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4074 image->filename);
4075 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004076 p=cache_info->channel_map;
4077 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004078 if ((cache_info->type != UndefinedCache) &&
4079 (cache_info->columns <= source_info.columns) &&
4080 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004081 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004082 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004083 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4084 {
4085 /*
4086 Inline pixel cache clone optimization.
4087 */
4088 if ((cache_info->columns == source_info.columns) &&
4089 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004090 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004091 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004092 (cache_info->metacontent_extent == source_info.metacontent_extent))
4093 return(MagickTrue);
4094 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4095 }
cristy3ed852e2009-09-05 21:47:34 +00004096 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004097 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004098 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004099 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4100 {
4101 status=AcquireMagickResource(MemoryResource,cache_info->length);
4102 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4103 (cache_info->type == MemoryCache))
4104 {
cristyd43a46b2010-01-21 02:13:41 +00004105 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004106 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004107 cache_info->pixels=source_info.pixels;
4108 else
4109 {
4110 /*
4111 Create memory pixel cache.
4112 */
cristy4c08aed2011-07-01 19:47:50 +00004113 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004114 if (image->debug != MagickFalse)
4115 {
cristy32cacff2011-12-31 03:36:27 +00004116 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004117 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004118 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4119 cache_info->filename,cache_info->mapped != MagickFalse ?
4120 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004121 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004122 format);
cristy3ed852e2009-09-05 21:47:34 +00004123 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4124 message);
4125 }
cristy3ed852e2009-09-05 21:47:34 +00004126 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004127 cache_info->metacontent=(void *) NULL;
4128 if (cache_info->metacontent_extent != 0)
4129 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004130 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004131 if ((source_info.storage_class != UndefinedClass) &&
4132 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004133 {
cristy4c08aed2011-07-01 19:47:50 +00004134 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004135 exception);
4136 RelinquishPixelCachePixels(&source_info);
4137 }
cristy4c08aed2011-07-01 19:47:50 +00004138 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004139 }
4140 }
4141 RelinquishMagickResource(MemoryResource,cache_info->length);
4142 }
4143 /*
4144 Create pixel cache on disk.
4145 */
4146 status=AcquireMagickResource(DiskResource,cache_info->length);
4147 if (status == MagickFalse)
4148 {
4149 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4150 "CacheResourcesExhausted","`%s'",image->filename);
4151 return(MagickFalse);
4152 }
cristy413f1302012-01-01 17:48:27 +00004153 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4154 {
4155 (void) ClosePixelCacheOnDisk(cache_info);
4156 *cache_info->cache_filename='\0';
4157 }
cristy3ed852e2009-09-05 21:47:34 +00004158 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4159 {
4160 RelinquishMagickResource(DiskResource,cache_info->length);
4161 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4162 image->filename);
4163 return(MagickFalse);
4164 }
4165 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4166 cache_info->length);
4167 if (status == MagickFalse)
4168 {
4169 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4170 image->filename);
4171 return(MagickFalse);
4172 }
cristyed231572011-07-14 02:18:59 +00004173 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004174 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004175 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004176 cache_info->type=DiskCache;
4177 else
4178 {
4179 status=AcquireMagickResource(MapResource,cache_info->length);
4180 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4181 (cache_info->type != MemoryCache))
4182 cache_info->type=DiskCache;
4183 else
4184 {
cristy4c08aed2011-07-01 19:47:50 +00004185 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004186 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004187 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004188 {
cristy3ed852e2009-09-05 21:47:34 +00004189 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004190 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004191 }
4192 else
4193 {
4194 /*
4195 Create file-backed memory-mapped pixel cache.
4196 */
cristy4c08aed2011-07-01 19:47:50 +00004197 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004198 (void) ClosePixelCacheOnDisk(cache_info);
4199 cache_info->type=MapCache;
4200 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004201 cache_info->metacontent=(void *) NULL;
4202 if (cache_info->metacontent_extent != 0)
4203 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004204 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004205 if ((source_info.storage_class != UndefinedClass) &&
4206 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004207 {
4208 status=ClonePixelCachePixels(cache_info,&source_info,
4209 exception);
4210 RelinquishPixelCachePixels(&source_info);
4211 }
4212 if (image->debug != MagickFalse)
4213 {
cristy413f1302012-01-01 17:48:27 +00004214 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004215 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004216 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004217 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004218 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004219 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004220 format);
cristy3ed852e2009-09-05 21:47:34 +00004221 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4222 message);
4223 }
cristy4c08aed2011-07-01 19:47:50 +00004224 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004225 }
4226 }
4227 RelinquishMagickResource(MapResource,cache_info->length);
4228 }
cristy4c08aed2011-07-01 19:47:50 +00004229 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00004230 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004231 {
4232 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4233 RelinquishPixelCachePixels(&source_info);
4234 }
4235 if (image->debug != MagickFalse)
4236 {
cristyb9080c92009-12-01 20:13:26 +00004237 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004238 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004239 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004240 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004241 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004242 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004243 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4244 }
cristy4c08aed2011-07-01 19:47:50 +00004245 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004246}
4247
4248/*
4249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4250% %
4251% %
4252% %
4253+ P e r s i s t P i x e l C a c h e %
4254% %
4255% %
4256% %
4257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4258%
4259% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4260% persistent pixel cache is one that resides on disk and is not destroyed
4261% when the program exits.
4262%
4263% The format of the PersistPixelCache() method is:
4264%
4265% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4266% const MagickBooleanType attach,MagickOffsetType *offset,
4267% ExceptionInfo *exception)
4268%
4269% A description of each parameter follows:
4270%
4271% o image: the image.
4272%
4273% o filename: the persistent pixel cache filename.
4274%
cristyf3a6a9d2010-11-07 21:02:56 +00004275% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004276%
cristy3ed852e2009-09-05 21:47:34 +00004277% o initialize: A value other than zero initializes the persistent pixel
4278% cache.
4279%
4280% o offset: the offset in the persistent cache to store pixels.
4281%
4282% o exception: return any errors or warnings in this structure.
4283%
4284*/
4285MagickExport MagickBooleanType PersistPixelCache(Image *image,
4286 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4287 ExceptionInfo *exception)
4288{
4289 CacheInfo
4290 *cache_info,
4291 *clone_info;
4292
4293 Image
4294 clone_image;
4295
cristy3ed852e2009-09-05 21:47:34 +00004296 MagickBooleanType
4297 status;
4298
cristye076a6e2010-08-15 19:59:43 +00004299 ssize_t
4300 page_size;
4301
cristy3ed852e2009-09-05 21:47:34 +00004302 assert(image != (Image *) NULL);
4303 assert(image->signature == MagickSignature);
4304 if (image->debug != MagickFalse)
4305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4306 assert(image->cache != (void *) NULL);
4307 assert(filename != (const char *) NULL);
4308 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004309 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004310 cache_info=(CacheInfo *) image->cache;
4311 assert(cache_info->signature == MagickSignature);
4312 if (attach != MagickFalse)
4313 {
4314 /*
cristy01b7eb02009-09-10 23:10:14 +00004315 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004316 */
4317 if (image->debug != MagickFalse)
4318 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004319 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004320 (void) CopyMagickString(cache_info->cache_filename,filename,
4321 MaxTextExtent);
4322 cache_info->type=DiskCache;
4323 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004324 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004325 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004326 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004327 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004328 }
cristy01b7eb02009-09-10 23:10:14 +00004329 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4330 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004331 {
cristyf84a1932010-01-03 18:00:18 +00004332 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004333 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004334 (cache_info->reference_count == 1))
4335 {
4336 int
4337 status;
4338
4339 /*
cristy01b7eb02009-09-10 23:10:14 +00004340 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004341 */
cristy320684d2011-09-23 14:55:47 +00004342 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004343 if (status == 0)
4344 {
4345 (void) CopyMagickString(cache_info->cache_filename,filename,
4346 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004347 *offset+=cache_info->length+page_size-(cache_info->length %
4348 page_size);
cristyf84a1932010-01-03 18:00:18 +00004349 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004350 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004351 if (image->debug != MagickFalse)
4352 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4353 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004354 return(MagickTrue);
4355 }
4356 }
cristyf84a1932010-01-03 18:00:18 +00004357 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004358 }
4359 /*
cristy01b7eb02009-09-10 23:10:14 +00004360 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004361 */
4362 clone_image=(*image);
4363 clone_info=(CacheInfo *) clone_image.cache;
4364 image->cache=ClonePixelCache(cache_info);
4365 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4366 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4367 cache_info->type=DiskCache;
4368 cache_info->offset=(*offset);
4369 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004370 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004371 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004372 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004373 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004374 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4375 return(status);
4376}
4377
4378/*
4379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4380% %
4381% %
4382% %
4383+ Q u e u e A u t h e n t i c N e x u s %
4384% %
4385% %
4386% %
4387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4388%
4389% QueueAuthenticNexus() allocates an region to store image pixels as defined
4390% by the region rectangle and returns a pointer to the region. This region is
4391% subsequently transferred from the pixel cache with
4392% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4393% pixels are transferred, otherwise a NULL is returned.
4394%
4395% The format of the QueueAuthenticNexus() method is:
4396%
cristy4c08aed2011-07-01 19:47:50 +00004397% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004398% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004399% const MagickBooleanType clone,NexusInfo *nexus_info,
4400% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004401%
4402% A description of each parameter follows:
4403%
4404% o image: the image.
4405%
4406% o x,y,columns,rows: These values define the perimeter of a region of
4407% pixels.
4408%
4409% o nexus_info: the cache nexus to set.
4410%
cristy65dbf172011-10-06 17:32:04 +00004411% o clone: clone the pixel cache.
4412%
cristy3ed852e2009-09-05 21:47:34 +00004413% o exception: return any errors or warnings in this structure.
4414%
4415*/
cristya6577ff2011-09-02 19:54:26 +00004416MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004417 const ssize_t y,const size_t columns,const size_t rows,
4418 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004419{
4420 CacheInfo
4421 *cache_info;
4422
4423 MagickOffsetType
4424 offset;
4425
4426 MagickSizeType
4427 number_pixels;
4428
4429 RectangleInfo
4430 region;
4431
4432 /*
4433 Validate pixel cache geometry.
4434 */
cristye7cc7cf2010-09-21 13:26:47 +00004435 assert(image != (const Image *) NULL);
4436 assert(image->signature == MagickSignature);
4437 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004438 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004439 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004440 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004441 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004442 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4443 {
4444 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4445 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004446 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004447 }
cristybb503372010-05-27 20:51:26 +00004448 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4449 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004450 {
4451 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4452 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004453 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004454 }
4455 offset=(MagickOffsetType) y*cache_info->columns+x;
4456 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004457 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004458 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4459 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4460 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004461 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004462 /*
4463 Return pixel cache.
4464 */
4465 region.x=x;
4466 region.y=y;
4467 region.width=columns;
4468 region.height=rows;
4469 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4470}
4471
4472/*
4473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474% %
4475% %
4476% %
4477+ 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 %
4478% %
4479% %
4480% %
4481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482%
4483% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4484% defined by the region rectangle and returns a pointer to the region. This
4485% region is subsequently transferred from the pixel cache with
4486% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4487% pixels are transferred, otherwise a NULL is returned.
4488%
4489% The format of the QueueAuthenticPixelsCache() method is:
4490%
cristy4c08aed2011-07-01 19:47:50 +00004491% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004492% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004493% ExceptionInfo *exception)
4494%
4495% A description of each parameter follows:
4496%
4497% o image: the image.
4498%
4499% o x,y,columns,rows: These values define the perimeter of a region of
4500% pixels.
4501%
4502% o exception: return any errors or warnings in this structure.
4503%
4504*/
cristy4c08aed2011-07-01 19:47:50 +00004505static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004506 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004507 ExceptionInfo *exception)
4508{
4509 CacheInfo
4510 *cache_info;
4511
cristy5c9e6f22010-09-17 17:31:01 +00004512 const int
4513 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004514
cristy4c08aed2011-07-01 19:47:50 +00004515 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004516 *q;
cristy4c08aed2011-07-01 19:47:50 +00004517
cristye7cc7cf2010-09-21 13:26:47 +00004518 assert(image != (const Image *) NULL);
4519 assert(image->signature == MagickSignature);
4520 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004521 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004522 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004523 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004524 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4525 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004526 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004527}
4528
4529/*
4530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4531% %
4532% %
4533% %
4534% Q u e u e A u t h e n t i c P i x e l s %
4535% %
4536% %
4537% %
4538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4539%
4540% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004541% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004542% region is returned, otherwise NULL is returned. The returned pointer may
4543% point to a temporary working buffer for the pixels or it may point to the
4544% final location of the pixels in memory.
4545%
4546% Write-only access means that any existing pixel values corresponding to
4547% the region are ignored. This is useful if the initial image is being
4548% created from scratch, or if the existing pixel values are to be
4549% completely replaced without need to refer to their pre-existing values.
4550% The application is free to read and write the pixel buffer returned by
4551% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4552% initialize the pixel array values. Initializing pixel array values is the
4553% application's responsibility.
4554%
4555% Performance is maximized if the selected region is part of one row, or
4556% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004557% pixels in-place (without a copy) if the image is in memory, or in a
4558% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004559% by the user.
4560%
4561% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004562% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4563% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4564% obtain the meta-content (of type void) corresponding to the region.
4565% Once the Quantum (and/or Quantum) array has been updated, the
4566% changes must be saved back to the underlying image using
4567% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004568%
4569% The format of the QueueAuthenticPixels() method is:
4570%
cristy4c08aed2011-07-01 19:47:50 +00004571% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004572% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004573% ExceptionInfo *exception)
4574%
4575% A description of each parameter follows:
4576%
4577% o image: the image.
4578%
4579% o x,y,columns,rows: These values define the perimeter of a region of
4580% pixels.
4581%
4582% o exception: return any errors or warnings in this structure.
4583%
4584*/
cristy4c08aed2011-07-01 19:47:50 +00004585MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004586 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004587 ExceptionInfo *exception)
4588{
4589 CacheInfo
4590 *cache_info;
4591
cristy2036f5c2010-09-19 21:18:17 +00004592 const int
4593 id = GetOpenMPThreadId();
4594
cristy4c08aed2011-07-01 19:47:50 +00004595 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004596 *q;
cristy4c08aed2011-07-01 19:47:50 +00004597
cristy3ed852e2009-09-05 21:47:34 +00004598 assert(image != (Image *) NULL);
4599 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004600 assert(image->cache != (Cache) NULL);
4601 cache_info=(CacheInfo *) image->cache;
4602 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004603 if (cache_info->methods.queue_authentic_pixels_handler !=
4604 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004605 {
cristyacd2ed22011-08-30 01:44:23 +00004606 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004607 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004608 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004609 }
cristy2036f5c2010-09-19 21:18:17 +00004610 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004611 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4612 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004613 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004614}
4615
4616/*
4617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4618% %
4619% %
4620% %
cristy4c08aed2011-07-01 19:47:50 +00004621+ 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 +00004622% %
4623% %
4624% %
4625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4626%
cristy4c08aed2011-07-01 19:47:50 +00004627% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004628% the pixel cache.
4629%
cristy4c08aed2011-07-01 19:47:50 +00004630% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004631%
cristy4c08aed2011-07-01 19:47:50 +00004632% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004633% NexusInfo *nexus_info,ExceptionInfo *exception)
4634%
4635% A description of each parameter follows:
4636%
4637% o cache_info: the pixel cache.
4638%
cristy4c08aed2011-07-01 19:47:50 +00004639% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004640%
4641% o exception: return any errors or warnings in this structure.
4642%
4643*/
cristy4c08aed2011-07-01 19:47:50 +00004644static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004645 NexusInfo *nexus_info,ExceptionInfo *exception)
4646{
4647 MagickOffsetType
4648 count,
4649 offset;
4650
4651 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004652 extent,
4653 length;
cristy3ed852e2009-09-05 21:47:34 +00004654
cristybb503372010-05-27 20:51:26 +00004655 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004656 y;
4657
cristy4c08aed2011-07-01 19:47:50 +00004658 register unsigned char
4659 *restrict q;
4660
cristybb503372010-05-27 20:51:26 +00004661 size_t
cristy3ed852e2009-09-05 21:47:34 +00004662 rows;
4663
cristy4c08aed2011-07-01 19:47:50 +00004664 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004665 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004666 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004667 return(MagickTrue);
4668 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4669 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004670 length=(MagickSizeType) nexus_info->region.width*
4671 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004672 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004673 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004674 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004675 switch (cache_info->type)
4676 {
4677 case MemoryCache:
4678 case MapCache:
4679 {
cristy4c08aed2011-07-01 19:47:50 +00004680 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004681 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004682
4683 /*
cristy4c08aed2011-07-01 19:47:50 +00004684 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004685 */
cristydd341db2010-03-04 19:06:38 +00004686 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004687 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004688 {
cristy48078b12010-09-23 17:11:01 +00004689 length=extent;
cristydd341db2010-03-04 19:06:38 +00004690 rows=1UL;
4691 }
cristy4c08aed2011-07-01 19:47:50 +00004692 p=(unsigned char *) cache_info->metacontent+offset*
4693 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004694 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004695 {
cristy8f036fe2010-09-18 02:02:00 +00004696 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004697 p+=cache_info->metacontent_extent*cache_info->columns;
4698 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004699 }
4700 break;
4701 }
4702 case DiskCache:
4703 {
4704 /*
cristy4c08aed2011-07-01 19:47:50 +00004705 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004706 */
4707 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4708 {
4709 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4710 cache_info->cache_filename);
4711 return(MagickFalse);
4712 }
cristydd341db2010-03-04 19:06:38 +00004713 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004714 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004715 {
cristy48078b12010-09-23 17:11:01 +00004716 length=extent;
cristydd341db2010-03-04 19:06:38 +00004717 rows=1UL;
4718 }
cristy48078b12010-09-23 17:11:01 +00004719 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004720 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004721 {
cristy48078b12010-09-23 17:11:01 +00004722 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004723 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004724 cache_info->metacontent_extent,length,(unsigned char *) q);
4725 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004726 break;
4727 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004728 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004729 }
cristybb503372010-05-27 20:51:26 +00004730 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004731 {
4732 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4733 cache_info->cache_filename);
4734 return(MagickFalse);
4735 }
4736 break;
4737 }
4738 default:
4739 break;
4740 }
4741 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004742 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004743 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004744 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004745 nexus_info->region.width,(double) nexus_info->region.height,(double)
4746 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004747 return(MagickTrue);
4748}
4749
4750/*
4751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4752% %
4753% %
4754% %
4755+ R e a d P i x e l C a c h e P i x e l s %
4756% %
4757% %
4758% %
4759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4760%
4761% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4762% cache.
4763%
4764% The format of the ReadPixelCachePixels() method is:
4765%
4766% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4767% NexusInfo *nexus_info,ExceptionInfo *exception)
4768%
4769% A description of each parameter follows:
4770%
4771% o cache_info: the pixel cache.
4772%
4773% o nexus_info: the cache nexus to read the pixels.
4774%
4775% o exception: return any errors or warnings in this structure.
4776%
4777*/
4778static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4779 NexusInfo *nexus_info,ExceptionInfo *exception)
4780{
4781 MagickOffsetType
4782 count,
4783 offset;
4784
4785 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004786 extent,
4787 length;
cristy3ed852e2009-09-05 21:47:34 +00004788
cristy4c08aed2011-07-01 19:47:50 +00004789 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004790 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004791
cristye076a6e2010-08-15 19:59:43 +00004792 register ssize_t
4793 y;
4794
cristybb503372010-05-27 20:51:26 +00004795 size_t
cristy3ed852e2009-09-05 21:47:34 +00004796 rows;
4797
cristy4c08aed2011-07-01 19:47:50 +00004798 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004799 return(MagickTrue);
4800 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4801 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004802 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004803 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004804 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004805 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004806 q=nexus_info->pixels;
4807 switch (cache_info->type)
4808 {
4809 case MemoryCache:
4810 case MapCache:
4811 {
cristy4c08aed2011-07-01 19:47:50 +00004812 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004813 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004814
4815 /*
4816 Read pixels from memory.
4817 */
cristydd341db2010-03-04 19:06:38 +00004818 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004819 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004820 {
cristy48078b12010-09-23 17:11:01 +00004821 length=extent;
cristydd341db2010-03-04 19:06:38 +00004822 rows=1UL;
4823 }
cristyed231572011-07-14 02:18:59 +00004824 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004825 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004826 {
cristy8f036fe2010-09-18 02:02:00 +00004827 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004828 p+=cache_info->number_channels*cache_info->columns;
4829 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004830 }
4831 break;
4832 }
4833 case DiskCache:
4834 {
4835 /*
4836 Read pixels from disk.
4837 */
4838 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4839 {
4840 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4841 cache_info->cache_filename);
4842 return(MagickFalse);
4843 }
cristydd341db2010-03-04 19:06:38 +00004844 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004845 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004846 {
cristy48078b12010-09-23 17:11:01 +00004847 length=extent;
cristydd341db2010-03-04 19:06:38 +00004848 rows=1UL;
4849 }
cristybb503372010-05-27 20:51:26 +00004850 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004851 {
4852 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004853 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004854 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004855 break;
4856 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004857 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004858 }
cristybb503372010-05-27 20:51:26 +00004859 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004860 {
4861 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4862 cache_info->cache_filename);
4863 return(MagickFalse);
4864 }
4865 break;
4866 }
4867 default:
4868 break;
4869 }
4870 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004871 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004872 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004873 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004874 nexus_info->region.width,(double) nexus_info->region.height,(double)
4875 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004876 return(MagickTrue);
4877}
4878
4879/*
4880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4881% %
4882% %
4883% %
4884+ R e f e r e n c e P i x e l C a c h e %
4885% %
4886% %
4887% %
4888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4889%
4890% ReferencePixelCache() increments the reference count associated with the
4891% pixel cache returning a pointer to the cache.
4892%
4893% The format of the ReferencePixelCache method is:
4894%
4895% Cache ReferencePixelCache(Cache cache_info)
4896%
4897% A description of each parameter follows:
4898%
4899% o cache_info: the pixel cache.
4900%
4901*/
cristya6577ff2011-09-02 19:54:26 +00004902MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004903{
4904 CacheInfo
4905 *cache_info;
4906
4907 assert(cache != (Cache *) NULL);
4908 cache_info=(CacheInfo *) cache;
4909 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004910 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004911 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004912 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004913 return(cache_info);
4914}
4915
4916/*
4917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4918% %
4919% %
4920% %
4921+ S e t P i x e l C a c h e M e t h o d s %
4922% %
4923% %
4924% %
4925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4926%
4927% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4928%
4929% The format of the SetPixelCacheMethods() method is:
4930%
4931% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4932%
4933% A description of each parameter follows:
4934%
4935% o cache: the pixel cache.
4936%
4937% o cache_methods: Specifies a pointer to a CacheMethods structure.
4938%
4939*/
cristya6577ff2011-09-02 19:54:26 +00004940MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004941{
4942 CacheInfo
4943 *cache_info;
4944
4945 GetOneAuthenticPixelFromHandler
4946 get_one_authentic_pixel_from_handler;
4947
4948 GetOneVirtualPixelFromHandler
4949 get_one_virtual_pixel_from_handler;
4950
4951 /*
4952 Set cache pixel methods.
4953 */
4954 assert(cache != (Cache) NULL);
4955 assert(cache_methods != (CacheMethods *) NULL);
4956 cache_info=(CacheInfo *) cache;
4957 assert(cache_info->signature == MagickSignature);
4958 if (cache_info->debug != MagickFalse)
4959 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4960 cache_info->filename);
4961 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4962 cache_info->methods.get_virtual_pixel_handler=
4963 cache_methods->get_virtual_pixel_handler;
4964 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4965 cache_info->methods.destroy_pixel_handler=
4966 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004967 if (cache_methods->get_virtual_metacontent_from_handler !=
4968 (GetVirtualMetacontentFromHandler) NULL)
4969 cache_info->methods.get_virtual_metacontent_from_handler=
4970 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004971 if (cache_methods->get_authentic_pixels_handler !=
4972 (GetAuthenticPixelsHandler) NULL)
4973 cache_info->methods.get_authentic_pixels_handler=
4974 cache_methods->get_authentic_pixels_handler;
4975 if (cache_methods->queue_authentic_pixels_handler !=
4976 (QueueAuthenticPixelsHandler) NULL)
4977 cache_info->methods.queue_authentic_pixels_handler=
4978 cache_methods->queue_authentic_pixels_handler;
4979 if (cache_methods->sync_authentic_pixels_handler !=
4980 (SyncAuthenticPixelsHandler) NULL)
4981 cache_info->methods.sync_authentic_pixels_handler=
4982 cache_methods->sync_authentic_pixels_handler;
4983 if (cache_methods->get_authentic_pixels_from_handler !=
4984 (GetAuthenticPixelsFromHandler) NULL)
4985 cache_info->methods.get_authentic_pixels_from_handler=
4986 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004987 if (cache_methods->get_authentic_metacontent_from_handler !=
4988 (GetAuthenticMetacontentFromHandler) NULL)
4989 cache_info->methods.get_authentic_metacontent_from_handler=
4990 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004991 get_one_virtual_pixel_from_handler=
4992 cache_info->methods.get_one_virtual_pixel_from_handler;
4993 if (get_one_virtual_pixel_from_handler !=
4994 (GetOneVirtualPixelFromHandler) NULL)
4995 cache_info->methods.get_one_virtual_pixel_from_handler=
4996 cache_methods->get_one_virtual_pixel_from_handler;
4997 get_one_authentic_pixel_from_handler=
4998 cache_methods->get_one_authentic_pixel_from_handler;
4999 if (get_one_authentic_pixel_from_handler !=
5000 (GetOneAuthenticPixelFromHandler) NULL)
5001 cache_info->methods.get_one_authentic_pixel_from_handler=
5002 cache_methods->get_one_authentic_pixel_from_handler;
5003}
5004
5005/*
5006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5007% %
5008% %
5009% %
5010+ S e t P i x e l C a c h e N e x u s P i x e l s %
5011% %
5012% %
5013% %
5014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5015%
5016% SetPixelCacheNexusPixels() defines the region of the cache for the
5017% specified cache nexus.
5018%
5019% The format of the SetPixelCacheNexusPixels() method is:
5020%
cristy4c08aed2011-07-01 19:47:50 +00005021% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005022% const RectangleInfo *region,NexusInfo *nexus_info,
5023% ExceptionInfo *exception)
5024%
5025% A description of each parameter follows:
5026%
5027% o image: the image.
5028%
5029% o region: A pointer to the RectangleInfo structure that defines the
5030% region of this particular cache nexus.
5031%
5032% o nexus_info: the cache nexus to set.
5033%
5034% o exception: return any errors or warnings in this structure.
5035%
5036*/
cristyabd6e372010-09-15 19:11:26 +00005037
5038static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5039 NexusInfo *nexus_info,ExceptionInfo *exception)
5040{
5041 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5042 return(MagickFalse);
5043 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005044 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005045 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005046 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005047 {
5048 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005049 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005050 nexus_info->length);
5051 }
cristy4c08aed2011-07-01 19:47:50 +00005052 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005053 {
5054 (void) ThrowMagickException(exception,GetMagickModule(),
5055 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5056 cache_info->filename);
5057 return(MagickFalse);
5058 }
5059 return(MagickTrue);
5060}
5061
cristy4c08aed2011-07-01 19:47:50 +00005062static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005063 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5064{
5065 CacheInfo
5066 *cache_info;
5067
5068 MagickBooleanType
5069 status;
5070
cristy3ed852e2009-09-05 21:47:34 +00005071 MagickSizeType
5072 length,
5073 number_pixels;
5074
cristy3ed852e2009-09-05 21:47:34 +00005075 cache_info=(CacheInfo *) image->cache;
5076 assert(cache_info->signature == MagickSignature);
5077 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005078 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005079 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005080 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5081 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005082 {
cristybb503372010-05-27 20:51:26 +00005083 ssize_t
cristybad067a2010-02-15 17:20:55 +00005084 x,
5085 y;
cristy3ed852e2009-09-05 21:47:34 +00005086
cristyeaedf062010-05-29 22:36:02 +00005087 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5088 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005089 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5090 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005091 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005092 ((nexus_info->region.width == cache_info->columns) ||
5093 ((nexus_info->region.width % cache_info->columns) == 0)))))
5094 {
5095 MagickOffsetType
5096 offset;
5097
5098 /*
5099 Pixels are accessed directly from memory.
5100 */
5101 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5102 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005103 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005104 offset;
5105 nexus_info->metacontent=(void *) NULL;
5106 if (cache_info->metacontent_extent != 0)
5107 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5108 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005109 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005110 }
5111 }
5112 /*
5113 Pixels are stored in a cache region until they are synced to the cache.
5114 */
5115 number_pixels=(MagickSizeType) nexus_info->region.width*
5116 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005117 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005118 if (cache_info->metacontent_extent != 0)
5119 length+=number_pixels*cache_info->metacontent_extent;
5120 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005121 {
5122 nexus_info->length=length;
5123 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5124 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005125 {
5126 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005127 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005128 }
cristy3ed852e2009-09-05 21:47:34 +00005129 }
5130 else
5131 if (nexus_info->length != length)
5132 {
5133 RelinquishCacheNexusPixels(nexus_info);
5134 nexus_info->length=length;
5135 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5136 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005137 {
5138 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005139 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005140 }
cristy3ed852e2009-09-05 21:47:34 +00005141 }
5142 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005143 nexus_info->metacontent=(void *) NULL;
5144 if (cache_info->metacontent_extent != 0)
5145 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005146 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005147 return(nexus_info->pixels);
5148}
5149
5150/*
5151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152% %
5153% %
5154% %
5155% 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 %
5156% %
5157% %
5158% %
5159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5160%
5161% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5162% pixel cache and returns the previous setting. A virtual pixel is any pixel
5163% access that is outside the boundaries of the image cache.
5164%
5165% The format of the SetPixelCacheVirtualMethod() method is:
5166%
5167% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5168% const VirtualPixelMethod virtual_pixel_method)
5169%
5170% A description of each parameter follows:
5171%
5172% o image: the image.
5173%
5174% o virtual_pixel_method: choose the type of virtual pixel.
5175%
5176*/
cristyd1dd6e42011-09-04 01:46:08 +00005177MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005178 const VirtualPixelMethod virtual_pixel_method)
5179{
5180 CacheInfo
5181 *cache_info;
5182
5183 VirtualPixelMethod
5184 method;
5185
5186 assert(image != (Image *) NULL);
5187 assert(image->signature == MagickSignature);
5188 if (image->debug != MagickFalse)
5189 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5190 assert(image->cache != (Cache) NULL);
5191 cache_info=(CacheInfo *) image->cache;
5192 assert(cache_info->signature == MagickSignature);
5193 method=cache_info->virtual_pixel_method;
5194 cache_info->virtual_pixel_method=virtual_pixel_method;
5195 return(method);
5196}
5197
5198/*
5199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5200% %
5201% %
5202% %
5203+ 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 %
5204% %
5205% %
5206% %
5207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5208%
5209% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5210% in-memory or disk cache. The method returns MagickTrue if the pixel region
5211% is synced, otherwise MagickFalse.
5212%
5213% The format of the SyncAuthenticPixelCacheNexus() method is:
5214%
5215% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5216% NexusInfo *nexus_info,ExceptionInfo *exception)
5217%
5218% A description of each parameter follows:
5219%
5220% o image: the image.
5221%
5222% o nexus_info: the cache nexus to sync.
5223%
5224% o exception: return any errors or warnings in this structure.
5225%
5226*/
cristya6577ff2011-09-02 19:54:26 +00005227MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005228 NexusInfo *nexus_info,ExceptionInfo *exception)
5229{
5230 CacheInfo
5231 *cache_info;
5232
5233 MagickBooleanType
5234 status;
5235
5236 /*
5237 Transfer pixels to the cache.
5238 */
5239 assert(image != (Image *) NULL);
5240 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005241 if (image->cache == (Cache) NULL)
5242 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5243 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005244 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005245 if (cache_info->type == UndefinedCache)
5246 return(MagickFalse);
5247 if ((image->clip_mask != (Image *) NULL) &&
5248 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5249 return(MagickFalse);
5250 if ((image->mask != (Image *) NULL) &&
5251 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5252 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005253 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005254 return(MagickTrue);
5255 assert(cache_info->signature == MagickSignature);
5256 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005257 if ((cache_info->metacontent_extent != 0) &&
5258 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005259 return(MagickFalse);
5260 return(status);
5261}
5262
5263/*
5264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5265% %
5266% %
5267% %
5268+ S y n c A u t h e n t i c P i x e l C a c h e %
5269% %
5270% %
5271% %
5272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5273%
5274% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5275% or disk cache. The method returns MagickTrue if the pixel region is synced,
5276% otherwise MagickFalse.
5277%
5278% The format of the SyncAuthenticPixelsCache() method is:
5279%
5280% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5281% ExceptionInfo *exception)
5282%
5283% A description of each parameter follows:
5284%
5285% o image: the image.
5286%
5287% o exception: return any errors or warnings in this structure.
5288%
5289*/
5290static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5291 ExceptionInfo *exception)
5292{
5293 CacheInfo
5294 *cache_info;
5295
cristy5c9e6f22010-09-17 17:31:01 +00005296 const int
5297 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005298
cristy4c08aed2011-07-01 19:47:50 +00005299 MagickBooleanType
5300 status;
5301
cristye7cc7cf2010-09-21 13:26:47 +00005302 assert(image != (Image *) NULL);
5303 assert(image->signature == MagickSignature);
5304 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005305 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005306 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005307 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005308 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5309 exception);
5310 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005311}
5312
5313/*
5314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315% %
5316% %
5317% %
5318% S y n c A u t h e n t i c P i x e l s %
5319% %
5320% %
5321% %
5322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5323%
5324% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5325% The method returns MagickTrue if the pixel region is flushed, otherwise
5326% MagickFalse.
5327%
5328% The format of the SyncAuthenticPixels() method is:
5329%
5330% MagickBooleanType SyncAuthenticPixels(Image *image,
5331% ExceptionInfo *exception)
5332%
5333% A description of each parameter follows:
5334%
5335% o image: the image.
5336%
5337% o exception: return any errors or warnings in this structure.
5338%
5339*/
5340MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5341 ExceptionInfo *exception)
5342{
5343 CacheInfo
5344 *cache_info;
5345
cristy2036f5c2010-09-19 21:18:17 +00005346 const int
5347 id = GetOpenMPThreadId();
5348
cristy4c08aed2011-07-01 19:47:50 +00005349 MagickBooleanType
5350 status;
5351
cristy3ed852e2009-09-05 21:47:34 +00005352 assert(image != (Image *) NULL);
5353 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005354 assert(image->cache != (Cache) NULL);
5355 cache_info=(CacheInfo *) image->cache;
5356 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005357 if (cache_info->methods.sync_authentic_pixels_handler !=
5358 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005359 {
5360 status=cache_info->methods.sync_authentic_pixels_handler(image,
5361 exception);
5362 return(status);
5363 }
cristy2036f5c2010-09-19 21:18:17 +00005364 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005365 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5366 exception);
5367 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005368}
5369
5370/*
5371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5372% %
5373% %
5374% %
cristyd1dd6e42011-09-04 01:46:08 +00005375+ 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 +00005376% %
5377% %
5378% %
5379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5380%
5381% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5382% The method returns MagickTrue if the pixel region is flushed, otherwise
5383% MagickFalse.
5384%
5385% The format of the SyncImagePixelCache() method is:
5386%
5387% MagickBooleanType SyncImagePixelCache(Image *image,
5388% ExceptionInfo *exception)
5389%
5390% A description of each parameter follows:
5391%
5392% o image: the image.
5393%
5394% o exception: return any errors or warnings in this structure.
5395%
5396*/
cristyd1dd6e42011-09-04 01:46:08 +00005397MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005398 ExceptionInfo *exception)
5399{
5400 CacheInfo
5401 *cache_info;
5402
5403 assert(image != (Image *) NULL);
5404 assert(exception != (ExceptionInfo *) NULL);
5405 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5406 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5407}
5408
5409/*
5410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5411% %
5412% %
5413% %
cristy4c08aed2011-07-01 19:47:50 +00005414+ 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 +00005415% %
5416% %
5417% %
5418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5419%
cristy4c08aed2011-07-01 19:47:50 +00005420% WritePixelCacheMetacontent() writes the meta-content to the specified region
5421% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005422%
cristy4c08aed2011-07-01 19:47:50 +00005423% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005424%
cristy4c08aed2011-07-01 19:47:50 +00005425% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005426% NexusInfo *nexus_info,ExceptionInfo *exception)
5427%
5428% A description of each parameter follows:
5429%
5430% o cache_info: the pixel cache.
5431%
cristy4c08aed2011-07-01 19:47:50 +00005432% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005433%
5434% o exception: return any errors or warnings in this structure.
5435%
5436*/
cristy4c08aed2011-07-01 19:47:50 +00005437static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005438 NexusInfo *nexus_info,ExceptionInfo *exception)
5439{
5440 MagickOffsetType
5441 count,
5442 offset;
5443
5444 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005445 extent,
5446 length;
cristy3ed852e2009-09-05 21:47:34 +00005447
cristy4c08aed2011-07-01 19:47:50 +00005448 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005449 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005450
cristybb503372010-05-27 20:51:26 +00005451 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005452 y;
5453
cristybb503372010-05-27 20:51:26 +00005454 size_t
cristy3ed852e2009-09-05 21:47:34 +00005455 rows;
5456
cristy4c08aed2011-07-01 19:47:50 +00005457 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005458 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005459 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005460 return(MagickTrue);
5461 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5462 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005463 length=(MagickSizeType) nexus_info->region.width*
5464 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005465 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005466 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005467 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005468 switch (cache_info->type)
5469 {
5470 case MemoryCache:
5471 case MapCache:
5472 {
cristy4c08aed2011-07-01 19:47:50 +00005473 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005474 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005475
5476 /*
cristy4c08aed2011-07-01 19:47:50 +00005477 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005478 */
cristydd341db2010-03-04 19:06:38 +00005479 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005480 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005481 {
cristy48078b12010-09-23 17:11:01 +00005482 length=extent;
cristydd341db2010-03-04 19:06:38 +00005483 rows=1UL;
5484 }
cristy4c08aed2011-07-01 19:47:50 +00005485 q=(unsigned char *) cache_info->metacontent+offset*
5486 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005487 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005488 {
cristy8f036fe2010-09-18 02:02:00 +00005489 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005490 p+=nexus_info->region.width*cache_info->metacontent_extent;
5491 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005492 }
5493 break;
5494 }
5495 case DiskCache:
5496 {
5497 /*
cristy4c08aed2011-07-01 19:47:50 +00005498 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005499 */
5500 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5501 {
5502 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5503 cache_info->cache_filename);
5504 return(MagickFalse);
5505 }
cristydd341db2010-03-04 19:06:38 +00005506 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005507 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005508 {
cristy48078b12010-09-23 17:11:01 +00005509 length=extent;
cristydd341db2010-03-04 19:06:38 +00005510 rows=1UL;
5511 }
cristy48078b12010-09-23 17:11:01 +00005512 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005513 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005514 {
cristy48078b12010-09-23 17:11:01 +00005515 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005516 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005517 cache_info->metacontent_extent,length,(const unsigned char *) p);
5518 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005519 break;
cristy4c08aed2011-07-01 19:47:50 +00005520 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005521 offset+=cache_info->columns;
5522 }
cristybb503372010-05-27 20:51:26 +00005523 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005524 {
5525 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5526 cache_info->cache_filename);
5527 return(MagickFalse);
5528 }
5529 break;
5530 }
5531 default:
5532 break;
5533 }
5534 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005535 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005536 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005537 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005538 nexus_info->region.width,(double) nexus_info->region.height,(double)
5539 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005540 return(MagickTrue);
5541}
5542
5543/*
5544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5545% %
5546% %
5547% %
5548+ W r i t e C a c h e P i x e l s %
5549% %
5550% %
5551% %
5552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5553%
5554% WritePixelCachePixels() writes image pixels to the specified region of the
5555% pixel cache.
5556%
5557% The format of the WritePixelCachePixels() method is:
5558%
5559% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5560% NexusInfo *nexus_info,ExceptionInfo *exception)
5561%
5562% A description of each parameter follows:
5563%
5564% o cache_info: the pixel cache.
5565%
5566% o nexus_info: the cache nexus to write the pixels.
5567%
5568% o exception: return any errors or warnings in this structure.
5569%
5570*/
5571static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5572 NexusInfo *nexus_info,ExceptionInfo *exception)
5573{
5574 MagickOffsetType
5575 count,
5576 offset;
5577
5578 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005579 extent,
5580 length;
cristy3ed852e2009-09-05 21:47:34 +00005581
cristy4c08aed2011-07-01 19:47:50 +00005582 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005583 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005584
cristybb503372010-05-27 20:51:26 +00005585 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005586 y;
5587
cristybb503372010-05-27 20:51:26 +00005588 size_t
cristy3ed852e2009-09-05 21:47:34 +00005589 rows;
5590
cristy4c08aed2011-07-01 19:47:50 +00005591 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005592 return(MagickTrue);
5593 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5594 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005595 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005596 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005597 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005598 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005599 p=nexus_info->pixels;
5600 switch (cache_info->type)
5601 {
5602 case MemoryCache:
5603 case MapCache:
5604 {
cristy4c08aed2011-07-01 19:47:50 +00005605 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005606 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005607
5608 /*
5609 Write pixels to memory.
5610 */
cristydd341db2010-03-04 19:06:38 +00005611 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005612 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005613 {
cristy48078b12010-09-23 17:11:01 +00005614 length=extent;
cristydd341db2010-03-04 19:06:38 +00005615 rows=1UL;
5616 }
cristyed231572011-07-14 02:18:59 +00005617 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005618 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005619 {
cristy8f036fe2010-09-18 02:02:00 +00005620 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005621 p+=nexus_info->region.width*cache_info->number_channels;
5622 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005623 }
5624 break;
5625 }
5626 case DiskCache:
5627 {
5628 /*
5629 Write pixels to disk.
5630 */
5631 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5632 {
5633 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5634 cache_info->cache_filename);
5635 return(MagickFalse);
5636 }
cristydd341db2010-03-04 19:06:38 +00005637 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005638 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005639 {
cristy48078b12010-09-23 17:11:01 +00005640 length=extent;
cristydd341db2010-03-04 19:06:38 +00005641 rows=1UL;
5642 }
cristybb503372010-05-27 20:51:26 +00005643 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005644 {
5645 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005646 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005647 p);
5648 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005649 break;
cristyed231572011-07-14 02:18:59 +00005650 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005651 offset+=cache_info->columns;
5652 }
cristybb503372010-05-27 20:51:26 +00005653 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005654 {
5655 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5656 cache_info->cache_filename);
5657 return(MagickFalse);
5658 }
5659 break;
5660 }
5661 default:
5662 break;
5663 }
5664 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005665 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005666 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005667 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005668 nexus_info->region.width,(double) nexus_info->region.height,(double)
5669 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005670 return(MagickTrue);
5671}