blob: 41acfbeddf9c57a9a9598cb064676c4d9b939216 [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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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
425 i;
426
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);
cristy4c08aed2011-07-01 19:47:50 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,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;
cristybb503372010-05-27 20:51:26 +0000451 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy4c08aed2011-07-01 19:47:50 +0000453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000454 break;
cristy4c08aed2011-07-01 19:47:50 +0000455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000456 {
cristy4c08aed2011-07-01 19:47:50 +0000457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000463 }
cristyed231572011-07-14 02:18:59 +0000464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000467 }
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000470 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000471 return(MagickFalse);
472 return(MagickTrue);
473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
480+ C l o n e P i x e l C a c h e %
481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
486% ClonePixelCache() clones a pixel cache.
487%
488% The format of the ClonePixelCache() method is:
489%
490% Cache ClonePixelCache(const Cache cache)
491%
492% A description of each parameter follows:
493%
494% o cache: the pixel cache.
495%
496*/
cristya6577ff2011-09-02 19:54:26 +0000497MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000498{
499 CacheInfo
500 *clone_info;
501
502 const CacheInfo
503 *cache_info;
504
cristy9f027d12011-09-21 01:17:17 +0000505 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
516}
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520% %
521% %
522% %
cristy60c44a82009-10-07 00:58:49 +0000523+ 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 +0000524% %
525% %
526% %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528% ClonePixelCachePixels() clones the source pixel cache to the destination
529% cache.
530%
531% The format of the ClonePixelCachePixels() method is:
532%
533% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534% CacheInfo *source_info,ExceptionInfo *exception)
535%
536% A description of each parameter follows:
537%
538% o cache_info: the pixel cache.
539%
540% o source_info: the source pixel cache.
541%
542% o exception: return any errors or warnings in this structure.
543%
544*/
545
546static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
547{
548 int
549 status;
550
cristy5ee247a2010-02-12 15:42:34 +0000551 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000552 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000553 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000554 {
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
558 }
cristyf84a1932010-01-03 18:00:18 +0000559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000560 return(status == -1 ? MagickFalse : MagickTrue);
561}
562
563static void LimitPixelCacheDescriptors(void)
564{
565 register CacheInfo
566 *p,
567 *q;
568
569 /*
570 Limit # of open file descriptors.
571 */
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
573 return;
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (cache_resources == (SplayTreeInfo *) NULL)
576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return;
579 }
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
583 {
584 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000585 break;
cristy3ed852e2009-09-05 21:47:34 +0000586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 }
588 for (q=p; p != (CacheInfo *) NULL; )
589 {
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000592 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
594 }
595 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000596 {
597 /*
598 Close least recently used cache.
599 */
600 (void) close(q->file);
601 q->file=(-1);
602 }
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604}
605
606static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
608{
609 if (x > y)
610 return(x);
611 return(y);
612}
613
614static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x < y)
618 return(x);
619 return(y);
620}
621
622static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
623 const MapMode mode)
624{
625 int
626 file;
627
628 /*
629 Open pixel cache on disk.
630 */
cristyf84a1932010-01-03 18:00:18 +0000631 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000632 if (cache_info->file != -1)
633 {
cristyf84a1932010-01-03 18:00:18 +0000634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 return(MagickTrue); /* cache already open */
636 }
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
640 else
641 switch (mode)
642 {
643 case ReadMode:
644 {
cristy18c6c272011-09-23 14:40:37 +0000645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 case WriteMode:
649 {
cristy18c6c272011-09-23 14:40:37 +0000650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000652 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case IOMode:
657 default:
658 {
cristy18c6c272011-09-23 14:40:37 +0000659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000660 O_EXCL,S_MODE);
661 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
664 }
665 }
666 if (file == -1)
667 {
cristyf84a1932010-01-03 18:00:18 +0000668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000669 return(MagickFalse);
670 }
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
673 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000674 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000675 return(MagickTrue);
676}
677
678static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
679 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000680 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000681{
682 register MagickOffsetType
683 i;
684
685 ssize_t
686 count;
687
cristy08a88202010-03-04 19:18:05 +0000688 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000689#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000690 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000691 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristyf84a1932010-01-03 18:00:18 +0000693 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 return((MagickOffsetType) -1);
695 }
696#endif
697 count=0;
698 for (i=0; i < (MagickOffsetType) length; i+=count)
699 {
700#if !defined(MAGICKCORE_HAVE_PREAD)
701 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX));
703#else
704 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000705 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000706#endif
707 if (count > 0)
708 continue;
709 count=0;
710 if (errno != EINTR)
711 {
712 i=(-1);
713 break;
714 }
715 }
716#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000717 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000718#endif
719 return(i);
720}
721
722static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
723 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000724 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000725{
726 register MagickOffsetType
727 i;
728
729 ssize_t
730 count;
731
cristy08a88202010-03-04 19:18:05 +0000732 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000733#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000734 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000735 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000736 {
cristyf84a1932010-01-03 18:00:18 +0000737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 return((MagickOffsetType) -1);
739 }
740#endif
741 count=0;
742 for (i=0; i < (MagickOffsetType) length; i+=count)
743 {
744#if !defined(MAGICKCORE_HAVE_PWRITE)
745 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX));
747#else
748 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000749 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000750#endif
751 if (count > 0)
752 continue;
753 count=0;
754 if (errno != EINTR)
755 {
756 i=(-1);
757 break;
758 }
759 }
760#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000761 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000762#endif
763 return(i);
764}
765
cristy4c08aed2011-07-01 19:47:50 +0000766static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000767 CacheInfo *cache_info,ExceptionInfo *exception)
768{
769 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000770 count;
cristy3ed852e2009-09-05 21:47:34 +0000771
cristy4c08aed2011-07-01 19:47:50 +0000772 register MagickOffsetType
773 i;
cristye076a6e2010-08-15 19:59:43 +0000774
cristybb503372010-05-27 20:51:26 +0000775 size_t
cristy4c08aed2011-07-01 19:47:50 +0000776 length;
cristy3ed852e2009-09-05 21:47:34 +0000777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
780
781 /*
782 Clone pixel cache (both caches on disk).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000786 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000787 sizeof(*blob));
788 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000789 {
cristy4c08aed2011-07-01 19:47:50 +0000790 (void) ThrowMagickException(exception,GetMagickModule(),
791 ResourceLimitError,"MemoryAllocationFailed","`%s'",
792 cache_info->filename);
793 return(MagickFalse);
794 }
cristy3dedf062011-07-02 14:07:40 +0000795 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000796 {
797 blob=(unsigned char *) RelinquishMagickMemory(blob);
798 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
799 cache_info->cache_filename);
800 return(MagickFalse);
801 }
cristy3dedf062011-07-02 14:07:40 +0000802 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000803 {
804 (void) ClosePixelCacheOnDisk(cache_info);
805 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000806 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
807 clone_info->cache_filename);
808 return(MagickFalse);
809 }
cristy4c08aed2011-07-01 19:47:50 +0000810 count=0;
811 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
814 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
815 blob);
816 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000817 {
cristy4c08aed2011-07-01 19:47:50 +0000818 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
819 cache_info->cache_filename);
820 break;
cristy3ed852e2009-09-05 21:47:34 +0000821 }
cristy4c08aed2011-07-01 19:47:50 +0000822 length=(size_t) count;
823 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
824 if ((MagickSizeType) count != length)
825 {
826 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
827 clone_info->cache_filename);
828 break;
829 }
830 }
831 (void) ClosePixelCacheOnDisk(clone_info);
832 (void) ClosePixelCacheOnDisk(cache_info);
833 blob=(unsigned char *) RelinquishMagickMemory(blob);
834 if (i < (MagickOffsetType) cache_info->length)
835 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000836 return(MagickTrue);
837}
838
cristy4c08aed2011-07-01 19:47:50 +0000839static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000840 CacheInfo *cache_info,ExceptionInfo *exception)
841{
842 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000843 count;
cristy3ed852e2009-09-05 21:47:34 +0000844
cristy4c08aed2011-07-01 19:47:50 +0000845 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000846 {
cristy3ed852e2009-09-05 21:47:34 +0000847 /*
cristy4c08aed2011-07-01 19:47:50 +0000848 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000849 */
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->debug != MagickFalse)
851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
852 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
853 cache_info->length);
854 return(MagickTrue);
855 }
856 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
857 {
858 /*
859 Clone pixel cache (one cache on disk, one in memory).
860 */
861 if (cache_info->debug != MagickFalse)
862 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
863 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy4c08aed2011-07-01 19:47:50 +0000865 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000866 cache_info->cache_filename);
867 return(MagickFalse);
868 }
cristy4c08aed2011-07-01 19:47:50 +0000869 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
870 cache_info->length,(unsigned char *) clone_info->pixels);
871 (void) ClosePixelCacheOnDisk(cache_info);
872 if ((MagickSizeType) count != cache_info->length)
873 {
874 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
875 cache_info->cache_filename);
876 return(MagickFalse);
877 }
878 return(MagickTrue);
879 }
880 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
881 {
882 /*
883 Clone pixel cache (one cache on disk, one in memory).
884 */
885 if (clone_info->debug != MagickFalse)
886 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
887 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
888 {
889 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
890 clone_info->cache_filename);
891 return(MagickFalse);
892 }
893 count=WritePixelCacheRegion(clone_info,clone_info->offset,
894 clone_info->length,(unsigned char *) cache_info->pixels);
895 (void) ClosePixelCacheOnDisk(clone_info);
896 if ((MagickSizeType) count != clone_info->length)
897 {
898 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
899 clone_info->cache_filename);
900 return(MagickFalse);
901 }
902 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000903 }
904 /*
cristy4c08aed2011-07-01 19:47:50 +0000905 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000906 */
cristy4c08aed2011-07-01 19:47:50 +0000907 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000908}
909
cristy4c08aed2011-07-01 19:47:50 +0000910static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000911 CacheInfo *cache_info,ExceptionInfo *exception)
912{
cristy4c08aed2011-07-01 19:47:50 +0000913 MagickBooleanType
914 status;
cristy3ed852e2009-09-05 21:47:34 +0000915
cristy4c08aed2011-07-01 19:47:50 +0000916 MagickOffsetType
917 cache_offset,
918 clone_offset,
919 count;
920
921 register ssize_t
922 x;
923
924 size_t
cristy3ed852e2009-09-05 21:47:34 +0000925 length;
926
cristy4c08aed2011-07-01 19:47:50 +0000927 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000928 y;
929
cristy4c08aed2011-07-01 19:47:50 +0000930 unsigned char
931 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000932
cristy4c08aed2011-07-01 19:47:50 +0000933 /*
934 Clone pixel cache (unoptimized).
935 */
cristy3ed852e2009-09-05 21:47:34 +0000936 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000937 {
cristy4c08aed2011-07-01 19:47:50 +0000938 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
939 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
940 else
941 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
942 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
943 else
944 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
946 else
947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
948 }
cristyed231572011-07-14 02:18:59 +0000949 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
950 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000951 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000952 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000953 if (blob == (unsigned char *) NULL)
954 {
955 (void) ThrowMagickException(exception,GetMagickModule(),
956 ResourceLimitError,"MemoryAllocationFailed","`%s'",
957 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000958 return(MagickFalse);
959 }
cristy4c08aed2011-07-01 19:47:50 +0000960 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
961 cache_offset=0;
962 clone_offset=0;
963 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000964 {
cristy4c08aed2011-07-01 19:47:50 +0000965 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
cristy4c08aed2011-07-01 19:47:50 +0000967 blob=(unsigned char *) RelinquishMagickMemory(blob);
968 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
cristy4c08aed2011-07-01 19:47:50 +0000972 cache_offset=cache_info->offset;
973 }
974 if (clone_info->type == DiskCache)
975 {
cristy3dedf062011-07-02 14:07:40 +0000976 if ((cache_info->type == DiskCache) &&
977 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
978 {
979 (void) ClosePixelCacheOnDisk(clone_info);
980 *clone_info->cache_filename='\0';
981 }
982 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000983 {
cristy4c08aed2011-07-01 19:47:50 +0000984 if (cache_info->type == DiskCache)
985 (void) ClosePixelCacheOnDisk(cache_info);
986 blob=(unsigned char *) RelinquishMagickMemory(blob);
987 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
988 clone_info->cache_filename);
989 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000990 }
cristy4c08aed2011-07-01 19:47:50 +0000991 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000992 }
993 /*
cristy4c08aed2011-07-01 19:47:50 +0000994 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000995 */
cristy4c08aed2011-07-01 19:47:50 +0000996 status=MagickTrue;
997 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
cristy4c08aed2011-07-01 19:47:50 +0000999 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001000 {
cristy3ed852e2009-09-05 21:47:34 +00001001 /*
cristy4c08aed2011-07-01 19:47:50 +00001002 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001003 */
cristyed231572011-07-14 02:18:59 +00001004 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001005 if (cache_info->type != DiskCache)
1006 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1007 length);
cristy3ed852e2009-09-05 21:47:34 +00001008 else
1009 {
cristy4c08aed2011-07-01 19:47:50 +00001010 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1011 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001012 {
cristy4c08aed2011-07-01 19:47:50 +00001013 status=MagickFalse;
1014 break;
cristy3ed852e2009-09-05 21:47:34 +00001015 }
1016 }
cristy4c08aed2011-07-01 19:47:50 +00001017 cache_offset+=length;
1018 if ((y < (ssize_t) clone_info->rows) &&
1019 (x < (ssize_t) clone_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00001020 {
cristy4c08aed2011-07-01 19:47:50 +00001021 /*
1022 Write a set of pixel channels.
1023 */
cristyed231572011-07-14 02:18:59 +00001024 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001025 if (clone_info->type != DiskCache)
1026 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1027 blob,length);
1028 else
1029 {
cristy208b1002011-08-07 18:51:50 +00001030 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001031 if ((MagickSizeType) count != length)
1032 {
1033 status=MagickFalse;
1034 break;
1035 }
1036 }
1037 clone_offset+=length;
cristy3ed852e2009-09-05 21:47:34 +00001038 }
1039 }
cristyed231572011-07-14 02:18:59 +00001040 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001041 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1042 for ( ; x < (ssize_t) clone_info->columns; x++)
1043 {
1044 /*
1045 Set remaining columns with transparent pixel channels.
1046 */
1047 if (clone_info->type != DiskCache)
1048 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1049 length);
1050 else
1051 {
1052 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1053 if ((MagickSizeType) count != length)
1054 {
1055 status=MagickFalse;
1056 break;
1057 }
1058 }
1059 clone_offset+=length;
1060 }
1061 }
cristyed231572011-07-14 02:18:59 +00001062 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001063 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1064 for ( ; y < (ssize_t) clone_info->rows; y++)
1065 {
1066 /*
1067 Set remaining rows with transparent pixels.
1068 */
1069 for (x=0; x < (ssize_t) clone_info->columns; x++)
1070 {
1071 if (clone_info->type != DiskCache)
1072 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1073 length);
1074 else
1075 {
1076 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1077 if ((MagickSizeType) count != length)
1078 {
1079 status=MagickFalse;
1080 break;
1081 }
1082 }
1083 clone_offset+=length;
1084 }
1085 }
1086 if ((cache_info->metacontent_extent != 0) &&
1087 (clone_info->metacontent_extent != 0))
1088 {
1089 /*
1090 Clone metacontent.
1091 */
1092 for (y=0; y < (ssize_t) cache_info->rows; y++)
1093 {
1094 for (x=0; x < (ssize_t) cache_info->columns; x++)
1095 {
1096 /*
1097 Read a set of metacontent.
1098 */
1099 length=cache_info->metacontent_extent;
1100 if (cache_info->type != DiskCache)
1101 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1102 cache_offset,length);
1103 else
1104 {
1105 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1106 if ((MagickSizeType) count != length)
1107 {
1108 status=MagickFalse;
1109 break;
1110 }
1111 }
1112 cache_offset+=length;
1113 if ((y < (ssize_t) clone_info->rows) &&
1114 (x < (ssize_t) clone_info->columns))
1115 {
1116 /*
1117 Write a set of metacontent.
1118 */
1119 length=clone_info->metacontent_extent;
1120 if (clone_info->type != DiskCache)
1121 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1122 blob,length);
1123 else
1124 {
1125 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1126 blob);
1127 if ((MagickSizeType) count != length)
1128 {
1129 status=MagickFalse;
1130 break;
1131 }
1132 }
1133 clone_offset+=length;
1134 }
1135 }
1136 length=clone_info->metacontent_extent;
1137 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1138 for ( ; x < (ssize_t) clone_info->columns; x++)
1139 {
1140 /*
1141 Set remaining columns with metacontent.
1142 */
1143 if (clone_info->type != DiskCache)
1144 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1145 blob,length);
1146 else
1147 {
cristy208b1002011-08-07 18:51:50 +00001148 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001149 if ((MagickSizeType) count != length)
1150 {
1151 status=MagickFalse;
1152 break;
1153 }
1154 }
1155 clone_offset+=length;
1156 }
1157 }
1158 length=clone_info->metacontent_extent;
1159 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1160 for ( ; y < (ssize_t) clone_info->rows; y++)
1161 {
1162 /*
1163 Set remaining rows with metacontent.
1164 */
1165 for (x=0; x < (ssize_t) clone_info->columns; x++)
1166 {
1167 if (clone_info->type != DiskCache)
1168 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1169 blob,length);
1170 else
1171 {
1172 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1173 if ((MagickSizeType) count != length)
1174 {
1175 status=MagickFalse;
1176 break;
1177 }
1178 }
1179 clone_offset+=length;
1180 }
1181 }
1182 }
1183 if (clone_info->type == DiskCache)
1184 (void) ClosePixelCacheOnDisk(clone_info);
1185 if (cache_info->type == DiskCache)
1186 (void) ClosePixelCacheOnDisk(cache_info);
1187 blob=(unsigned char *) RelinquishMagickMemory(blob);
1188 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001189}
1190
1191static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1192 CacheInfo *cache_info,ExceptionInfo *exception)
1193{
cristy5a7fbfb2010-11-06 16:10:59 +00001194 if (cache_info->type == PingCache)
1195 return(MagickTrue);
cristy4c08aed2011-07-01 19:47:50 +00001196 if ((cache_info->columns == clone_info->columns) &&
1197 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001198 (cache_info->number_channels == clone_info->number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00001199 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1200 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1201 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001202}
1203
1204/*
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206% %
1207% %
1208% %
1209+ C l o n e P i x e l C a c h e M e t h o d s %
1210% %
1211% %
1212% %
1213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214%
1215% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1216% another.
1217%
1218% The format of the ClonePixelCacheMethods() method is:
1219%
1220% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1221%
1222% A description of each parameter follows:
1223%
1224% o clone: Specifies a pointer to a Cache structure.
1225%
1226% o cache: the pixel cache.
1227%
1228*/
cristya6577ff2011-09-02 19:54:26 +00001229MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001230{
1231 CacheInfo
1232 *cache_info,
1233 *source_info;
1234
1235 assert(clone != (Cache) NULL);
1236 source_info=(CacheInfo *) clone;
1237 assert(source_info->signature == MagickSignature);
1238 if (source_info->debug != MagickFalse)
1239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1240 source_info->filename);
1241 assert(cache != (Cache) NULL);
1242 cache_info=(CacheInfo *) cache;
1243 assert(cache_info->signature == MagickSignature);
1244 source_info->methods=cache_info->methods;
1245}
1246
1247/*
1248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249% %
1250% %
1251% %
1252+ D e s t r o y I m a g e P i x e l C a c h e %
1253% %
1254% %
1255% %
1256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257%
1258% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1259%
1260% The format of the DestroyImagePixelCache() method is:
1261%
1262% void DestroyImagePixelCache(Image *image)
1263%
1264% A description of each parameter follows:
1265%
1266% o image: the image.
1267%
1268*/
1269static void DestroyImagePixelCache(Image *image)
1270{
1271 assert(image != (Image *) NULL);
1272 assert(image->signature == MagickSignature);
1273 if (image->debug != MagickFalse)
1274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1275 if (image->cache == (void *) NULL)
1276 return;
1277 image->cache=DestroyPixelCache(image->cache);
1278}
1279
1280/*
1281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282% %
1283% %
1284% %
1285+ D e s t r o y I m a g e P i x e l s %
1286% %
1287% %
1288% %
1289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290%
1291% DestroyImagePixels() deallocates memory associated with the pixel cache.
1292%
1293% The format of the DestroyImagePixels() method is:
1294%
1295% void DestroyImagePixels(Image *image)
1296%
1297% A description of each parameter follows:
1298%
1299% o image: the image.
1300%
1301*/
1302MagickExport void DestroyImagePixels(Image *image)
1303{
1304 CacheInfo
1305 *cache_info;
1306
1307 assert(image != (const Image *) NULL);
1308 assert(image->signature == MagickSignature);
1309 if (image->debug != MagickFalse)
1310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1311 assert(image->cache != (Cache) NULL);
1312 cache_info=(CacheInfo *) image->cache;
1313 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001314 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1315 {
1316 cache_info->methods.destroy_pixel_handler(image);
1317 return;
1318 }
cristy2036f5c2010-09-19 21:18:17 +00001319 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001320}
1321
1322/*
1323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324% %
1325% %
1326% %
1327+ D e s t r o y P i x e l C a c h e %
1328% %
1329% %
1330% %
1331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332%
1333% DestroyPixelCache() deallocates memory associated with the pixel cache.
1334%
1335% The format of the DestroyPixelCache() method is:
1336%
1337% Cache DestroyPixelCache(Cache cache)
1338%
1339% A description of each parameter follows:
1340%
1341% o cache: the pixel cache.
1342%
1343*/
1344
1345static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1346{
1347 switch (cache_info->type)
1348 {
1349 case MemoryCache:
1350 {
1351 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001352 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001353 cache_info->pixels);
1354 else
cristy4c08aed2011-07-01 19:47:50 +00001355 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001356 (size_t) cache_info->length);
1357 RelinquishMagickResource(MemoryResource,cache_info->length);
1358 break;
1359 }
1360 case MapCache:
1361 {
cristy4c08aed2011-07-01 19:47:50 +00001362 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001363 cache_info->length);
1364 RelinquishMagickResource(MapResource,cache_info->length);
1365 }
1366 case DiskCache:
1367 {
1368 if (cache_info->file != -1)
1369 (void) ClosePixelCacheOnDisk(cache_info);
1370 RelinquishMagickResource(DiskResource,cache_info->length);
1371 break;
1372 }
1373 default:
1374 break;
1375 }
1376 cache_info->type=UndefinedCache;
1377 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001378 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001379}
1380
cristya6577ff2011-09-02 19:54:26 +00001381MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001382{
1383 CacheInfo
1384 *cache_info;
1385
cristy3ed852e2009-09-05 21:47:34 +00001386 assert(cache != (Cache) NULL);
1387 cache_info=(CacheInfo *) cache;
1388 assert(cache_info->signature == MagickSignature);
1389 if (cache_info->debug != MagickFalse)
1390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1391 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001392 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001393 cache_info->reference_count--;
1394 if (cache_info->reference_count != 0)
1395 {
cristyf84a1932010-01-03 18:00:18 +00001396 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001397 return((Cache) NULL);
1398 }
cristyf84a1932010-01-03 18:00:18 +00001399 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001400 if (cache_resources != (SplayTreeInfo *) NULL)
1401 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001402 if (cache_info->debug != MagickFalse)
1403 {
1404 char
1405 message[MaxTextExtent];
1406
cristyb51dff52011-05-19 16:55:47 +00001407 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001408 cache_info->filename);
1409 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1410 }
cristyc2e1bdd2009-09-10 23:43:34 +00001411 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1412 (cache_info->type != DiskCache)))
1413 RelinquishPixelCachePixels(cache_info);
1414 else
1415 {
1416 RelinquishPixelCachePixels(cache_info);
1417 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1418 }
cristy3ed852e2009-09-05 21:47:34 +00001419 *cache_info->cache_filename='\0';
1420 if (cache_info->nexus_info != (NexusInfo **) NULL)
1421 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1422 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001423 if (cache_info->random_info != (RandomInfo *) NULL)
1424 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001425 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1426 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1427 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1428 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001429 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001430 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001431 cache=(Cache) NULL;
1432 return(cache);
1433}
1434
1435/*
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437% %
1438% %
1439% %
1440+ D e s t r o y P i x e l C a c h e N e x u s %
1441% %
1442% %
1443% %
1444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445%
1446% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1447%
1448% The format of the DestroyPixelCacheNexus() method is:
1449%
1450% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001451% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001452%
1453% A description of each parameter follows:
1454%
1455% o nexus_info: the nexus to destroy.
1456%
1457% o number_threads: the number of nexus threads.
1458%
1459*/
1460
1461static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1462{
1463 if (nexus_info->mapped == MagickFalse)
1464 (void) RelinquishMagickMemory(nexus_info->cache);
1465 else
1466 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001467 nexus_info->cache=(Quantum *) NULL;
1468 nexus_info->pixels=(Quantum *) NULL;
1469 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001470 nexus_info->length=0;
1471 nexus_info->mapped=MagickFalse;
1472}
1473
cristya6577ff2011-09-02 19:54:26 +00001474MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001475 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001476{
cristybb503372010-05-27 20:51:26 +00001477 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001478 i;
1479
1480 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001481 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001482 {
cristy4c08aed2011-07-01 19:47:50 +00001483 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001484 RelinquishCacheNexusPixels(nexus_info[i]);
1485 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001486 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001487 }
cristyb41ee102010-10-04 16:46:15 +00001488 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001489 return(nexus_info);
1490}
1491
1492/*
1493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494% %
1495% %
1496% %
cristy4c08aed2011-07-01 19:47:50 +00001497% 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 +00001498% %
1499% %
1500% %
1501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502%
cristy4c08aed2011-07-01 19:47:50 +00001503% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1504% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1505% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001506%
cristy4c08aed2011-07-01 19:47:50 +00001507% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001508%
cristy4c08aed2011-07-01 19:47:50 +00001509% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001510%
1511% A description of each parameter follows:
1512%
1513% o image: the image.
1514%
1515*/
cristy4c08aed2011-07-01 19:47:50 +00001516MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001517{
1518 CacheInfo
1519 *cache_info;
1520
cristy5c9e6f22010-09-17 17:31:01 +00001521 const int
1522 id = GetOpenMPThreadId();
1523
cristy4c08aed2011-07-01 19:47:50 +00001524 void
1525 *metacontent;
1526
cristye7cc7cf2010-09-21 13:26:47 +00001527 assert(image != (const Image *) NULL);
1528 assert(image->signature == MagickSignature);
1529 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001530 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001531 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001532 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1533 (GetAuthenticMetacontentFromHandler) NULL)
1534 {
1535 metacontent=cache_info->methods.
1536 get_authentic_metacontent_from_handler(image);
1537 return(metacontent);
1538 }
cristy6ebe97c2010-07-03 01:17:28 +00001539 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001540 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1541 cache_info->nexus_info[id]);
1542 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001543}
1544
1545/*
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547% %
1548% %
1549% %
cristy4c08aed2011-07-01 19:47:50 +00001550+ 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 +00001551% %
1552% %
1553% %
1554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555%
cristy4c08aed2011-07-01 19:47:50 +00001556% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1557% with the last call to QueueAuthenticPixelsCache() or
1558% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001559%
cristy4c08aed2011-07-01 19:47:50 +00001560% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001561%
cristy4c08aed2011-07-01 19:47:50 +00001562% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001563%
1564% A description of each parameter follows:
1565%
1566% o image: the image.
1567%
1568*/
cristy4c08aed2011-07-01 19:47:50 +00001569static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001570{
1571 CacheInfo
1572 *cache_info;
1573
cristy2036f5c2010-09-19 21:18:17 +00001574 const int
1575 id = GetOpenMPThreadId();
1576
cristy4c08aed2011-07-01 19:47:50 +00001577 void
1578 *metacontent;
1579
cristy3ed852e2009-09-05 21:47:34 +00001580 assert(image != (const Image *) NULL);
1581 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001582 assert(image->cache != (Cache) NULL);
1583 cache_info=(CacheInfo *) image->cache;
1584 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001585 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001586 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1587 cache_info->nexus_info[id]);
1588 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001589}
1590
1591/*
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593% %
1594% %
1595% %
1596+ 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 %
1597% %
1598% %
1599% %
1600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601%
1602% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1603% disk pixel cache as defined by the geometry parameters. A pointer to the
1604% pixels is returned if the pixels are transferred, otherwise a NULL is
1605% returned.
1606%
1607% The format of the GetAuthenticPixelCacheNexus() method is:
1608%
cristy4c08aed2011-07-01 19:47:50 +00001609% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001610% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001611% NexusInfo *nexus_info,ExceptionInfo *exception)
1612%
1613% A description of each parameter follows:
1614%
1615% o image: the image.
1616%
1617% o x,y,columns,rows: These values define the perimeter of a region of
1618% pixels.
1619%
1620% o nexus_info: the cache nexus to return.
1621%
1622% o exception: return any errors or warnings in this structure.
1623%
1624*/
1625
cristy4c08aed2011-07-01 19:47:50 +00001626static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001627 NexusInfo *nexus_info)
1628{
cristy4c08aed2011-07-01 19:47:50 +00001629 MagickBooleanType
1630 status;
1631
cristy3ed852e2009-09-05 21:47:34 +00001632 MagickOffsetType
1633 offset;
1634
cristy73724512010-04-12 14:43:14 +00001635 if (cache_info->type == PingCache)
1636 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001637 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1638 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001639 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001640 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001641 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001642}
1643
cristya6577ff2011-09-02 19:54:26 +00001644MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001645 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001646 NexusInfo *nexus_info,ExceptionInfo *exception)
1647{
1648 CacheInfo
1649 *cache_info;
1650
cristy4c08aed2011-07-01 19:47:50 +00001651 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001652 *q;
cristy3ed852e2009-09-05 21:47:34 +00001653
1654 /*
1655 Transfer pixels from the cache.
1656 */
1657 assert(image != (Image *) NULL);
1658 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001659 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001660 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001661 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001662 cache_info=(CacheInfo *) image->cache;
1663 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001664 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001665 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001666 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001667 return((Quantum *) NULL);
1668 if (cache_info->metacontent_extent != 0)
1669 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1670 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001671 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001672}
1673
1674/*
1675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676% %
1677% %
1678% %
1679+ 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 %
1680% %
1681% %
1682% %
1683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684%
1685% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1686% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1687%
1688% The format of the GetAuthenticPixelsFromCache() method is:
1689%
cristy4c08aed2011-07-01 19:47:50 +00001690% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001691%
1692% A description of each parameter follows:
1693%
1694% o image: the image.
1695%
1696*/
cristy4c08aed2011-07-01 19:47:50 +00001697static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001698{
1699 CacheInfo
1700 *cache_info;
1701
cristy5c9e6f22010-09-17 17:31:01 +00001702 const int
1703 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001704
cristye7cc7cf2010-09-21 13:26:47 +00001705 assert(image != (const Image *) NULL);
1706 assert(image->signature == MagickSignature);
1707 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001708 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001709 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001710 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001711 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001712}
1713
1714/*
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716% %
1717% %
1718% %
1719% G e t A u t h e n t i c P i x e l Q u e u e %
1720% %
1721% %
1722% %
1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724%
cristy4c08aed2011-07-01 19:47:50 +00001725% GetAuthenticPixelQueue() returns the authentic pixels associated
1726% corresponding with the last call to QueueAuthenticPixels() or
1727% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001728%
1729% The format of the GetAuthenticPixelQueue() method is:
1730%
cristy4c08aed2011-07-01 19:47:50 +00001731% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001732%
1733% A description of each parameter follows:
1734%
1735% o image: the image.
1736%
1737*/
cristy4c08aed2011-07-01 19:47:50 +00001738MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001739{
1740 CacheInfo
1741 *cache_info;
1742
cristy2036f5c2010-09-19 21:18:17 +00001743 const int
1744 id = GetOpenMPThreadId();
1745
cristy3ed852e2009-09-05 21:47:34 +00001746 assert(image != (const Image *) NULL);
1747 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001748 assert(image->cache != (Cache) NULL);
1749 cache_info=(CacheInfo *) image->cache;
1750 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001751 if (cache_info->methods.get_authentic_pixels_from_handler !=
1752 (GetAuthenticPixelsFromHandler) NULL)
1753 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001754 assert(id < (int) cache_info->number_threads);
1755 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001756}
1757
1758/*
1759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760% %
1761% %
1762% %
1763% G e t A u t h e n t i c P i x e l s %
1764% %
1765% %
cristy4c08aed2011-07-01 19:47:50 +00001766% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001767%
1768% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001769% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001770% representing the region is returned, otherwise NULL is returned.
1771%
1772% The returned pointer may point to a temporary working copy of the pixels
1773% or it may point to the original pixels in memory. Performance is maximized
1774% if the selected region is part of one row, or one or more full rows, since
1775% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001776% if the image is in memory, or in a memory-mapped file. The returned pointer
1777% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001778%
1779% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001780% Quantum. If the image has corresponding metacontent,call
1781% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1782% meta-content corresponding to the region. Once the Quantum array has
1783% been updated, the changes must be saved back to the underlying image using
1784% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001785%
1786% The format of the GetAuthenticPixels() method is:
1787%
cristy4c08aed2011-07-01 19:47:50 +00001788% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001789% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001790% ExceptionInfo *exception)
1791%
1792% A description of each parameter follows:
1793%
1794% o image: the image.
1795%
1796% o x,y,columns,rows: These values define the perimeter of a region of
1797% pixels.
1798%
1799% o exception: return any errors or warnings in this structure.
1800%
1801*/
cristy4c08aed2011-07-01 19:47:50 +00001802MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001803 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001804 ExceptionInfo *exception)
1805{
1806 CacheInfo
1807 *cache_info;
1808
cristy2036f5c2010-09-19 21:18:17 +00001809 const int
1810 id = GetOpenMPThreadId();
1811
cristy4c08aed2011-07-01 19:47:50 +00001812 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001813 *q;
cristy4c08aed2011-07-01 19:47:50 +00001814
cristy3ed852e2009-09-05 21:47:34 +00001815 assert(image != (Image *) NULL);
1816 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001817 assert(image->cache != (Cache) NULL);
1818 cache_info=(CacheInfo *) image->cache;
1819 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001820 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001821 (GetAuthenticPixelsHandler) NULL)
1822 {
cristyacd2ed22011-08-30 01:44:23 +00001823 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1824 exception);
1825 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001826 }
cristy2036f5c2010-09-19 21:18:17 +00001827 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001828 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001829 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001830 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001831}
1832
1833/*
1834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835% %
1836% %
1837% %
1838+ G e t A u t h e n t i c P i x e l s C a c h e %
1839% %
1840% %
1841% %
1842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1843%
1844% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1845% as defined by the geometry parameters. A pointer to the pixels is returned
1846% if the pixels are transferred, otherwise a NULL is returned.
1847%
1848% The format of the GetAuthenticPixelsCache() method is:
1849%
cristy4c08aed2011-07-01 19:47:50 +00001850% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001851% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001852% ExceptionInfo *exception)
1853%
1854% A description of each parameter follows:
1855%
1856% o image: the image.
1857%
1858% o x,y,columns,rows: These values define the perimeter of a region of
1859% pixels.
1860%
1861% o exception: return any errors or warnings in this structure.
1862%
1863*/
cristy4c08aed2011-07-01 19:47:50 +00001864static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001865 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001866 ExceptionInfo *exception)
1867{
1868 CacheInfo
1869 *cache_info;
1870
cristy5c9e6f22010-09-17 17:31:01 +00001871 const int
1872 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001873
cristy4c08aed2011-07-01 19:47:50 +00001874 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001875 *q;
cristy4c08aed2011-07-01 19:47:50 +00001876
cristye7cc7cf2010-09-21 13:26:47 +00001877 assert(image != (const Image *) NULL);
1878 assert(image->signature == MagickSignature);
1879 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001880 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001881 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001882 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001883 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001884 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001885 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001886 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001887 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001888}
1889
1890/*
1891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892% %
1893% %
1894% %
1895+ G e t I m a g e E x t e n t %
1896% %
1897% %
1898% %
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900%
cristy4c08aed2011-07-01 19:47:50 +00001901% GetImageExtent() returns the extent of the pixels associated corresponding
1902% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001903%
1904% The format of the GetImageExtent() method is:
1905%
1906% MagickSizeType GetImageExtent(const Image *image)
1907%
1908% A description of each parameter follows:
1909%
1910% o image: the image.
1911%
1912*/
1913MagickExport MagickSizeType GetImageExtent(const Image *image)
1914{
1915 CacheInfo
1916 *cache_info;
1917
cristy5c9e6f22010-09-17 17:31:01 +00001918 const int
1919 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001920
cristy3ed852e2009-09-05 21:47:34 +00001921 assert(image != (Image *) NULL);
1922 assert(image->signature == MagickSignature);
1923 if (image->debug != MagickFalse)
1924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1925 assert(image->cache != (Cache) NULL);
1926 cache_info=(CacheInfo *) image->cache;
1927 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001928 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001929 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001930}
1931
1932/*
1933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1934% %
1935% %
1936% %
1937+ G e t I m a g e P i x e l C a c h e %
1938% %
1939% %
1940% %
1941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942%
1943% GetImagePixelCache() ensures that there is only a single reference to the
1944% pixel cache to be modified, updating the provided cache pointer to point to
1945% a clone of the original pixel cache if necessary.
1946%
1947% The format of the GetImagePixelCache method is:
1948%
1949% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1950% ExceptionInfo *exception)
1951%
1952% A description of each parameter follows:
1953%
1954% o image: the image.
1955%
1956% o clone: any value other than MagickFalse clones the cache pixels.
1957%
1958% o exception: return any errors or warnings in this structure.
1959%
1960*/
cristyaf894d72011-08-06 23:03:10 +00001961
cristy3ed852e2009-09-05 21:47:34 +00001962static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1963{
1964 CacheInfo
1965 *cache_info;
1966
1967 /*
1968 Does the image match the pixel cache morphology?
1969 */
1970 cache_info=(CacheInfo *) image->cache;
1971 if ((image->storage_class != cache_info->storage_class) ||
1972 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001973 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00001974 (image->columns != cache_info->columns) ||
1975 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001976 (image->number_channels != cache_info->number_channels) ||
cristy4c08aed2011-07-01 19:47:50 +00001977 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001978 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1979 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1980 return(MagickFalse);
1981 return(MagickTrue);
1982}
1983
cristycd01fae2011-08-06 23:52:42 +00001984static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1985 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001986{
1987 CacheInfo
1988 *cache_info;
1989
cristy3ed852e2009-09-05 21:47:34 +00001990 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001991 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001992 status;
1993
cristy50a10922010-02-15 18:35:25 +00001994 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001995 cpu_throttle = 0,
1996 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001997 time_limit = 0;
1998
cristy1ea34962010-07-01 19:49:21 +00001999 static time_t
cristy208b1002011-08-07 18:51:50 +00002000 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002001
cristyc4f9f132010-03-04 18:50:01 +00002002 status=MagickTrue;
2003 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002004 if (cpu_throttle == 0)
2005 {
2006 char
2007 *limit;
2008
2009 /*
2010 Set CPU throttle in milleseconds.
2011 */
2012 cpu_throttle=MagickResourceInfinity;
2013 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2014 if (limit == (char *) NULL)
2015 limit=GetPolicyValue("throttle");
2016 if (limit != (char *) NULL)
2017 {
2018 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2019 limit=DestroyString(limit);
2020 }
2021 }
2022 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2023 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002024 if (time_limit == 0)
2025 {
cristy6ebe97c2010-07-03 01:17:28 +00002026 /*
2027 Set the exire time in seconds.
2028 */
cristy1ea34962010-07-01 19:49:21 +00002029 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002030 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002031 }
2032 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002033 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002034 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002035 assert(image->cache != (Cache) NULL);
2036 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002037 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002038 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002039 {
cristyceb55ee2010-11-06 16:05:49 +00002040 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002041 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002042 {
cristyceb55ee2010-11-06 16:05:49 +00002043 Image
2044 clone_image;
2045
2046 CacheInfo
2047 *clone_info;
2048
2049 /*
2050 Clone pixel cache.
2051 */
2052 clone_image=(*image);
2053 clone_image.semaphore=AllocateSemaphoreInfo();
2054 clone_image.reference_count=1;
2055 clone_image.cache=ClonePixelCache(cache_info);
2056 clone_info=(CacheInfo *) clone_image.cache;
2057 status=OpenPixelCache(&clone_image,IOMode,exception);
2058 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002059 {
cristy5a7fbfb2010-11-06 16:10:59 +00002060 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002061 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002062 if (status != MagickFalse)
2063 {
cristy979bf772011-08-08 00:04:15 +00002064 if (cache_info->mode == ReadMode)
2065 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002066 destroy=MagickTrue;
2067 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002068 }
2069 }
cristyceb55ee2010-11-06 16:05:49 +00002070 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002071 }
cristyceb55ee2010-11-06 16:05:49 +00002072 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002073 }
cristy4320e0e2009-09-10 15:00:08 +00002074 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002075 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002076 if (status != MagickFalse)
2077 {
2078 /*
2079 Ensure the image matches the pixel cache morphology.
2080 */
2081 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002082 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002083 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2084 status=OpenPixelCache(image,IOMode,exception);
2085 }
cristyf84a1932010-01-03 18:00:18 +00002086 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002087 if (status == MagickFalse)
2088 return((Cache) NULL);
2089 return(image->cache);
2090}
2091
2092/*
2093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094% %
2095% %
2096% %
2097% G e t O n e A u t h e n t i c P i x e l %
2098% %
2099% %
2100% %
2101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102%
2103% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2104% location. The image background color is returned if an error occurs.
2105%
2106% The format of the GetOneAuthenticPixel() method is:
2107%
cristybb503372010-05-27 20:51:26 +00002108% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002109% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002110%
2111% A description of each parameter follows:
2112%
2113% o image: the image.
2114%
2115% o x,y: These values define the location of the pixel to return.
2116%
2117% o pixel: return a pixel at the specified (x,y) location.
2118%
2119% o exception: return any errors or warnings in this structure.
2120%
2121*/
cristyacbbb7c2010-06-30 18:56:48 +00002122MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002123 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002124{
2125 CacheInfo
2126 *cache_info;
2127
cristy4c08aed2011-07-01 19:47:50 +00002128 register Quantum
2129 *q;
cristy2036f5c2010-09-19 21:18:17 +00002130
cristy2ed42f62011-10-02 19:49:57 +00002131 register ssize_t
2132 i;
2133
cristy3ed852e2009-09-05 21:47:34 +00002134 assert(image != (Image *) NULL);
2135 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002136 assert(image->cache != (Cache) NULL);
2137 cache_info=(CacheInfo *) image->cache;
2138 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002139 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002140 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2141 (GetOneAuthenticPixelFromHandler) NULL)
2142 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2143 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002144 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2145 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002146 {
2147 pixel[RedPixelChannel]=image->background_color.red;
2148 pixel[GreenPixelChannel]=image->background_color.green;
2149 pixel[BluePixelChannel]=image->background_color.blue;
2150 pixel[AlphaPixelChannel]=image->background_color.alpha;
2151 return(MagickFalse);
2152 }
2153 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2154 {
2155 PixelChannel
2156 channel;
2157
2158 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2159 pixel[channel]=q[i];
2160 }
cristy2036f5c2010-09-19 21:18:17 +00002161 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002162}
2163
2164/*
2165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166% %
2167% %
2168% %
2169+ 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 %
2170% %
2171% %
2172% %
2173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2174%
2175% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2176% location. The image background color is returned if an error occurs.
2177%
2178% The format of the GetOneAuthenticPixelFromCache() method is:
2179%
2180% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002181% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002182% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002183%
2184% A description of each parameter follows:
2185%
2186% o image: the image.
2187%
2188% o x,y: These values define the location of the pixel to return.
2189%
2190% o pixel: return a pixel at the specified (x,y) location.
2191%
2192% o exception: return any errors or warnings in this structure.
2193%
2194*/
2195static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002196 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002197{
cristy098f78c2010-09-23 17:28:44 +00002198 CacheInfo
2199 *cache_info;
2200
2201 const int
2202 id = GetOpenMPThreadId();
2203
cristy4c08aed2011-07-01 19:47:50 +00002204 register Quantum
2205 *q;
cristy3ed852e2009-09-05 21:47:34 +00002206
cristy2ed42f62011-10-02 19:49:57 +00002207 register ssize_t
2208 i;
2209
cristy0158a4b2010-09-20 13:59:45 +00002210 assert(image != (const Image *) NULL);
2211 assert(image->signature == MagickSignature);
2212 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002213 cache_info=(CacheInfo *) image->cache;
2214 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002215 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002216 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002217 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2218 exception);
2219 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002220 {
2221 pixel[RedPixelChannel]=image->background_color.red;
2222 pixel[GreenPixelChannel]=image->background_color.green;
2223 pixel[BluePixelChannel]=image->background_color.blue;
2224 pixel[AlphaPixelChannel]=image->background_color.alpha;
2225 return(MagickFalse);
2226 }
2227 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2228 {
2229 PixelChannel
2230 channel;
2231
2232 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2233 pixel[channel]=q[i];
2234 }
cristy3ed852e2009-09-05 21:47:34 +00002235 return(MagickTrue);
2236}
2237
2238/*
2239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240% %
2241% %
2242% %
2243% G e t O n e V i r t u a l M a g i c k P i x e l %
2244% %
2245% %
2246% %
2247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2248%
2249% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2250% location. The image background color is returned if an error occurs. If
2251% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2252%
2253% The format of the GetOneVirtualMagickPixel() method is:
2254%
2255% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002256% const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002257% ExceptionInfo exception)
2258%
2259% A description of each parameter follows:
2260%
2261% o image: the image.
2262%
2263% o x,y: these values define the location of the pixel to return.
2264%
2265% o pixel: return a pixel at the specified (x,y) location.
2266%
2267% o exception: return any errors or warnings in this structure.
2268%
2269*/
2270MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002271 const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristyacbbb7c2010-06-30 18:56:48 +00002272 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002273{
2274 CacheInfo
2275 *cache_info;
2276
cristy0158a4b2010-09-20 13:59:45 +00002277 const int
2278 id = GetOpenMPThreadId();
2279
cristy4c08aed2011-07-01 19:47:50 +00002280 register const Quantum
cristyacd2ed22011-08-30 01:44:23 +00002281 *p;
cristy3ed852e2009-09-05 21:47:34 +00002282
2283 assert(image != (const Image *) NULL);
2284 assert(image->signature == MagickSignature);
2285 assert(image->cache != (Cache) NULL);
2286 cache_info=(CacheInfo *) image->cache;
2287 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002288 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00002289 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002290 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002291 GetPixelInfo(image,pixel);
cristyacd2ed22011-08-30 01:44:23 +00002292 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002293 return(MagickFalse);
cristyacd2ed22011-08-30 01:44:23 +00002294 SetPixelInfo(image,p,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002295 return(MagickTrue);
2296}
2297
2298/*
2299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2300% %
2301% %
2302% %
2303% G e t O n e V i r t u a l M e t h o d P i x e l %
2304% %
2305% %
2306% %
2307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2308%
2309% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2310% location as defined by specified pixel method. The image background color
2311% is returned if an error occurs. If you plan to modify the pixel, use
2312% GetOneAuthenticPixel() instead.
2313%
2314% The format of the GetOneVirtualMethodPixel() method is:
2315%
2316% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002317% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002318% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002319%
2320% A description of each parameter follows:
2321%
2322% o image: the image.
2323%
2324% o virtual_pixel_method: the virtual pixel method.
2325%
2326% o x,y: These values define the location of the pixel to return.
2327%
2328% o pixel: return a pixel at the specified (x,y) location.
2329%
2330% o exception: return any errors or warnings in this structure.
2331%
2332*/
2333MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002334 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002335 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002336{
cristy3ed852e2009-09-05 21:47:34 +00002337 CacheInfo
2338 *cache_info;
2339
cristy0158a4b2010-09-20 13:59:45 +00002340 const int
2341 id = GetOpenMPThreadId();
2342
cristy4c08aed2011-07-01 19:47:50 +00002343 const Quantum
2344 *p;
cristy2036f5c2010-09-19 21:18:17 +00002345
cristy2ed42f62011-10-02 19:49:57 +00002346 register ssize_t
2347 i;
2348
cristy3ed852e2009-09-05 21:47:34 +00002349 assert(image != (const Image *) NULL);
2350 assert(image->signature == MagickSignature);
2351 assert(image->cache != (Cache) NULL);
2352 cache_info=(CacheInfo *) image->cache;
2353 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002354 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002355 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2356 (GetOneVirtualPixelFromHandler) NULL)
2357 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2358 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002359 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002361 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002362 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002363 {
2364 pixel[RedPixelChannel]=image->background_color.red;
2365 pixel[GreenPixelChannel]=image->background_color.green;
2366 pixel[BluePixelChannel]=image->background_color.blue;
2367 pixel[AlphaPixelChannel]=image->background_color.alpha;
2368 return(MagickFalse);
2369 }
2370 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2371 {
2372 PixelChannel
2373 channel;
2374
2375 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2376 pixel[channel]=p[i];
2377 }
cristy2036f5c2010-09-19 21:18:17 +00002378 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002379}
2380
2381/*
2382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2383% %
2384% %
2385% %
2386% G e t O n e V i r t u a l P i x e l %
2387% %
2388% %
2389% %
2390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391%
2392% GetOneVirtualPixel() returns a single virtual pixel at the specified
2393% (x,y) location. The image background color is returned if an error occurs.
2394% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2395%
2396% The format of the GetOneVirtualPixel() method is:
2397%
cristybb503372010-05-27 20:51:26 +00002398% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002399% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002400%
2401% A description of each parameter follows:
2402%
2403% o image: the image.
2404%
2405% o x,y: These values define the location of the pixel to return.
2406%
2407% o pixel: return a pixel at the specified (x,y) location.
2408%
2409% o exception: return any errors or warnings in this structure.
2410%
2411*/
2412MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002413 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002414{
cristy3ed852e2009-09-05 21:47:34 +00002415 CacheInfo
2416 *cache_info;
2417
cristy0158a4b2010-09-20 13:59:45 +00002418 const int
2419 id = GetOpenMPThreadId();
2420
cristy4c08aed2011-07-01 19:47:50 +00002421 const Quantum
2422 *p;
cristy2036f5c2010-09-19 21:18:17 +00002423
cristy2ed42f62011-10-02 19:49:57 +00002424 register ssize_t
2425 i;
2426
cristy3ed852e2009-09-05 21:47:34 +00002427 assert(image != (const Image *) NULL);
2428 assert(image->signature == MagickSignature);
2429 assert(image->cache != (Cache) NULL);
2430 cache_info=(CacheInfo *) image->cache;
2431 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002432 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002433 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2434 (GetOneVirtualPixelFromHandler) NULL)
2435 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2436 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002437 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002438 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002439 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002440 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002441 {
2442 pixel[RedPixelChannel]=image->background_color.red;
2443 pixel[GreenPixelChannel]=image->background_color.green;
2444 pixel[BluePixelChannel]=image->background_color.blue;
2445 pixel[AlphaPixelChannel]=image->background_color.alpha;
2446 return(MagickFalse);
2447 }
2448 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2449 {
2450 PixelChannel
2451 channel;
2452
2453 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2454 pixel[channel]=p[i];
2455 }
cristy2036f5c2010-09-19 21:18:17 +00002456 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002457}
2458
2459/*
2460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2461% %
2462% %
2463% %
2464+ 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 %
2465% %
2466% %
2467% %
2468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2469%
2470% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2471% specified (x,y) location. The image background color is returned if an
2472% error occurs.
2473%
2474% The format of the GetOneVirtualPixelFromCache() method is:
2475%
2476% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002477% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002478% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002479%
2480% A description of each parameter follows:
2481%
2482% o image: the image.
2483%
2484% o virtual_pixel_method: the virtual pixel method.
2485%
2486% o x,y: These values define the location of the pixel to return.
2487%
2488% o pixel: return a pixel at the specified (x,y) location.
2489%
2490% o exception: return any errors or warnings in this structure.
2491%
2492*/
2493static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002494 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002495 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002496{
cristy0158a4b2010-09-20 13:59:45 +00002497 CacheInfo
2498 *cache_info;
2499
2500 const int
2501 id = GetOpenMPThreadId();
2502
cristy4c08aed2011-07-01 19:47:50 +00002503 const Quantum
2504 *p;
cristy3ed852e2009-09-05 21:47:34 +00002505
cristy2ed42f62011-10-02 19:49:57 +00002506 register ssize_t
2507 i;
2508
cristye7cc7cf2010-09-21 13:26:47 +00002509 assert(image != (const Image *) NULL);
2510 assert(image->signature == MagickSignature);
2511 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002512 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002513 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002514 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002515 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002516 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002517 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002518 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002519 {
2520 pixel[RedPixelChannel]=image->background_color.red;
2521 pixel[GreenPixelChannel]=image->background_color.green;
2522 pixel[BluePixelChannel]=image->background_color.blue;
2523 pixel[AlphaPixelChannel]=image->background_color.alpha;
2524 return(MagickFalse);
2525 }
2526 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2527 {
2528 PixelChannel
2529 channel;
2530
2531 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2532 pixel[channel]=p[i];
2533 }
cristy3ed852e2009-09-05 21:47:34 +00002534 return(MagickTrue);
2535}
2536
2537/*
2538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2539% %
2540% %
2541% %
2542+ G e t P i x e l C a c h e C o l o r s p a c e %
2543% %
2544% %
2545% %
2546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2547%
2548% GetPixelCacheColorspace() returns the class type of the pixel cache.
2549%
2550% The format of the GetPixelCacheColorspace() method is:
2551%
2552% Colorspace GetPixelCacheColorspace(Cache cache)
2553%
2554% A description of each parameter follows:
2555%
2556% o cache: the pixel cache.
2557%
2558*/
cristya6577ff2011-09-02 19:54:26 +00002559MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002560{
2561 CacheInfo
2562 *cache_info;
2563
2564 assert(cache != (Cache) NULL);
2565 cache_info=(CacheInfo *) cache;
2566 assert(cache_info->signature == MagickSignature);
2567 if (cache_info->debug != MagickFalse)
2568 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2569 cache_info->filename);
2570 return(cache_info->colorspace);
2571}
2572
2573/*
2574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2575% %
2576% %
2577% %
2578+ G e t P i x e l C a c h e M e t h o d s %
2579% %
2580% %
2581% %
2582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583%
2584% GetPixelCacheMethods() initializes the CacheMethods structure.
2585%
2586% The format of the GetPixelCacheMethods() method is:
2587%
2588% void GetPixelCacheMethods(CacheMethods *cache_methods)
2589%
2590% A description of each parameter follows:
2591%
2592% o cache_methods: Specifies a pointer to a CacheMethods structure.
2593%
2594*/
cristya6577ff2011-09-02 19:54:26 +00002595MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002596{
2597 assert(cache_methods != (CacheMethods *) NULL);
2598 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2599 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2600 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002601 cache_methods->get_virtual_metacontent_from_handler=
2602 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002603 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2604 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002605 cache_methods->get_authentic_metacontent_from_handler=
2606 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002607 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2608 cache_methods->get_one_authentic_pixel_from_handler=
2609 GetOneAuthenticPixelFromCache;
2610 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2611 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2612 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2613}
2614
2615/*
2616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2617% %
2618% %
2619% %
2620+ G e t P i x e l C a c h e N e x u s E x t e n t %
2621% %
2622% %
2623% %
2624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2625%
cristy4c08aed2011-07-01 19:47:50 +00002626% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2627% corresponding with the last call to SetPixelCacheNexusPixels() or
2628% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002629%
2630% The format of the GetPixelCacheNexusExtent() method is:
2631%
2632% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2633% NexusInfo *nexus_info)
2634%
2635% A description of each parameter follows:
2636%
2637% o nexus_info: the nexus info.
2638%
2639*/
cristya6577ff2011-09-02 19:54:26 +00002640MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002641 NexusInfo *nexus_info)
2642{
2643 CacheInfo
2644 *cache_info;
2645
2646 MagickSizeType
2647 extent;
2648
cristy9f027d12011-09-21 01:17:17 +00002649 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002650 cache_info=(CacheInfo *) cache;
2651 assert(cache_info->signature == MagickSignature);
2652 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2653 if (extent == 0)
2654 return((MagickSizeType) cache_info->columns*cache_info->rows);
2655 return(extent);
2656}
2657
2658/*
2659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2660% %
2661% %
2662% %
cristy4c08aed2011-07-01 19:47:50 +00002663+ 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 +00002664% %
2665% %
2666% %
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668%
cristy4c08aed2011-07-01 19:47:50 +00002669% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2670% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002671%
cristy4c08aed2011-07-01 19:47:50 +00002672% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002673%
cristy4c08aed2011-07-01 19:47:50 +00002674% void *GetPixelCacheNexusMetacontent(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%
cristy4c08aed2011-07-01 19:47:50 +00002681% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002682%
2683*/
cristya6577ff2011-09-02 19:54:26 +00002684MagickPrivate void *GetPixelCacheNexusMetacontent(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);
2693 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002694 return((void *) NULL);
2695 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002696}
2697
2698/*
2699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700% %
2701% %
2702% %
2703+ G e t P i x e l C a c h e N e x u s P i x e l s %
2704% %
2705% %
2706% %
2707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2708%
2709% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2710% cache nexus.
2711%
2712% The format of the GetPixelCacheNexusPixels() method is:
2713%
cristy4c08aed2011-07-01 19:47:50 +00002714% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002715% NexusInfo *nexus_info)
2716%
2717% A description of each parameter follows:
2718%
2719% o cache: the pixel cache.
2720%
2721% o nexus_info: the cache nexus to return the pixels.
2722%
2723*/
cristya6577ff2011-09-02 19:54:26 +00002724MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002725 NexusInfo *nexus_info)
2726{
2727 CacheInfo
2728 *cache_info;
2729
cristy9f027d12011-09-21 01:17:17 +00002730 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002731 cache_info=(CacheInfo *) cache;
2732 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002733 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002734 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002735 return(nexus_info->pixels);
2736}
2737
2738/*
2739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2740% %
2741% %
2742% %
cristy056ba772010-01-02 23:33:54 +00002743+ G e t P i x e l C a c h e P i x e l s %
2744% %
2745% %
2746% %
2747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2748%
2749% GetPixelCachePixels() returns the pixels associated with the specified image.
2750%
2751% The format of the GetPixelCachePixels() method is:
2752%
cristyf84a1932010-01-03 18:00:18 +00002753% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2754% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002755%
2756% A description of each parameter follows:
2757%
2758% o image: the image.
2759%
2760% o length: the pixel cache length.
2761%
cristyf84a1932010-01-03 18:00:18 +00002762% o exception: return any errors or warnings in this structure.
2763%
cristy056ba772010-01-02 23:33:54 +00002764*/
cristyd1dd6e42011-09-04 01:46:08 +00002765MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002766 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002767{
2768 CacheInfo
2769 *cache_info;
2770
2771 assert(image != (const Image *) NULL);
2772 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002773 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002774 assert(length != (MagickSizeType *) NULL);
2775 assert(exception != (ExceptionInfo *) NULL);
2776 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002777 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002778 assert(cache_info->signature == MagickSignature);
2779 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002780 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002781 return((void *) NULL);
2782 *length=cache_info->length;
2783 return((void *) cache_info->pixels);
2784}
2785
2786/*
2787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2788% %
2789% %
2790% %
cristyb32b90a2009-09-07 21:45:48 +00002791+ 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 +00002792% %
2793% %
2794% %
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796%
2797% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2798%
2799% The format of the GetPixelCacheStorageClass() method is:
2800%
2801% ClassType GetPixelCacheStorageClass(Cache cache)
2802%
2803% A description of each parameter follows:
2804%
2805% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2806%
2807% o cache: the pixel cache.
2808%
2809*/
cristya6577ff2011-09-02 19:54:26 +00002810MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002811{
2812 CacheInfo
2813 *cache_info;
2814
2815 assert(cache != (Cache) NULL);
2816 cache_info=(CacheInfo *) cache;
2817 assert(cache_info->signature == MagickSignature);
2818 if (cache_info->debug != MagickFalse)
2819 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2820 cache_info->filename);
2821 return(cache_info->storage_class);
2822}
2823
2824/*
2825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2826% %
2827% %
2828% %
cristyb32b90a2009-09-07 21:45:48 +00002829+ G e t P i x e l C a c h e T i l e S i z e %
2830% %
2831% %
2832% %
2833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2834%
2835% GetPixelCacheTileSize() returns the pixel cache tile size.
2836%
2837% The format of the GetPixelCacheTileSize() method is:
2838%
cristybb503372010-05-27 20:51:26 +00002839% void GetPixelCacheTileSize(const Image *image,size_t *width,
2840% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002841%
2842% A description of each parameter follows:
2843%
2844% o image: the image.
2845%
2846% o width: the optimize cache tile width in pixels.
2847%
2848% o height: the optimize cache tile height in pixels.
2849%
2850*/
cristya6577ff2011-09-02 19:54:26 +00002851MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002852 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002853{
cristy4c08aed2011-07-01 19:47:50 +00002854 CacheInfo
2855 *cache_info;
2856
cristyb32b90a2009-09-07 21:45:48 +00002857 assert(image != (Image *) NULL);
2858 assert(image->signature == MagickSignature);
2859 if (image->debug != MagickFalse)
2860 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002861 cache_info=(CacheInfo *) image->cache;
2862 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002863 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002864 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002865 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002866 *height=(*width);
2867}
2868
2869/*
2870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2871% %
2872% %
2873% %
2874+ G e t P i x e l C a c h e T y p e %
2875% %
2876% %
2877% %
2878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2879%
2880% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2881%
2882% The format of the GetPixelCacheType() method is:
2883%
2884% CacheType GetPixelCacheType(const Image *image)
2885%
2886% A description of each parameter follows:
2887%
2888% o image: the image.
2889%
2890*/
cristya6577ff2011-09-02 19:54:26 +00002891MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002892{
2893 CacheInfo
2894 *cache_info;
2895
2896 assert(image != (Image *) NULL);
2897 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002898 assert(image->cache != (Cache) NULL);
2899 cache_info=(CacheInfo *) image->cache;
2900 assert(cache_info->signature == MagickSignature);
2901 return(cache_info->type);
2902}
2903
2904/*
2905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2906% %
2907% %
2908% %
cristy3ed852e2009-09-05 21:47:34 +00002909+ 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 %
2910% %
2911% %
2912% %
2913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2914%
2915% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2916% pixel cache. A virtual pixel is any pixel access that is outside the
2917% boundaries of the image cache.
2918%
2919% The format of the GetPixelCacheVirtualMethod() method is:
2920%
2921% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2922%
2923% A description of each parameter follows:
2924%
2925% o image: the image.
2926%
2927*/
cristyd1dd6e42011-09-04 01:46:08 +00002928MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002929{
2930 CacheInfo
2931 *cache_info;
2932
2933 assert(image != (Image *) NULL);
2934 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002935 assert(image->cache != (Cache) NULL);
2936 cache_info=(CacheInfo *) image->cache;
2937 assert(cache_info->signature == MagickSignature);
2938 return(cache_info->virtual_pixel_method);
2939}
2940
2941/*
2942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2943% %
2944% %
2945% %
cristy4c08aed2011-07-01 19:47:50 +00002946+ 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 +00002947% %
2948% %
2949% %
2950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2951%
cristy4c08aed2011-07-01 19:47:50 +00002952% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2953% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002954%
cristy4c08aed2011-07-01 19:47:50 +00002955% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002956%
cristy4c08aed2011-07-01 19:47:50 +00002957% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002958%
2959% A description of each parameter follows:
2960%
2961% o image: the image.
2962%
2963*/
cristy4c08aed2011-07-01 19:47:50 +00002964static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002965{
2966 CacheInfo
2967 *cache_info;
2968
cristy5c9e6f22010-09-17 17:31:01 +00002969 const int
2970 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002971
cristy4c08aed2011-07-01 19:47:50 +00002972 const void
2973 *metacontent;
2974
cristye7cc7cf2010-09-21 13:26:47 +00002975 assert(image != (const Image *) NULL);
2976 assert(image->signature == MagickSignature);
2977 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002978 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002979 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002980 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002981 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2982 cache_info->nexus_info[id]);
2983 return(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 F r o m N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00002992% %
2993% %
2994% %
2995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2996%
cristy4c08aed2011-07-01 19:47:50 +00002997% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2998% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002999%
cristy4c08aed2011-07-01 19:47:50 +00003000% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00003001%
cristy4c08aed2011-07-01 19:47:50 +00003002% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003003% NexusInfo *nexus_info)
3004%
3005% A description of each parameter follows:
3006%
3007% o cache: the pixel cache.
3008%
cristy4c08aed2011-07-01 19:47:50 +00003009% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00003010%
3011*/
cristya6577ff2011-09-02 19:54:26 +00003012MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00003013 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00003014{
3015 CacheInfo
3016 *cache_info;
3017
cristye7cc7cf2010-09-21 13:26:47 +00003018 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003019 cache_info=(CacheInfo *) cache;
3020 assert(cache_info->signature == MagickSignature);
3021 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003022 return((void *) NULL);
3023 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003024}
3025
3026/*
3027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3028% %
3029% %
3030% %
cristy4c08aed2011-07-01 19:47:50 +00003031% 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 +00003032% %
3033% %
3034% %
3035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3036%
cristy4c08aed2011-07-01 19:47:50 +00003037% GetVirtualMetacontent() returns the virtual metacontent corresponding with
3038% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3039% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003040%
cristy4c08aed2011-07-01 19:47:50 +00003041% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003042%
cristy4c08aed2011-07-01 19:47:50 +00003043% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003044%
3045% A description of each parameter follows:
3046%
3047% o image: the image.
3048%
3049*/
cristy4c08aed2011-07-01 19:47:50 +00003050MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003051{
3052 CacheInfo
3053 *cache_info;
3054
cristy2036f5c2010-09-19 21:18:17 +00003055 const int
3056 id = GetOpenMPThreadId();
3057
cristy4c08aed2011-07-01 19:47:50 +00003058 const void
3059 *metacontent;
3060
cristy3ed852e2009-09-05 21:47:34 +00003061 assert(image != (const Image *) NULL);
3062 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003063 assert(image->cache != (Cache) NULL);
3064 cache_info=(CacheInfo *) image->cache;
3065 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003066 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3067 (GetVirtualMetacontentFromHandler) NULL)
3068 {
3069 metacontent=cache_info->methods.
3070 get_virtual_metacontent_from_handler(image);
3071 return(metacontent);
3072 }
cristy2036f5c2010-09-19 21:18:17 +00003073 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003074 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3075 cache_info->nexus_info[id]);
3076 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003077}
3078
3079/*
3080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3081% %
3082% %
3083% %
3084+ 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 %
3085% %
3086% %
3087% %
3088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3089%
3090% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3091% pixel cache as defined by the geometry parameters. A pointer to the pixels
3092% is returned if the pixels are transferred, otherwise a NULL is returned.
3093%
3094% The format of the GetVirtualPixelsFromNexus() method is:
3095%
cristy4c08aed2011-07-01 19:47:50 +00003096% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003097% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003098% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3099% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003100%
3101% A description of each parameter follows:
3102%
3103% o image: the image.
3104%
3105% o virtual_pixel_method: the virtual pixel method.
3106%
3107% o x,y,columns,rows: These values define the perimeter of a region of
3108% pixels.
3109%
3110% o nexus_info: the cache nexus to acquire.
3111%
3112% o exception: return any errors or warnings in this structure.
3113%
3114*/
3115
cristybb503372010-05-27 20:51:26 +00003116static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003117 DitherMatrix[64] =
3118 {
3119 0, 48, 12, 60, 3, 51, 15, 63,
3120 32, 16, 44, 28, 35, 19, 47, 31,
3121 8, 56, 4, 52, 11, 59, 7, 55,
3122 40, 24, 36, 20, 43, 27, 39, 23,
3123 2, 50, 14, 62, 1, 49, 13, 61,
3124 34, 18, 46, 30, 33, 17, 45, 29,
3125 10, 58, 6, 54, 9, 57, 5, 53,
3126 42, 26, 38, 22, 41, 25, 37, 21
3127 };
3128
cristybb503372010-05-27 20:51:26 +00003129static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003130{
cristybb503372010-05-27 20:51:26 +00003131 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003132 index;
3133
3134 index=x+DitherMatrix[x & 0x07]-32L;
3135 if (index < 0L)
3136 return(0L);
cristybb503372010-05-27 20:51:26 +00003137 if (index >= (ssize_t) columns)
3138 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003139 return(index);
3140}
3141
cristybb503372010-05-27 20:51:26 +00003142static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003143{
cristybb503372010-05-27 20:51:26 +00003144 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003145 index;
3146
3147 index=y+DitherMatrix[y & 0x07]-32L;
3148 if (index < 0L)
3149 return(0L);
cristybb503372010-05-27 20:51:26 +00003150 if (index >= (ssize_t) rows)
3151 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003152 return(index);
3153}
3154
cristybb503372010-05-27 20:51:26 +00003155static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003156{
3157 if (x < 0L)
3158 return(0L);
cristybb503372010-05-27 20:51:26 +00003159 if (x >= (ssize_t) columns)
3160 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003161 return(x);
3162}
3163
cristybb503372010-05-27 20:51:26 +00003164static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003165{
3166 if (y < 0L)
3167 return(0L);
cristybb503372010-05-27 20:51:26 +00003168 if (y >= (ssize_t) rows)
3169 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003170 return(y);
3171}
3172
cristybb503372010-05-27 20:51:26 +00003173static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003174{
cristybb503372010-05-27 20:51:26 +00003175 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003176}
3177
cristybb503372010-05-27 20:51:26 +00003178static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003179{
cristybb503372010-05-27 20:51:26 +00003180 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003181}
3182
cristybb503372010-05-27 20:51:26 +00003183static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3184 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003185{
3186 MagickModulo
3187 modulo;
3188
cristy6162bb42011-07-18 11:34:09 +00003189 /*
3190 Compute the remainder of dividing offset by extent. It returns not only
3191 the quotient (tile the offset falls in) but also the positive remainer
3192 within that tile such that 0 <= remainder < extent. This method is
3193 essentially a ldiv() using a floored modulo division rather than the
3194 normal default truncated modulo division.
3195 */
cristybb503372010-05-27 20:51:26 +00003196 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003197 if (offset < 0L)
3198 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003199 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003200 return(modulo);
3201}
3202
cristya6577ff2011-09-02 19:54:26 +00003203MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003204 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3205 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003206 ExceptionInfo *exception)
3207{
3208 CacheInfo
3209 *cache_info;
3210
3211 MagickOffsetType
3212 offset;
3213
3214 MagickSizeType
3215 length,
3216 number_pixels;
3217
3218 NexusInfo
3219 **virtual_nexus;
3220
cristy4c08aed2011-07-01 19:47:50 +00003221 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003222 *pixels,
cristy105ba3c2011-07-18 02:28:38 +00003223 virtual_pixel[MaxPixelChannels];
cristy3ed852e2009-09-05 21:47:34 +00003224
3225 RectangleInfo
3226 region;
3227
cristy4c08aed2011-07-01 19:47:50 +00003228 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003229 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003230
cristy4c08aed2011-07-01 19:47:50 +00003231 register const void
3232 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003233
cristy4c08aed2011-07-01 19:47:50 +00003234 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003235 *restrict q;
3236
cristybb503372010-05-27 20:51:26 +00003237 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003238 i,
3239 u;
cristy3ed852e2009-09-05 21:47:34 +00003240
cristy4c08aed2011-07-01 19:47:50 +00003241 register unsigned char
3242 *restrict s;
3243
cristy105ba3c2011-07-18 02:28:38 +00003244 ssize_t
3245 v;
3246
cristy4c08aed2011-07-01 19:47:50 +00003247 void
cristy105ba3c2011-07-18 02:28:38 +00003248 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003249
cristy3ed852e2009-09-05 21:47:34 +00003250 /*
3251 Acquire pixels.
3252 */
cristye7cc7cf2010-09-21 13:26:47 +00003253 assert(image != (const Image *) NULL);
3254 assert(image->signature == MagickSignature);
3255 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003256 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003257 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003258 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003259 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003260 region.x=x;
3261 region.y=y;
3262 region.width=columns;
3263 region.height=rows;
3264 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003265 if (pixels == (Quantum *) NULL)
3266 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003267 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003268 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3269 nexus_info->region.x;
3270 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3271 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003272 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3273 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003274 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3275 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003276 {
3277 MagickBooleanType
3278 status;
3279
3280 /*
3281 Pixel request is inside cache extents.
3282 */
cristy4c08aed2011-07-01 19:47:50 +00003283 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003284 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003285 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3286 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003287 return((const Quantum *) NULL);
3288 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003289 {
cristy4c08aed2011-07-01 19:47:50 +00003290 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003291 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003292 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003293 }
cristyacd2ed22011-08-30 01:44:23 +00003294 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003295 }
3296 /*
3297 Pixel request is outside cache extents.
3298 */
cristy4c08aed2011-07-01 19:47:50 +00003299 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003300 virtual_nexus=AcquirePixelCacheNexus(1);
3301 if (virtual_nexus == (NexusInfo **) NULL)
3302 {
cristy4c08aed2011-07-01 19:47:50 +00003303 if (virtual_nexus != (NexusInfo **) NULL)
3304 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003305 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3306 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003307 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003308 }
cristy105ba3c2011-07-18 02:28:38 +00003309 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3310 sizeof(*virtual_pixel));
3311 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003312 switch (virtual_pixel_method)
3313 {
cristy4c08aed2011-07-01 19:47:50 +00003314 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003315 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003316 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003317 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003318 case MaskVirtualPixelMethod:
3319 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003320 case EdgeVirtualPixelMethod:
3321 case CheckerTileVirtualPixelMethod:
3322 case HorizontalTileVirtualPixelMethod:
3323 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003324 {
cristy4c08aed2011-07-01 19:47:50 +00003325 if (cache_info->metacontent_extent != 0)
3326 {
cristy6162bb42011-07-18 11:34:09 +00003327 /*
3328 Acquire a metacontent buffer.
3329 */
cristya64b85d2011-09-14 01:02:31 +00003330 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003331 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003332 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003333 {
cristy4c08aed2011-07-01 19:47:50 +00003334 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3335 (void) ThrowMagickException(exception,GetMagickModule(),
3336 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3337 return((const Quantum *) NULL);
3338 }
cristy105ba3c2011-07-18 02:28:38 +00003339 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003340 cache_info->metacontent_extent);
3341 }
3342 switch (virtual_pixel_method)
3343 {
3344 case BlackVirtualPixelMethod:
3345 {
cristy30301712011-07-18 15:06:51 +00003346 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3347 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003348 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3349 break;
3350 }
3351 case GrayVirtualPixelMethod:
3352 {
cristy30301712011-07-18 15:06:51 +00003353 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003354 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3355 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003356 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3357 break;
3358 }
3359 case TransparentVirtualPixelMethod:
3360 {
cristy30301712011-07-18 15:06:51 +00003361 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3362 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003363 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3364 break;
3365 }
3366 case MaskVirtualPixelMethod:
3367 case WhiteVirtualPixelMethod:
3368 {
cristy30301712011-07-18 15:06:51 +00003369 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3370 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003371 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3372 break;
3373 }
3374 default:
3375 {
3376 SetPixelRed(image,image->background_color.red,virtual_pixel);
3377 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3378 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003379 if (image->colorspace == CMYKColorspace)
3380 SetPixelBlack(image,image->background_color.black,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003381 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3382 break;
3383 }
3384 }
cristy3ed852e2009-09-05 21:47:34 +00003385 break;
3386 }
3387 default:
cristy3ed852e2009-09-05 21:47:34 +00003388 break;
cristy3ed852e2009-09-05 21:47:34 +00003389 }
cristybb503372010-05-27 20:51:26 +00003390 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003391 {
cristybb503372010-05-27 20:51:26 +00003392 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003393 {
3394 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003395 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003396 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3397 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003398 {
3399 MagickModulo
3400 x_modulo,
3401 y_modulo;
3402
3403 /*
3404 Transfer a single pixel.
3405 */
3406 length=(MagickSizeType) 1;
3407 switch (virtual_pixel_method)
3408 {
cristy3ed852e2009-09-05 21:47:34 +00003409 default:
3410 {
3411 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003412 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003413 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003414 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003415 break;
3416 }
3417 case RandomVirtualPixelMethod:
3418 {
3419 if (cache_info->random_info == (RandomInfo *) NULL)
3420 cache_info->random_info=AcquireRandomInfo();
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003422 RandomX(cache_info->random_info,cache_info->columns),
3423 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003424 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003425 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 case DitherVirtualPixelMethod:
3429 {
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003431 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003432 1UL,1UL,*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 TileVirtualPixelMethod:
3437 {
3438 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3439 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003441 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003442 exception);
cristy4c08aed2011-07-01 19:47:50 +00003443 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003444 break;
3445 }
3446 case MirrorVirtualPixelMethod:
3447 {
3448 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3449 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003450 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003451 x_modulo.remainder-1L;
3452 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3453 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003454 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003455 y_modulo.remainder-1L;
3456 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003457 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003458 exception);
cristy4c08aed2011-07-01 19:47:50 +00003459 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003460 break;
3461 }
3462 case HorizontalTileEdgeVirtualPixelMethod:
3463 {
3464 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3465 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003466 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003467 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003468 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003469 break;
3470 }
3471 case VerticalTileEdgeVirtualPixelMethod:
3472 {
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003475 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003476 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003477 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3478 break;
3479 }
3480 case BackgroundVirtualPixelMethod:
3481 case BlackVirtualPixelMethod:
3482 case GrayVirtualPixelMethod:
3483 case TransparentVirtualPixelMethod:
3484 case MaskVirtualPixelMethod:
3485 case WhiteVirtualPixelMethod:
3486 {
3487 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003488 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003489 break;
3490 }
3491 case EdgeVirtualPixelMethod:
3492 case CheckerTileVirtualPixelMethod:
3493 {
3494 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3495 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3496 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3497 {
3498 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003499 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003500 break;
3501 }
3502 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3503 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3504 exception);
3505 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3506 break;
3507 }
3508 case HorizontalTileVirtualPixelMethod:
3509 {
3510 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3511 {
3512 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003513 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003514 break;
3515 }
3516 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3517 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3518 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3519 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3520 exception);
3521 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3522 break;
3523 }
3524 case VerticalTileVirtualPixelMethod:
3525 {
3526 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3527 {
3528 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003529 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003530 break;
3531 }
3532 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3533 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3534 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3535 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3536 exception);
3537 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003538 break;
3539 }
3540 }
cristy4c08aed2011-07-01 19:47:50 +00003541 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003542 break;
cristyed231572011-07-14 02:18:59 +00003543 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003544 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003545 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003546 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003547 {
3548 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3549 s+=cache_info->metacontent_extent;
3550 }
cristy3ed852e2009-09-05 21:47:34 +00003551 continue;
3552 }
3553 /*
3554 Transfer a run of pixels.
3555 */
cristy4c08aed2011-07-01 19:47:50 +00003556 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3557 length,1UL,*virtual_nexus,exception);
3558 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003559 break;
cristy4c08aed2011-07-01 19:47:50 +00003560 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003561 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3562 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003563 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003564 {
cristy4c08aed2011-07-01 19:47:50 +00003565 (void) memcpy(s,r,(size_t) length);
3566 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003567 }
3568 }
3569 }
cristy4c08aed2011-07-01 19:47:50 +00003570 /*
3571 Free resources.
3572 */
cristy105ba3c2011-07-18 02:28:38 +00003573 if (virtual_metacontent != (void *) NULL)
3574 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003575 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3576 return(pixels);
3577}
3578
3579/*
3580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3581% %
3582% %
3583% %
3584+ G e t V i r t u a l P i x e l C a c h e %
3585% %
3586% %
3587% %
3588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3589%
3590% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3591% cache as defined by the geometry parameters. A pointer to the pixels
3592% is returned if the pixels are transferred, otherwise a NULL is returned.
3593%
3594% The format of the GetVirtualPixelCache() method is:
3595%
cristy4c08aed2011-07-01 19:47:50 +00003596% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003597% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3598% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003599% ExceptionInfo *exception)
3600%
3601% A description of each parameter follows:
3602%
3603% o image: the image.
3604%
3605% o virtual_pixel_method: the virtual pixel method.
3606%
3607% o x,y,columns,rows: These values define the perimeter of a region of
3608% pixels.
3609%
3610% o exception: return any errors or warnings in this structure.
3611%
3612*/
cristy4c08aed2011-07-01 19:47:50 +00003613static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003614 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3615 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003616{
3617 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003618 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003619
cristy5c9e6f22010-09-17 17:31:01 +00003620 const int
3621 id = GetOpenMPThreadId();
3622
cristy4c08aed2011-07-01 19:47:50 +00003623 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003624 *p;
cristy4c08aed2011-07-01 19:47:50 +00003625
cristye7cc7cf2010-09-21 13:26:47 +00003626 assert(image != (const Image *) NULL);
3627 assert(image->signature == MagickSignature);
3628 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003629 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003630 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003631 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003632 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003633 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003634 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003635}
3636
3637/*
3638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3639% %
3640% %
3641% %
3642% G e t V i r t u a l P i x e l Q u e u e %
3643% %
3644% %
3645% %
3646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647%
cristy4c08aed2011-07-01 19:47:50 +00003648% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3649% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003650%
3651% The format of the GetVirtualPixelQueue() method is:
3652%
cristy4c08aed2011-07-01 19:47:50 +00003653% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003654%
3655% A description of each parameter follows:
3656%
3657% o image: the image.
3658%
3659*/
cristy4c08aed2011-07-01 19:47:50 +00003660MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003661{
3662 CacheInfo
3663 *cache_info;
3664
cristy2036f5c2010-09-19 21:18:17 +00003665 const int
3666 id = GetOpenMPThreadId();
3667
cristy3ed852e2009-09-05 21:47:34 +00003668 assert(image != (const Image *) NULL);
3669 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003670 assert(image->cache != (Cache) NULL);
3671 cache_info=(CacheInfo *) image->cache;
3672 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003673 if (cache_info->methods.get_virtual_pixels_handler !=
3674 (GetVirtualPixelsHandler) NULL)
3675 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003676 assert(id < (int) cache_info->number_threads);
3677 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003678}
3679
3680/*
3681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3682% %
3683% %
3684% %
3685% G e t V i r t u a l P i x e l s %
3686% %
3687% %
3688% %
3689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3690%
3691% GetVirtualPixels() returns an immutable pixel region. If the
3692% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003693% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003694% copy of the pixels or it may point to the original pixels in memory.
3695% Performance is maximized if the selected region is part of one row, or one
3696% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003697% (without a copy) if the image is in memory, or in a memory-mapped file. The
3698% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003699%
3700% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003701% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3702% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3703% access the meta-content (of type void) corresponding to the the
3704% region.
cristy3ed852e2009-09-05 21:47:34 +00003705%
3706% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3707%
3708% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3709% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3710% GetCacheViewAuthenticPixels() instead.
3711%
3712% The format of the GetVirtualPixels() method is:
3713%
cristy4c08aed2011-07-01 19:47:50 +00003714% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003715% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003716% ExceptionInfo *exception)
3717%
3718% A description of each parameter follows:
3719%
3720% o image: the image.
3721%
3722% o x,y,columns,rows: These values define the perimeter of a region of
3723% pixels.
3724%
3725% o exception: return any errors or warnings in this structure.
3726%
3727*/
cristy4c08aed2011-07-01 19:47:50 +00003728MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003729 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3730 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003731{
3732 CacheInfo
3733 *cache_info;
3734
cristy2036f5c2010-09-19 21:18:17 +00003735 const int
3736 id = GetOpenMPThreadId();
3737
cristy4c08aed2011-07-01 19:47:50 +00003738 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003739 *p;
cristy4c08aed2011-07-01 19:47:50 +00003740
cristy3ed852e2009-09-05 21:47:34 +00003741 assert(image != (const Image *) NULL);
3742 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003743 assert(image->cache != (Cache) NULL);
3744 cache_info=(CacheInfo *) image->cache;
3745 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003746 if (cache_info->methods.get_virtual_pixel_handler !=
3747 (GetVirtualPixelHandler) NULL)
3748 return(cache_info->methods.get_virtual_pixel_handler(image,
3749 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003750 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003751 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003752 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003753 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003754}
3755
3756/*
3757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3758% %
3759% %
3760% %
3761+ 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 %
3762% %
3763% %
3764% %
3765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3766%
cristy4c08aed2011-07-01 19:47:50 +00003767% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3768% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003769%
3770% The format of the GetVirtualPixelsCache() method is:
3771%
cristy4c08aed2011-07-01 19:47:50 +00003772% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003773%
3774% A description of each parameter follows:
3775%
3776% o image: the image.
3777%
3778*/
cristy4c08aed2011-07-01 19:47:50 +00003779static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003780{
3781 CacheInfo
3782 *cache_info;
3783
cristy5c9e6f22010-09-17 17:31:01 +00003784 const int
3785 id = GetOpenMPThreadId();
3786
cristye7cc7cf2010-09-21 13:26:47 +00003787 assert(image != (const Image *) NULL);
3788 assert(image->signature == MagickSignature);
3789 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003790 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003791 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003792 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003793 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003794}
3795
3796/*
3797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3798% %
3799% %
3800% %
3801+ G e t V i r t u a l P i x e l s N e x u s %
3802% %
3803% %
3804% %
3805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3806%
3807% GetVirtualPixelsNexus() returns the pixels associated with the specified
3808% cache nexus.
3809%
3810% The format of the GetVirtualPixelsNexus() method is:
3811%
cristy4c08aed2011-07-01 19:47:50 +00003812% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003813% NexusInfo *nexus_info)
3814%
3815% A description of each parameter follows:
3816%
3817% o cache: the pixel cache.
3818%
3819% o nexus_info: the cache nexus to return the colormap pixels.
3820%
3821*/
cristya6577ff2011-09-02 19:54:26 +00003822MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003823 NexusInfo *nexus_info)
3824{
3825 CacheInfo
3826 *cache_info;
3827
cristye7cc7cf2010-09-21 13:26:47 +00003828 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003829 cache_info=(CacheInfo *) cache;
3830 assert(cache_info->signature == MagickSignature);
3831 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003832 return((Quantum *) NULL);
3833 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003834}
3835
3836/*
3837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3838% %
3839% %
3840% %
3841+ M a s k P i x e l C a c h e N e x u s %
3842% %
3843% %
3844% %
3845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3846%
3847% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3848% The method returns MagickTrue if the pixel region is masked, otherwise
3849% MagickFalse.
3850%
3851% The format of the MaskPixelCacheNexus() method is:
3852%
3853% MagickBooleanType MaskPixelCacheNexus(Image *image,
3854% NexusInfo *nexus_info,ExceptionInfo *exception)
3855%
3856% A description of each parameter follows:
3857%
3858% o image: the image.
3859%
3860% o nexus_info: the cache nexus to clip.
3861%
3862% o exception: return any errors or warnings in this structure.
3863%
3864*/
3865
cristy4c08aed2011-07-01 19:47:50 +00003866static inline void MagickPixelCompositeMask(const PixelInfo *p,
3867 const MagickRealType alpha,const PixelInfo *q,
3868 const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003869{
3870 MagickRealType
3871 gamma;
3872
cristyaa83c2c2011-09-21 13:36:25 +00003873 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003874 {
3875 *composite=(*q);
3876 return;
3877 }
3878 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3879 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003880 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3881 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3882 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003883 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003884 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003885}
3886
3887static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3888 ExceptionInfo *exception)
3889{
3890 CacheInfo
3891 *cache_info;
3892
cristy4c08aed2011-07-01 19:47:50 +00003893 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003894 alpha,
3895 beta;
3896
3897 MagickSizeType
3898 number_pixels;
3899
3900 NexusInfo
3901 **clip_nexus,
3902 **image_nexus;
3903
cristy4c08aed2011-07-01 19:47:50 +00003904 register const Quantum
3905 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003906 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003907
cristy4c08aed2011-07-01 19:47:50 +00003908 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003909 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003910
cristye076a6e2010-08-15 19:59:43 +00003911 register ssize_t
3912 i;
3913
cristy3ed852e2009-09-05 21:47:34 +00003914 /*
3915 Apply clip mask.
3916 */
3917 if (image->debug != MagickFalse)
3918 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3919 if (image->mask == (Image *) NULL)
3920 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003921 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003922 if (cache_info == (Cache) NULL)
3923 return(MagickFalse);
3924 image_nexus=AcquirePixelCacheNexus(1);
3925 clip_nexus=AcquirePixelCacheNexus(1);
3926 if ((image_nexus == (NexusInfo **) NULL) ||
3927 (clip_nexus == (NexusInfo **) NULL))
3928 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003929 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3930 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3931 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003932 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003933 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3934 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3935 nexus_info->region.height,clip_nexus[0],&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00003936 GetPixelInfo(image,&alpha);
3937 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003938 number_pixels=(MagickSizeType) nexus_info->region.width*
3939 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003940 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003941 {
cristy4c08aed2011-07-01 19:47:50 +00003942 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003943 break;
cristy4c08aed2011-07-01 19:47:50 +00003944 SetPixelInfo(image,p,&alpha);
3945 SetPixelInfo(image,q,&beta);
3946 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3947 &alpha,alpha.alpha,&beta);
3948 SetPixelRed(image,ClampToQuantum(beta.red),q);
3949 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3950 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3951 if (cache_info->colorspace == CMYKColorspace)
3952 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3953 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003954 p++;
3955 q++;
3956 r++;
3957 }
3958 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3959 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003960 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003961 return(MagickFalse);
3962 return(MagickTrue);
3963}
3964
3965/*
3966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967% %
3968% %
3969% %
3970+ O p e n P i x e l C a c h e %
3971% %
3972% %
3973% %
3974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3975%
3976% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3977% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003978% metacontent, and memory mapping the cache if it is disk based. The cache
3979% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003980%
3981% The format of the OpenPixelCache() method is:
3982%
3983% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3984% ExceptionInfo *exception)
3985%
3986% A description of each parameter follows:
3987%
3988% o image: the image.
3989%
3990% o mode: ReadMode, WriteMode, or IOMode.
3991%
3992% o exception: return any errors or warnings in this structure.
3993%
3994*/
3995
cristyd43a46b2010-01-21 02:13:41 +00003996static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003997{
3998 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003999 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00004000 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004001 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004002 {
4003 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004004 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00004005 cache_info->length);
4006 }
4007}
4008
4009static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4010{
4011 CacheInfo
4012 *cache_info;
4013
4014 MagickOffsetType
4015 count,
4016 extent,
4017 offset;
4018
4019 cache_info=(CacheInfo *) image->cache;
4020 if (image->debug != MagickFalse)
4021 {
4022 char
4023 format[MaxTextExtent],
4024 message[MaxTextExtent];
4025
cristyb9080c92009-12-01 20:13:26 +00004026 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004027 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004028 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004029 cache_info->cache_filename,cache_info->file,format);
4030 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4031 }
4032 if (length != (MagickSizeType) ((MagickOffsetType) length))
4033 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004034 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004035 if (extent < 0)
4036 return(MagickFalse);
4037 if ((MagickSizeType) extent >= length)
4038 return(MagickTrue);
4039 offset=(MagickOffsetType) length-1;
4040 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4041 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4042}
4043
4044static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4045 ExceptionInfo *exception)
4046{
cristy3ed852e2009-09-05 21:47:34 +00004047 CacheInfo
4048 *cache_info,
4049 source_info;
4050
cristyf3a6a9d2010-11-07 21:02:56 +00004051 char
4052 format[MaxTextExtent],
4053 message[MaxTextExtent];
4054
cristy4c08aed2011-07-01 19:47:50 +00004055 MagickBooleanType
4056 status;
4057
cristy3ed852e2009-09-05 21:47:34 +00004058 MagickSizeType
4059 length,
4060 number_pixels;
4061
cristy3ed852e2009-09-05 21:47:34 +00004062 size_t
cristye076a6e2010-08-15 19:59:43 +00004063 columns,
cristy3ed852e2009-09-05 21:47:34 +00004064 packet_size;
4065
cristye7cc7cf2010-09-21 13:26:47 +00004066 assert(image != (const Image *) NULL);
4067 assert(image->signature == MagickSignature);
4068 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004069 if (image->debug != MagickFalse)
4070 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4071 if ((image->columns == 0) || (image->rows == 0))
4072 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4073 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004074 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004075 source_info=(*cache_info);
4076 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004077 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004078 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004079 cache_info->storage_class=image->storage_class;
4080 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004081 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004082 cache_info->rows=image->rows;
4083 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004084 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004085 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004086 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004087 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004088 if (image->ping != MagickFalse)
4089 {
cristy73724512010-04-12 14:43:14 +00004090 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004091 cache_info->pixels=(Quantum *) NULL;
4092 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004093 cache_info->length=0;
4094 return(MagickTrue);
4095 }
cristy3ed852e2009-09-05 21:47:34 +00004096 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004097 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004098 if (image->metacontent_extent != 0)
4099 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004100 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004101 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004102 if (cache_info->columns != columns)
4103 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4104 image->filename);
4105 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004106 if ((cache_info->type != UndefinedCache) &&
4107 (cache_info->columns <= source_info.columns) &&
4108 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004109 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004110 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4111 {
4112 /*
4113 Inline pixel cache clone optimization.
4114 */
4115 if ((cache_info->columns == source_info.columns) &&
4116 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004117 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004118 (cache_info->metacontent_extent == source_info.metacontent_extent))
4119 return(MagickTrue);
4120 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4121 }
cristy3ed852e2009-09-05 21:47:34 +00004122 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004123 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004124 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004125 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4126 {
4127 status=AcquireMagickResource(MemoryResource,cache_info->length);
4128 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4129 (cache_info->type == MemoryCache))
4130 {
cristyd43a46b2010-01-21 02:13:41 +00004131 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004132 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004133 cache_info->pixels=source_info.pixels;
4134 else
4135 {
4136 /*
4137 Create memory pixel cache.
4138 */
cristy4c08aed2011-07-01 19:47:50 +00004139 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004140 if (image->debug != MagickFalse)
4141 {
cristy97e7a572009-12-05 15:07:53 +00004142 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004143 format);
cristyb51dff52011-05-19 16:55:47 +00004144 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004145 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4146 cache_info->filename,cache_info->mapped != MagickFalse ?
4147 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004148 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004149 format);
cristy3ed852e2009-09-05 21:47:34 +00004150 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4151 message);
4152 }
cristy3ed852e2009-09-05 21:47:34 +00004153 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004154 cache_info->metacontent=(void *) NULL;
4155 if (cache_info->metacontent_extent != 0)
4156 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004157 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004158 if (source_info.storage_class != UndefinedClass)
4159 {
cristy4c08aed2011-07-01 19:47:50 +00004160 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004161 exception);
4162 RelinquishPixelCachePixels(&source_info);
4163 }
cristy4c08aed2011-07-01 19:47:50 +00004164 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004165 }
4166 }
4167 RelinquishMagickResource(MemoryResource,cache_info->length);
4168 }
4169 /*
4170 Create pixel cache on disk.
4171 */
4172 status=AcquireMagickResource(DiskResource,cache_info->length);
4173 if (status == MagickFalse)
4174 {
4175 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4176 "CacheResourcesExhausted","`%s'",image->filename);
4177 return(MagickFalse);
4178 }
4179 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4180 {
4181 RelinquishMagickResource(DiskResource,cache_info->length);
4182 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4183 image->filename);
4184 return(MagickFalse);
4185 }
4186 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4187 cache_info->length);
4188 if (status == MagickFalse)
4189 {
4190 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4191 image->filename);
4192 return(MagickFalse);
4193 }
cristyed231572011-07-14 02:18:59 +00004194 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004195 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004196 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004197 cache_info->type=DiskCache;
4198 else
4199 {
4200 status=AcquireMagickResource(MapResource,cache_info->length);
4201 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4202 (cache_info->type != MemoryCache))
4203 cache_info->type=DiskCache;
4204 else
4205 {
cristy4c08aed2011-07-01 19:47:50 +00004206 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004207 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004208 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004209 {
cristy3ed852e2009-09-05 21:47:34 +00004210 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004211 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004212 }
4213 else
4214 {
4215 /*
4216 Create file-backed memory-mapped pixel cache.
4217 */
cristy4c08aed2011-07-01 19:47:50 +00004218 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004219 (void) ClosePixelCacheOnDisk(cache_info);
4220 cache_info->type=MapCache;
4221 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004222 cache_info->metacontent=(void *) NULL;
4223 if (cache_info->metacontent_extent != 0)
4224 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004225 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004226 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004227 {
4228 status=ClonePixelCachePixels(cache_info,&source_info,
4229 exception);
4230 RelinquishPixelCachePixels(&source_info);
4231 }
4232 if (image->debug != MagickFalse)
4233 {
cristy97e7a572009-12-05 15:07:53 +00004234 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004235 format);
cristyb51dff52011-05-19 16:55:47 +00004236 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004237 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004238 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004239 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004240 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004241 format);
cristy3ed852e2009-09-05 21:47:34 +00004242 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4243 message);
4244 }
cristy4c08aed2011-07-01 19:47:50 +00004245 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004246 }
4247 }
4248 RelinquishMagickResource(MapResource,cache_info->length);
4249 }
cristy4c08aed2011-07-01 19:47:50 +00004250 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004251 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4252 {
4253 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4254 RelinquishPixelCachePixels(&source_info);
4255 }
4256 if (image->debug != MagickFalse)
4257 {
cristyb9080c92009-12-01 20:13:26 +00004258 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004259 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004260 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004261 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004262 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004263 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004264 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4265 }
cristy4c08aed2011-07-01 19:47:50 +00004266 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004267}
4268
4269/*
4270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4271% %
4272% %
4273% %
4274+ P e r s i s t P i x e l C a c h e %
4275% %
4276% %
4277% %
4278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4279%
4280% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4281% persistent pixel cache is one that resides on disk and is not destroyed
4282% when the program exits.
4283%
4284% The format of the PersistPixelCache() method is:
4285%
4286% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4287% const MagickBooleanType attach,MagickOffsetType *offset,
4288% ExceptionInfo *exception)
4289%
4290% A description of each parameter follows:
4291%
4292% o image: the image.
4293%
4294% o filename: the persistent pixel cache filename.
4295%
cristyf3a6a9d2010-11-07 21:02:56 +00004296% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004297%
cristy3ed852e2009-09-05 21:47:34 +00004298% o initialize: A value other than zero initializes the persistent pixel
4299% cache.
4300%
4301% o offset: the offset in the persistent cache to store pixels.
4302%
4303% o exception: return any errors or warnings in this structure.
4304%
4305*/
4306MagickExport MagickBooleanType PersistPixelCache(Image *image,
4307 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4308 ExceptionInfo *exception)
4309{
4310 CacheInfo
4311 *cache_info,
4312 *clone_info;
4313
4314 Image
4315 clone_image;
4316
cristy3ed852e2009-09-05 21:47:34 +00004317 MagickBooleanType
4318 status;
4319
cristye076a6e2010-08-15 19:59:43 +00004320 ssize_t
4321 page_size;
4322
cristy3ed852e2009-09-05 21:47:34 +00004323 assert(image != (Image *) NULL);
4324 assert(image->signature == MagickSignature);
4325 if (image->debug != MagickFalse)
4326 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4327 assert(image->cache != (void *) NULL);
4328 assert(filename != (const char *) NULL);
4329 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004330 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004331 cache_info=(CacheInfo *) image->cache;
4332 assert(cache_info->signature == MagickSignature);
4333 if (attach != MagickFalse)
4334 {
4335 /*
cristy01b7eb02009-09-10 23:10:14 +00004336 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004337 */
4338 if (image->debug != MagickFalse)
4339 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004340 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004341 (void) CopyMagickString(cache_info->cache_filename,filename,
4342 MaxTextExtent);
4343 cache_info->type=DiskCache;
4344 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004345 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004346 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004347 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004348 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004349 }
cristy01b7eb02009-09-10 23:10:14 +00004350 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4351 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004352 {
cristyf84a1932010-01-03 18:00:18 +00004353 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004354 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004355 (cache_info->reference_count == 1))
4356 {
4357 int
4358 status;
4359
4360 /*
cristy01b7eb02009-09-10 23:10:14 +00004361 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004362 */
cristy320684d2011-09-23 14:55:47 +00004363 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004364 if (status == 0)
4365 {
4366 (void) CopyMagickString(cache_info->cache_filename,filename,
4367 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004368 *offset+=cache_info->length+page_size-(cache_info->length %
4369 page_size);
cristyf84a1932010-01-03 18:00:18 +00004370 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004371 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004372 if (image->debug != MagickFalse)
4373 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4374 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004375 return(MagickTrue);
4376 }
4377 }
cristyf84a1932010-01-03 18:00:18 +00004378 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004379 }
4380 /*
cristy01b7eb02009-09-10 23:10:14 +00004381 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004382 */
4383 clone_image=(*image);
4384 clone_info=(CacheInfo *) clone_image.cache;
4385 image->cache=ClonePixelCache(cache_info);
4386 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4387 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4388 cache_info->type=DiskCache;
4389 cache_info->offset=(*offset);
4390 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004391 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004392 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004393 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004394 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004395 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4396 return(status);
4397}
4398
4399/*
4400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4401% %
4402% %
4403% %
4404+ Q u e u e A u t h e n t i c N e x u s %
4405% %
4406% %
4407% %
4408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4409%
4410% QueueAuthenticNexus() allocates an region to store image pixels as defined
4411% by the region rectangle and returns a pointer to the region. This region is
4412% subsequently transferred from the pixel cache with
4413% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4414% pixels are transferred, otherwise a NULL is returned.
4415%
4416% The format of the QueueAuthenticNexus() method is:
4417%
cristy4c08aed2011-07-01 19:47:50 +00004418% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004419% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004420% const MagickBooleanType clone,NexusInfo *nexus_info,
4421% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004422%
4423% A description of each parameter follows:
4424%
4425% o image: the image.
4426%
4427% o x,y,columns,rows: These values define the perimeter of a region of
4428% pixels.
4429%
4430% o nexus_info: the cache nexus to set.
4431%
cristy65dbf172011-10-06 17:32:04 +00004432% o clone: clone the pixel cache.
4433%
cristy3ed852e2009-09-05 21:47:34 +00004434% o exception: return any errors or warnings in this structure.
4435%
4436*/
cristya6577ff2011-09-02 19:54:26 +00004437MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004438 const ssize_t y,const size_t columns,const size_t rows,
4439 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004440{
4441 CacheInfo
4442 *cache_info;
4443
4444 MagickOffsetType
4445 offset;
4446
4447 MagickSizeType
4448 number_pixels;
4449
4450 RectangleInfo
4451 region;
4452
4453 /*
4454 Validate pixel cache geometry.
4455 */
cristye7cc7cf2010-09-21 13:26:47 +00004456 assert(image != (const Image *) NULL);
4457 assert(image->signature == MagickSignature);
4458 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004459 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004460 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004461 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004462 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004463 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4464 {
4465 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4466 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004467 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004468 }
cristybb503372010-05-27 20:51:26 +00004469 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4470 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004471 {
4472 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4473 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004474 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004475 }
4476 offset=(MagickOffsetType) y*cache_info->columns+x;
4477 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004478 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004479 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4480 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4481 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004482 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004483 /*
4484 Return pixel cache.
4485 */
4486 region.x=x;
4487 region.y=y;
4488 region.width=columns;
4489 region.height=rows;
4490 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4491}
4492
4493/*
4494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4495% %
4496% %
4497% %
4498+ 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 %
4499% %
4500% %
4501% %
4502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4503%
4504% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4505% defined by the region rectangle and returns a pointer to the region. This
4506% region is subsequently transferred from the pixel cache with
4507% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4508% pixels are transferred, otherwise a NULL is returned.
4509%
4510% The format of the QueueAuthenticPixelsCache() method is:
4511%
cristy4c08aed2011-07-01 19:47:50 +00004512% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004513% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004514% ExceptionInfo *exception)
4515%
4516% A description of each parameter follows:
4517%
4518% o image: the image.
4519%
4520% o x,y,columns,rows: These values define the perimeter of a region of
4521% pixels.
4522%
4523% o exception: return any errors or warnings in this structure.
4524%
4525*/
cristy4c08aed2011-07-01 19:47:50 +00004526static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004527 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004528 ExceptionInfo *exception)
4529{
4530 CacheInfo
4531 *cache_info;
4532
cristy5c9e6f22010-09-17 17:31:01 +00004533 const int
4534 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004535
cristy4c08aed2011-07-01 19:47:50 +00004536 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004537 *q;
cristy4c08aed2011-07-01 19:47:50 +00004538
cristye7cc7cf2010-09-21 13:26:47 +00004539 assert(image != (const Image *) NULL);
4540 assert(image->signature == MagickSignature);
4541 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004542 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004543 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004544 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004545 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4546 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004547 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004548}
4549
4550/*
4551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4552% %
4553% %
4554% %
4555% Q u e u e A u t h e n t i c P i x e l s %
4556% %
4557% %
4558% %
4559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4560%
4561% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004562% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004563% region is returned, otherwise NULL is returned. The returned pointer may
4564% point to a temporary working buffer for the pixels or it may point to the
4565% final location of the pixels in memory.
4566%
4567% Write-only access means that any existing pixel values corresponding to
4568% the region are ignored. This is useful if the initial image is being
4569% created from scratch, or if the existing pixel values are to be
4570% completely replaced without need to refer to their pre-existing values.
4571% The application is free to read and write the pixel buffer returned by
4572% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4573% initialize the pixel array values. Initializing pixel array values is the
4574% application's responsibility.
4575%
4576% Performance is maximized if the selected region is part of one row, or
4577% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004578% pixels in-place (without a copy) if the image is in memory, or in a
4579% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004580% by the user.
4581%
4582% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004583% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4584% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4585% obtain the meta-content (of type void) corresponding to the region.
4586% Once the Quantum (and/or Quantum) array has been updated, the
4587% changes must be saved back to the underlying image using
4588% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004589%
4590% The format of the QueueAuthenticPixels() method is:
4591%
cristy4c08aed2011-07-01 19:47:50 +00004592% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004593% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004594% ExceptionInfo *exception)
4595%
4596% A description of each parameter follows:
4597%
4598% o image: the image.
4599%
4600% o x,y,columns,rows: These values define the perimeter of a region of
4601% pixels.
4602%
4603% o exception: return any errors or warnings in this structure.
4604%
4605*/
cristy4c08aed2011-07-01 19:47:50 +00004606MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004607 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004608 ExceptionInfo *exception)
4609{
4610 CacheInfo
4611 *cache_info;
4612
cristy2036f5c2010-09-19 21:18:17 +00004613 const int
4614 id = GetOpenMPThreadId();
4615
cristy4c08aed2011-07-01 19:47:50 +00004616 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004617 *q;
cristy4c08aed2011-07-01 19:47:50 +00004618
cristy3ed852e2009-09-05 21:47:34 +00004619 assert(image != (Image *) NULL);
4620 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004621 assert(image->cache != (Cache) NULL);
4622 cache_info=(CacheInfo *) image->cache;
4623 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004624 if (cache_info->methods.queue_authentic_pixels_handler !=
4625 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004626 {
cristyacd2ed22011-08-30 01:44:23 +00004627 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004628 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004629 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004630 }
cristy2036f5c2010-09-19 21:18:17 +00004631 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004632 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4633 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004634 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004635}
4636
4637/*
4638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4639% %
4640% %
4641% %
cristy4c08aed2011-07-01 19:47:50 +00004642+ 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 +00004643% %
4644% %
4645% %
4646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4647%
cristy4c08aed2011-07-01 19:47:50 +00004648% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004649% the pixel cache.
4650%
cristy4c08aed2011-07-01 19:47:50 +00004651% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004652%
cristy4c08aed2011-07-01 19:47:50 +00004653% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004654% NexusInfo *nexus_info,ExceptionInfo *exception)
4655%
4656% A description of each parameter follows:
4657%
4658% o cache_info: the pixel cache.
4659%
cristy4c08aed2011-07-01 19:47:50 +00004660% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004661%
4662% o exception: return any errors or warnings in this structure.
4663%
4664*/
cristy4c08aed2011-07-01 19:47:50 +00004665static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004666 NexusInfo *nexus_info,ExceptionInfo *exception)
4667{
4668 MagickOffsetType
4669 count,
4670 offset;
4671
4672 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004673 extent,
4674 length;
cristy3ed852e2009-09-05 21:47:34 +00004675
cristybb503372010-05-27 20:51:26 +00004676 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004677 y;
4678
cristy4c08aed2011-07-01 19:47:50 +00004679 register unsigned char
4680 *restrict q;
4681
cristybb503372010-05-27 20:51:26 +00004682 size_t
cristy3ed852e2009-09-05 21:47:34 +00004683 rows;
4684
cristy4c08aed2011-07-01 19:47:50 +00004685 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004686 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004687 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004688 return(MagickTrue);
4689 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4690 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004691 length=(MagickSizeType) nexus_info->region.width*
4692 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004693 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004694 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004695 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004696 switch (cache_info->type)
4697 {
4698 case MemoryCache:
4699 case MapCache:
4700 {
cristy4c08aed2011-07-01 19:47:50 +00004701 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004702 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004703
4704 /*
cristy4c08aed2011-07-01 19:47:50 +00004705 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004706 */
cristydd341db2010-03-04 19:06:38 +00004707 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004708 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004709 {
cristy48078b12010-09-23 17:11:01 +00004710 length=extent;
cristydd341db2010-03-04 19:06:38 +00004711 rows=1UL;
4712 }
cristy4c08aed2011-07-01 19:47:50 +00004713 p=(unsigned char *) cache_info->metacontent+offset*
4714 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004715 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004716 {
cristy8f036fe2010-09-18 02:02:00 +00004717 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004718 p+=cache_info->metacontent_extent*cache_info->columns;
4719 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004720 }
4721 break;
4722 }
4723 case DiskCache:
4724 {
4725 /*
cristy4c08aed2011-07-01 19:47:50 +00004726 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004727 */
4728 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4729 {
4730 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4731 cache_info->cache_filename);
4732 return(MagickFalse);
4733 }
cristydd341db2010-03-04 19:06:38 +00004734 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004735 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004736 {
cristy48078b12010-09-23 17:11:01 +00004737 length=extent;
cristydd341db2010-03-04 19:06:38 +00004738 rows=1UL;
4739 }
cristy48078b12010-09-23 17:11:01 +00004740 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004741 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004742 {
cristy48078b12010-09-23 17:11:01 +00004743 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004744 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004745 cache_info->metacontent_extent,length,(unsigned char *) q);
4746 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004747 break;
4748 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004749 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004750 }
cristybb503372010-05-27 20:51:26 +00004751 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004752 {
4753 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4754 cache_info->cache_filename);
4755 return(MagickFalse);
4756 }
4757 break;
4758 }
4759 default:
4760 break;
4761 }
4762 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004763 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004764 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004765 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004766 nexus_info->region.width,(double) nexus_info->region.height,(double)
4767 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004768 return(MagickTrue);
4769}
4770
4771/*
4772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4773% %
4774% %
4775% %
4776+ R e a d P i x e l C a c h e P i x e l s %
4777% %
4778% %
4779% %
4780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4781%
4782% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4783% cache.
4784%
4785% The format of the ReadPixelCachePixels() method is:
4786%
4787% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4788% NexusInfo *nexus_info,ExceptionInfo *exception)
4789%
4790% A description of each parameter follows:
4791%
4792% o cache_info: the pixel cache.
4793%
4794% o nexus_info: the cache nexus to read the pixels.
4795%
4796% o exception: return any errors or warnings in this structure.
4797%
4798*/
4799static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4800 NexusInfo *nexus_info,ExceptionInfo *exception)
4801{
4802 MagickOffsetType
4803 count,
4804 offset;
4805
4806 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004807 extent,
4808 length;
cristy3ed852e2009-09-05 21:47:34 +00004809
cristy4c08aed2011-07-01 19:47:50 +00004810 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004811 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004812
cristye076a6e2010-08-15 19:59:43 +00004813 register ssize_t
4814 y;
4815
cristybb503372010-05-27 20:51:26 +00004816 size_t
cristy3ed852e2009-09-05 21:47:34 +00004817 rows;
4818
cristy4c08aed2011-07-01 19:47:50 +00004819 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004820 return(MagickTrue);
4821 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4822 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004823 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004824 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004825 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004826 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004827 q=nexus_info->pixels;
4828 switch (cache_info->type)
4829 {
4830 case MemoryCache:
4831 case MapCache:
4832 {
cristy4c08aed2011-07-01 19:47:50 +00004833 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004834 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004835
4836 /*
4837 Read pixels from memory.
4838 */
cristydd341db2010-03-04 19:06:38 +00004839 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004840 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004841 {
cristy48078b12010-09-23 17:11:01 +00004842 length=extent;
cristydd341db2010-03-04 19:06:38 +00004843 rows=1UL;
4844 }
cristyed231572011-07-14 02:18:59 +00004845 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004846 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004847 {
cristy8f036fe2010-09-18 02:02:00 +00004848 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004849 p+=cache_info->number_channels*cache_info->columns;
4850 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004851 }
4852 break;
4853 }
4854 case DiskCache:
4855 {
4856 /*
4857 Read pixels from disk.
4858 */
4859 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4860 {
4861 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4862 cache_info->cache_filename);
4863 return(MagickFalse);
4864 }
cristydd341db2010-03-04 19:06:38 +00004865 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004866 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004867 {
cristy48078b12010-09-23 17:11:01 +00004868 length=extent;
cristydd341db2010-03-04 19:06:38 +00004869 rows=1UL;
4870 }
cristybb503372010-05-27 20:51:26 +00004871 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004872 {
4873 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004874 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004875 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004876 break;
4877 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004878 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004879 }
cristybb503372010-05-27 20:51:26 +00004880 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004881 {
4882 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4883 cache_info->cache_filename);
4884 return(MagickFalse);
4885 }
4886 break;
4887 }
4888 default:
4889 break;
4890 }
4891 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004892 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004893 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004894 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004895 nexus_info->region.width,(double) nexus_info->region.height,(double)
4896 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004897 return(MagickTrue);
4898}
4899
4900/*
4901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4902% %
4903% %
4904% %
4905+ R e f e r e n c e P i x e l C a c h e %
4906% %
4907% %
4908% %
4909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4910%
4911% ReferencePixelCache() increments the reference count associated with the
4912% pixel cache returning a pointer to the cache.
4913%
4914% The format of the ReferencePixelCache method is:
4915%
4916% Cache ReferencePixelCache(Cache cache_info)
4917%
4918% A description of each parameter follows:
4919%
4920% o cache_info: the pixel cache.
4921%
4922*/
cristya6577ff2011-09-02 19:54:26 +00004923MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004924{
4925 CacheInfo
4926 *cache_info;
4927
4928 assert(cache != (Cache *) NULL);
4929 cache_info=(CacheInfo *) cache;
4930 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004931 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004932 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004933 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004934 return(cache_info);
4935}
4936
4937/*
4938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4939% %
4940% %
4941% %
4942+ S e t P i x e l C a c h e M e t h o d s %
4943% %
4944% %
4945% %
4946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4947%
4948% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4949%
4950% The format of the SetPixelCacheMethods() method is:
4951%
4952% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4953%
4954% A description of each parameter follows:
4955%
4956% o cache: the pixel cache.
4957%
4958% o cache_methods: Specifies a pointer to a CacheMethods structure.
4959%
4960*/
cristya6577ff2011-09-02 19:54:26 +00004961MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004962{
4963 CacheInfo
4964 *cache_info;
4965
4966 GetOneAuthenticPixelFromHandler
4967 get_one_authentic_pixel_from_handler;
4968
4969 GetOneVirtualPixelFromHandler
4970 get_one_virtual_pixel_from_handler;
4971
4972 /*
4973 Set cache pixel methods.
4974 */
4975 assert(cache != (Cache) NULL);
4976 assert(cache_methods != (CacheMethods *) NULL);
4977 cache_info=(CacheInfo *) cache;
4978 assert(cache_info->signature == MagickSignature);
4979 if (cache_info->debug != MagickFalse)
4980 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4981 cache_info->filename);
4982 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4983 cache_info->methods.get_virtual_pixel_handler=
4984 cache_methods->get_virtual_pixel_handler;
4985 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4986 cache_info->methods.destroy_pixel_handler=
4987 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004988 if (cache_methods->get_virtual_metacontent_from_handler !=
4989 (GetVirtualMetacontentFromHandler) NULL)
4990 cache_info->methods.get_virtual_metacontent_from_handler=
4991 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004992 if (cache_methods->get_authentic_pixels_handler !=
4993 (GetAuthenticPixelsHandler) NULL)
4994 cache_info->methods.get_authentic_pixels_handler=
4995 cache_methods->get_authentic_pixels_handler;
4996 if (cache_methods->queue_authentic_pixels_handler !=
4997 (QueueAuthenticPixelsHandler) NULL)
4998 cache_info->methods.queue_authentic_pixels_handler=
4999 cache_methods->queue_authentic_pixels_handler;
5000 if (cache_methods->sync_authentic_pixels_handler !=
5001 (SyncAuthenticPixelsHandler) NULL)
5002 cache_info->methods.sync_authentic_pixels_handler=
5003 cache_methods->sync_authentic_pixels_handler;
5004 if (cache_methods->get_authentic_pixels_from_handler !=
5005 (GetAuthenticPixelsFromHandler) NULL)
5006 cache_info->methods.get_authentic_pixels_from_handler=
5007 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00005008 if (cache_methods->get_authentic_metacontent_from_handler !=
5009 (GetAuthenticMetacontentFromHandler) NULL)
5010 cache_info->methods.get_authentic_metacontent_from_handler=
5011 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00005012 get_one_virtual_pixel_from_handler=
5013 cache_info->methods.get_one_virtual_pixel_from_handler;
5014 if (get_one_virtual_pixel_from_handler !=
5015 (GetOneVirtualPixelFromHandler) NULL)
5016 cache_info->methods.get_one_virtual_pixel_from_handler=
5017 cache_methods->get_one_virtual_pixel_from_handler;
5018 get_one_authentic_pixel_from_handler=
5019 cache_methods->get_one_authentic_pixel_from_handler;
5020 if (get_one_authentic_pixel_from_handler !=
5021 (GetOneAuthenticPixelFromHandler) NULL)
5022 cache_info->methods.get_one_authentic_pixel_from_handler=
5023 cache_methods->get_one_authentic_pixel_from_handler;
5024}
5025
5026/*
5027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5028% %
5029% %
5030% %
5031+ S e t P i x e l C a c h e N e x u s P i x e l s %
5032% %
5033% %
5034% %
5035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5036%
5037% SetPixelCacheNexusPixels() defines the region of the cache for the
5038% specified cache nexus.
5039%
5040% The format of the SetPixelCacheNexusPixels() method is:
5041%
cristy4c08aed2011-07-01 19:47:50 +00005042% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005043% const RectangleInfo *region,NexusInfo *nexus_info,
5044% ExceptionInfo *exception)
5045%
5046% A description of each parameter follows:
5047%
5048% o image: the image.
5049%
5050% o region: A pointer to the RectangleInfo structure that defines the
5051% region of this particular cache nexus.
5052%
5053% o nexus_info: the cache nexus to set.
5054%
5055% o exception: return any errors or warnings in this structure.
5056%
5057*/
cristyabd6e372010-09-15 19:11:26 +00005058
5059static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5060 NexusInfo *nexus_info,ExceptionInfo *exception)
5061{
5062 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5063 return(MagickFalse);
5064 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005065 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005066 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005067 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005068 {
5069 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005070 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005071 nexus_info->length);
5072 }
cristy4c08aed2011-07-01 19:47:50 +00005073 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005074 {
5075 (void) ThrowMagickException(exception,GetMagickModule(),
5076 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5077 cache_info->filename);
5078 return(MagickFalse);
5079 }
5080 return(MagickTrue);
5081}
5082
cristy4c08aed2011-07-01 19:47:50 +00005083static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005084 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5085{
5086 CacheInfo
5087 *cache_info;
5088
5089 MagickBooleanType
5090 status;
5091
cristy3ed852e2009-09-05 21:47:34 +00005092 MagickSizeType
5093 length,
5094 number_pixels;
5095
cristy3ed852e2009-09-05 21:47:34 +00005096 cache_info=(CacheInfo *) image->cache;
5097 assert(cache_info->signature == MagickSignature);
5098 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005099 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005100 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005101 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5102 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005103 {
cristybb503372010-05-27 20:51:26 +00005104 ssize_t
cristybad067a2010-02-15 17:20:55 +00005105 x,
5106 y;
cristy3ed852e2009-09-05 21:47:34 +00005107
cristyeaedf062010-05-29 22:36:02 +00005108 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5109 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005110 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5111 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005112 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005113 ((nexus_info->region.width == cache_info->columns) ||
5114 ((nexus_info->region.width % cache_info->columns) == 0)))))
5115 {
5116 MagickOffsetType
5117 offset;
5118
5119 /*
5120 Pixels are accessed directly from memory.
5121 */
5122 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5123 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005124 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005125 offset;
5126 nexus_info->metacontent=(void *) NULL;
5127 if (cache_info->metacontent_extent != 0)
5128 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5129 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005130 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005131 }
5132 }
5133 /*
5134 Pixels are stored in a cache region until they are synced to the cache.
5135 */
5136 number_pixels=(MagickSizeType) nexus_info->region.width*
5137 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005138 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005139 if (cache_info->metacontent_extent != 0)
5140 length+=number_pixels*cache_info->metacontent_extent;
5141 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005142 {
5143 nexus_info->length=length;
5144 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5145 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005146 {
5147 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005148 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005149 }
cristy3ed852e2009-09-05 21:47:34 +00005150 }
5151 else
5152 if (nexus_info->length != length)
5153 {
5154 RelinquishCacheNexusPixels(nexus_info);
5155 nexus_info->length=length;
5156 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5157 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005158 {
5159 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005160 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005161 }
cristy3ed852e2009-09-05 21:47:34 +00005162 }
5163 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005164 nexus_info->metacontent=(void *) NULL;
5165 if (cache_info->metacontent_extent != 0)
5166 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005167 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005168 return(nexus_info->pixels);
5169}
5170
5171/*
5172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173% %
5174% %
5175% %
5176% 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 %
5177% %
5178% %
5179% %
5180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181%
5182% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5183% pixel cache and returns the previous setting. A virtual pixel is any pixel
5184% access that is outside the boundaries of the image cache.
5185%
5186% The format of the SetPixelCacheVirtualMethod() method is:
5187%
5188% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5189% const VirtualPixelMethod virtual_pixel_method)
5190%
5191% A description of each parameter follows:
5192%
5193% o image: the image.
5194%
5195% o virtual_pixel_method: choose the type of virtual pixel.
5196%
5197*/
cristyd1dd6e42011-09-04 01:46:08 +00005198MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005199 const VirtualPixelMethod virtual_pixel_method)
5200{
5201 CacheInfo
5202 *cache_info;
5203
5204 VirtualPixelMethod
5205 method;
5206
5207 assert(image != (Image *) NULL);
5208 assert(image->signature == MagickSignature);
5209 if (image->debug != MagickFalse)
5210 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5211 assert(image->cache != (Cache) NULL);
5212 cache_info=(CacheInfo *) image->cache;
5213 assert(cache_info->signature == MagickSignature);
5214 method=cache_info->virtual_pixel_method;
5215 cache_info->virtual_pixel_method=virtual_pixel_method;
5216 return(method);
5217}
5218
5219/*
5220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5221% %
5222% %
5223% %
5224+ 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 %
5225% %
5226% %
5227% %
5228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5229%
5230% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5231% in-memory or disk cache. The method returns MagickTrue if the pixel region
5232% is synced, otherwise MagickFalse.
5233%
5234% The format of the SyncAuthenticPixelCacheNexus() method is:
5235%
5236% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5237% NexusInfo *nexus_info,ExceptionInfo *exception)
5238%
5239% A description of each parameter follows:
5240%
5241% o image: the image.
5242%
5243% o nexus_info: the cache nexus to sync.
5244%
5245% o exception: return any errors or warnings in this structure.
5246%
5247*/
cristya6577ff2011-09-02 19:54:26 +00005248MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005249 NexusInfo *nexus_info,ExceptionInfo *exception)
5250{
5251 CacheInfo
5252 *cache_info;
5253
5254 MagickBooleanType
5255 status;
5256
5257 /*
5258 Transfer pixels to the cache.
5259 */
5260 assert(image != (Image *) NULL);
5261 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005262 if (image->cache == (Cache) NULL)
5263 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5264 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005265 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005266 if (cache_info->type == UndefinedCache)
5267 return(MagickFalse);
5268 if ((image->clip_mask != (Image *) NULL) &&
5269 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5270 return(MagickFalse);
5271 if ((image->mask != (Image *) NULL) &&
5272 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5273 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005274 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005275 return(MagickTrue);
5276 assert(cache_info->signature == MagickSignature);
5277 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005278 if ((cache_info->metacontent_extent != 0) &&
5279 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005280 return(MagickFalse);
5281 return(status);
5282}
5283
5284/*
5285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5286% %
5287% %
5288% %
5289+ S y n c A u t h e n t i c P i x e l C a c h e %
5290% %
5291% %
5292% %
5293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5294%
5295% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5296% or disk cache. The method returns MagickTrue if the pixel region is synced,
5297% otherwise MagickFalse.
5298%
5299% The format of the SyncAuthenticPixelsCache() method is:
5300%
5301% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5302% ExceptionInfo *exception)
5303%
5304% A description of each parameter follows:
5305%
5306% o image: the image.
5307%
5308% o exception: return any errors or warnings in this structure.
5309%
5310*/
5311static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5312 ExceptionInfo *exception)
5313{
5314 CacheInfo
5315 *cache_info;
5316
cristy5c9e6f22010-09-17 17:31:01 +00005317 const int
5318 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005319
cristy4c08aed2011-07-01 19:47:50 +00005320 MagickBooleanType
5321 status;
5322
cristye7cc7cf2010-09-21 13:26:47 +00005323 assert(image != (Image *) NULL);
5324 assert(image->signature == MagickSignature);
5325 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005326 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005327 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005328 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005329 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5330 exception);
5331 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005332}
5333
5334/*
5335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5336% %
5337% %
5338% %
5339% S y n c A u t h e n t i c P i x e l s %
5340% %
5341% %
5342% %
5343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5344%
5345% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5346% The method returns MagickTrue if the pixel region is flushed, otherwise
5347% MagickFalse.
5348%
5349% The format of the SyncAuthenticPixels() method is:
5350%
5351% MagickBooleanType SyncAuthenticPixels(Image *image,
5352% ExceptionInfo *exception)
5353%
5354% A description of each parameter follows:
5355%
5356% o image: the image.
5357%
5358% o exception: return any errors or warnings in this structure.
5359%
5360*/
5361MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5362 ExceptionInfo *exception)
5363{
5364 CacheInfo
5365 *cache_info;
5366
cristy2036f5c2010-09-19 21:18:17 +00005367 const int
5368 id = GetOpenMPThreadId();
5369
cristy4c08aed2011-07-01 19:47:50 +00005370 MagickBooleanType
5371 status;
5372
cristy3ed852e2009-09-05 21:47:34 +00005373 assert(image != (Image *) NULL);
5374 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005375 assert(image->cache != (Cache) NULL);
5376 cache_info=(CacheInfo *) image->cache;
5377 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005378 if (cache_info->methods.sync_authentic_pixels_handler !=
5379 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005380 {
5381 status=cache_info->methods.sync_authentic_pixels_handler(image,
5382 exception);
5383 return(status);
5384 }
cristy2036f5c2010-09-19 21:18:17 +00005385 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005386 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5387 exception);
5388 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005389}
5390
5391/*
5392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5393% %
5394% %
5395% %
cristyd1dd6e42011-09-04 01:46:08 +00005396+ 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 +00005397% %
5398% %
5399% %
5400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5401%
5402% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5403% The method returns MagickTrue if the pixel region is flushed, otherwise
5404% MagickFalse.
5405%
5406% The format of the SyncImagePixelCache() method is:
5407%
5408% MagickBooleanType SyncImagePixelCache(Image *image,
5409% ExceptionInfo *exception)
5410%
5411% A description of each parameter follows:
5412%
5413% o image: the image.
5414%
5415% o exception: return any errors or warnings in this structure.
5416%
5417*/
cristyd1dd6e42011-09-04 01:46:08 +00005418MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005419 ExceptionInfo *exception)
5420{
5421 CacheInfo
5422 *cache_info;
5423
5424 assert(image != (Image *) NULL);
5425 assert(exception != (ExceptionInfo *) NULL);
5426 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5427 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5428}
5429
5430/*
5431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5432% %
5433% %
5434% %
cristy4c08aed2011-07-01 19:47:50 +00005435+ 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 +00005436% %
5437% %
5438% %
5439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5440%
cristy4c08aed2011-07-01 19:47:50 +00005441% WritePixelCacheMetacontent() writes the meta-content to the specified region
5442% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005443%
cristy4c08aed2011-07-01 19:47:50 +00005444% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005445%
cristy4c08aed2011-07-01 19:47:50 +00005446% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005447% NexusInfo *nexus_info,ExceptionInfo *exception)
5448%
5449% A description of each parameter follows:
5450%
5451% o cache_info: the pixel cache.
5452%
cristy4c08aed2011-07-01 19:47:50 +00005453% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005454%
5455% o exception: return any errors or warnings in this structure.
5456%
5457*/
cristy4c08aed2011-07-01 19:47:50 +00005458static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005459 NexusInfo *nexus_info,ExceptionInfo *exception)
5460{
5461 MagickOffsetType
5462 count,
5463 offset;
5464
5465 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005466 extent,
5467 length;
cristy3ed852e2009-09-05 21:47:34 +00005468
cristy4c08aed2011-07-01 19:47:50 +00005469 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005470 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005471
cristybb503372010-05-27 20:51:26 +00005472 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005473 y;
5474
cristybb503372010-05-27 20:51:26 +00005475 size_t
cristy3ed852e2009-09-05 21:47:34 +00005476 rows;
5477
cristy4c08aed2011-07-01 19:47:50 +00005478 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005479 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005480 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005481 return(MagickTrue);
5482 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5483 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005484 length=(MagickSizeType) nexus_info->region.width*
5485 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005486 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005487 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005488 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005489 switch (cache_info->type)
5490 {
5491 case MemoryCache:
5492 case MapCache:
5493 {
cristy4c08aed2011-07-01 19:47:50 +00005494 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005495 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005496
5497 /*
cristy4c08aed2011-07-01 19:47:50 +00005498 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005499 */
cristydd341db2010-03-04 19:06:38 +00005500 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005501 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005502 {
cristy48078b12010-09-23 17:11:01 +00005503 length=extent;
cristydd341db2010-03-04 19:06:38 +00005504 rows=1UL;
5505 }
cristy4c08aed2011-07-01 19:47:50 +00005506 q=(unsigned char *) cache_info->metacontent+offset*
5507 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005508 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005509 {
cristy8f036fe2010-09-18 02:02:00 +00005510 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005511 p+=nexus_info->region.width*cache_info->metacontent_extent;
5512 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005513 }
5514 break;
5515 }
5516 case DiskCache:
5517 {
5518 /*
cristy4c08aed2011-07-01 19:47:50 +00005519 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005520 */
5521 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5522 {
5523 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5524 cache_info->cache_filename);
5525 return(MagickFalse);
5526 }
cristydd341db2010-03-04 19:06:38 +00005527 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005528 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005529 {
cristy48078b12010-09-23 17:11:01 +00005530 length=extent;
cristydd341db2010-03-04 19:06:38 +00005531 rows=1UL;
5532 }
cristy48078b12010-09-23 17:11:01 +00005533 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005534 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005535 {
cristy48078b12010-09-23 17:11:01 +00005536 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005537 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005538 cache_info->metacontent_extent,length,(const unsigned char *) p);
5539 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005540 break;
cristy4c08aed2011-07-01 19:47:50 +00005541 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005542 offset+=cache_info->columns;
5543 }
cristybb503372010-05-27 20:51:26 +00005544 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005545 {
5546 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5547 cache_info->cache_filename);
5548 return(MagickFalse);
5549 }
5550 break;
5551 }
5552 default:
5553 break;
5554 }
5555 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005556 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005557 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005558 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005559 nexus_info->region.width,(double) nexus_info->region.height,(double)
5560 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005561 return(MagickTrue);
5562}
5563
5564/*
5565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5566% %
5567% %
5568% %
5569+ W r i t e C a c h e P i x e l s %
5570% %
5571% %
5572% %
5573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5574%
5575% WritePixelCachePixels() writes image pixels to the specified region of the
5576% pixel cache.
5577%
5578% The format of the WritePixelCachePixels() method is:
5579%
5580% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5581% NexusInfo *nexus_info,ExceptionInfo *exception)
5582%
5583% A description of each parameter follows:
5584%
5585% o cache_info: the pixel cache.
5586%
5587% o nexus_info: the cache nexus to write the pixels.
5588%
5589% o exception: return any errors or warnings in this structure.
5590%
5591*/
5592static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5593 NexusInfo *nexus_info,ExceptionInfo *exception)
5594{
5595 MagickOffsetType
5596 count,
5597 offset;
5598
5599 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005600 extent,
5601 length;
cristy3ed852e2009-09-05 21:47:34 +00005602
cristy4c08aed2011-07-01 19:47:50 +00005603 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005604 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005605
cristybb503372010-05-27 20:51:26 +00005606 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005607 y;
5608
cristybb503372010-05-27 20:51:26 +00005609 size_t
cristy3ed852e2009-09-05 21:47:34 +00005610 rows;
5611
cristy4c08aed2011-07-01 19:47:50 +00005612 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005613 return(MagickTrue);
5614 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5615 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005616 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005617 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005618 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005619 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005620 p=nexus_info->pixels;
5621 switch (cache_info->type)
5622 {
5623 case MemoryCache:
5624 case MapCache:
5625 {
cristy4c08aed2011-07-01 19:47:50 +00005626 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005627 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005628
5629 /*
5630 Write pixels to memory.
5631 */
cristydd341db2010-03-04 19:06:38 +00005632 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005633 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005634 {
cristy48078b12010-09-23 17:11:01 +00005635 length=extent;
cristydd341db2010-03-04 19:06:38 +00005636 rows=1UL;
5637 }
cristyed231572011-07-14 02:18:59 +00005638 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005639 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005640 {
cristy8f036fe2010-09-18 02:02:00 +00005641 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005642 p+=nexus_info->region.width*cache_info->number_channels;
5643 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005644 }
5645 break;
5646 }
5647 case DiskCache:
5648 {
5649 /*
5650 Write pixels to disk.
5651 */
5652 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5653 {
5654 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5655 cache_info->cache_filename);
5656 return(MagickFalse);
5657 }
cristydd341db2010-03-04 19:06:38 +00005658 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005659 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005660 {
cristy48078b12010-09-23 17:11:01 +00005661 length=extent;
cristydd341db2010-03-04 19:06:38 +00005662 rows=1UL;
5663 }
cristybb503372010-05-27 20:51:26 +00005664 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005665 {
5666 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005667 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005668 p);
5669 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005670 break;
cristyed231572011-07-14 02:18:59 +00005671 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005672 offset+=cache_info->columns;
5673 }
cristybb503372010-05-27 20:51:26 +00005674 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005675 {
5676 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5677 cache_info->cache_filename);
5678 return(MagickFalse);
5679 }
5680 break;
5681 }
5682 default:
5683 break;
5684 }
5685 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005686 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005687 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005688 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005689 nexus_info->region.width,(double) nexus_info->region.height,(double)
5690 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005691 return(MagickTrue);
5692}