blob: 4c0e9b77d0ac63f08bac391fb9a72d7517425c95 [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);
cristyacd2ed22011-08-30 01:44:23 +00001659 q=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1660 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);
cristy3ed852e2009-09-05 21:47:34 +00004196 status=AcquireMagickResource(AreaResource,cache_info->length);
4197 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4198 cache_info->type=DiskCache;
4199 else
4200 {
4201 status=AcquireMagickResource(MapResource,cache_info->length);
4202 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4203 (cache_info->type != MemoryCache))
4204 cache_info->type=DiskCache;
4205 else
4206 {
cristy4c08aed2011-07-01 19:47:50 +00004207 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004208 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004209 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004210 {
cristy3ed852e2009-09-05 21:47:34 +00004211 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004212 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004213 }
4214 else
4215 {
4216 /*
4217 Create file-backed memory-mapped pixel cache.
4218 */
cristy4c08aed2011-07-01 19:47:50 +00004219 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004220 (void) ClosePixelCacheOnDisk(cache_info);
4221 cache_info->type=MapCache;
4222 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004223 cache_info->metacontent=(void *) NULL;
4224 if (cache_info->metacontent_extent != 0)
4225 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004226 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004227 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004228 {
4229 status=ClonePixelCachePixels(cache_info,&source_info,
4230 exception);
4231 RelinquishPixelCachePixels(&source_info);
4232 }
4233 if (image->debug != MagickFalse)
4234 {
cristy97e7a572009-12-05 15:07:53 +00004235 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004236 format);
cristyb51dff52011-05-19 16:55:47 +00004237 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004238 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004239 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004240 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004241 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004242 format);
cristy3ed852e2009-09-05 21:47:34 +00004243 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4244 message);
4245 }
cristy4c08aed2011-07-01 19:47:50 +00004246 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004247 }
4248 }
4249 RelinquishMagickResource(MapResource,cache_info->length);
4250 }
cristy4c08aed2011-07-01 19:47:50 +00004251 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004252 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4253 {
4254 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4255 RelinquishPixelCachePixels(&source_info);
4256 }
4257 if (image->debug != MagickFalse)
4258 {
cristyb9080c92009-12-01 20:13:26 +00004259 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004260 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004261 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004262 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004263 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004264 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004265 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4266 }
cristy4c08aed2011-07-01 19:47:50 +00004267 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004268}
4269
4270/*
4271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4272% %
4273% %
4274% %
4275+ P e r s i s t P i x e l C a c h e %
4276% %
4277% %
4278% %
4279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4280%
4281% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4282% persistent pixel cache is one that resides on disk and is not destroyed
4283% when the program exits.
4284%
4285% The format of the PersistPixelCache() method is:
4286%
4287% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4288% const MagickBooleanType attach,MagickOffsetType *offset,
4289% ExceptionInfo *exception)
4290%
4291% A description of each parameter follows:
4292%
4293% o image: the image.
4294%
4295% o filename: the persistent pixel cache filename.
4296%
cristyf3a6a9d2010-11-07 21:02:56 +00004297% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004298%
cristy3ed852e2009-09-05 21:47:34 +00004299% o initialize: A value other than zero initializes the persistent pixel
4300% cache.
4301%
4302% o offset: the offset in the persistent cache to store pixels.
4303%
4304% o exception: return any errors or warnings in this structure.
4305%
4306*/
4307MagickExport MagickBooleanType PersistPixelCache(Image *image,
4308 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4309 ExceptionInfo *exception)
4310{
4311 CacheInfo
4312 *cache_info,
4313 *clone_info;
4314
4315 Image
4316 clone_image;
4317
cristy3ed852e2009-09-05 21:47:34 +00004318 MagickBooleanType
4319 status;
4320
cristye076a6e2010-08-15 19:59:43 +00004321 ssize_t
4322 page_size;
4323
cristy3ed852e2009-09-05 21:47:34 +00004324 assert(image != (Image *) NULL);
4325 assert(image->signature == MagickSignature);
4326 if (image->debug != MagickFalse)
4327 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4328 assert(image->cache != (void *) NULL);
4329 assert(filename != (const char *) NULL);
4330 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004331 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004332 cache_info=(CacheInfo *) image->cache;
4333 assert(cache_info->signature == MagickSignature);
4334 if (attach != MagickFalse)
4335 {
4336 /*
cristy01b7eb02009-09-10 23:10:14 +00004337 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004338 */
4339 if (image->debug != MagickFalse)
4340 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004341 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004342 (void) CopyMagickString(cache_info->cache_filename,filename,
4343 MaxTextExtent);
4344 cache_info->type=DiskCache;
4345 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004346 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004347 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004348 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004349 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004350 }
cristy01b7eb02009-09-10 23:10:14 +00004351 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4352 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004353 {
cristyf84a1932010-01-03 18:00:18 +00004354 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004355 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004356 (cache_info->reference_count == 1))
4357 {
4358 int
4359 status;
4360
4361 /*
cristy01b7eb02009-09-10 23:10:14 +00004362 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004363 */
cristy320684d2011-09-23 14:55:47 +00004364 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004365 if (status == 0)
4366 {
4367 (void) CopyMagickString(cache_info->cache_filename,filename,
4368 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004369 *offset+=cache_info->length+page_size-(cache_info->length %
4370 page_size);
cristyf84a1932010-01-03 18:00:18 +00004371 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004372 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004373 if (image->debug != MagickFalse)
4374 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4375 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004376 return(MagickTrue);
4377 }
4378 }
cristyf84a1932010-01-03 18:00:18 +00004379 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004380 }
4381 /*
cristy01b7eb02009-09-10 23:10:14 +00004382 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004383 */
4384 clone_image=(*image);
4385 clone_info=(CacheInfo *) clone_image.cache;
4386 image->cache=ClonePixelCache(cache_info);
4387 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4388 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4389 cache_info->type=DiskCache;
4390 cache_info->offset=(*offset);
4391 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004392 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004393 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004394 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004395 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004396 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4397 return(status);
4398}
4399
4400/*
4401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4402% %
4403% %
4404% %
4405+ Q u e u e A u t h e n t i c N e x u s %
4406% %
4407% %
4408% %
4409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4410%
4411% QueueAuthenticNexus() allocates an region to store image pixels as defined
4412% by the region rectangle and returns a pointer to the region. This region is
4413% subsequently transferred from the pixel cache with
4414% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4415% pixels are transferred, otherwise a NULL is returned.
4416%
4417% The format of the QueueAuthenticNexus() method is:
4418%
cristy4c08aed2011-07-01 19:47:50 +00004419% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004420% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004421% NexusInfo *nexus_info,ExceptionInfo *exception)
4422%
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%
4432% o exception: return any errors or warnings in this structure.
4433%
4434*/
cristya6577ff2011-09-02 19:54:26 +00004435MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004436 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4437 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004438{
4439 CacheInfo
4440 *cache_info;
4441
4442 MagickOffsetType
4443 offset;
4444
4445 MagickSizeType
4446 number_pixels;
4447
4448 RectangleInfo
4449 region;
4450
4451 /*
4452 Validate pixel cache geometry.
4453 */
cristye7cc7cf2010-09-21 13:26:47 +00004454 assert(image != (const Image *) NULL);
4455 assert(image->signature == MagickSignature);
4456 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004457 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4458 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004459 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004460 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004461 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4462 {
4463 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4464 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004465 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004466 }
cristybb503372010-05-27 20:51:26 +00004467 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4468 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004469 {
4470 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4471 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004472 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004473 }
4474 offset=(MagickOffsetType) y*cache_info->columns+x;
4475 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004476 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004477 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4478 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4479 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004480 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004481 /*
4482 Return pixel cache.
4483 */
4484 region.x=x;
4485 region.y=y;
4486 region.width=columns;
4487 region.height=rows;
4488 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4489}
4490
4491/*
4492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493% %
4494% %
4495% %
4496+ 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 %
4497% %
4498% %
4499% %
4500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4501%
4502% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4503% defined by the region rectangle and returns a pointer to the region. This
4504% region is subsequently transferred from the pixel cache with
4505% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4506% pixels are transferred, otherwise a NULL is returned.
4507%
4508% The format of the QueueAuthenticPixelsCache() method is:
4509%
cristy4c08aed2011-07-01 19:47:50 +00004510% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004511% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004512% ExceptionInfo *exception)
4513%
4514% A description of each parameter follows:
4515%
4516% o image: the image.
4517%
4518% o x,y,columns,rows: These values define the perimeter of a region of
4519% pixels.
4520%
4521% o exception: return any errors or warnings in this structure.
4522%
4523*/
cristy4c08aed2011-07-01 19:47:50 +00004524static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004525 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004526 ExceptionInfo *exception)
4527{
4528 CacheInfo
4529 *cache_info;
4530
cristy5c9e6f22010-09-17 17:31:01 +00004531 const int
4532 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004533
cristy4c08aed2011-07-01 19:47:50 +00004534 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004535 *q;
cristy4c08aed2011-07-01 19:47:50 +00004536
cristye7cc7cf2010-09-21 13:26:47 +00004537 assert(image != (const Image *) NULL);
4538 assert(image->signature == MagickSignature);
4539 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004540 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004541 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004542 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00004543 q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
cristy4c08aed2011-07-01 19:47:50 +00004544 exception);
cristyacd2ed22011-08-30 01:44:23 +00004545 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004546}
4547
4548/*
4549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4550% %
4551% %
4552% %
4553% Q u e u e A u t h e n t i c P i x e l s %
4554% %
4555% %
4556% %
4557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4558%
4559% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004560% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004561% region is returned, otherwise NULL is returned. The returned pointer may
4562% point to a temporary working buffer for the pixels or it may point to the
4563% final location of the pixels in memory.
4564%
4565% Write-only access means that any existing pixel values corresponding to
4566% the region are ignored. This is useful if the initial image is being
4567% created from scratch, or if the existing pixel values are to be
4568% completely replaced without need to refer to their pre-existing values.
4569% The application is free to read and write the pixel buffer returned by
4570% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4571% initialize the pixel array values. Initializing pixel array values is the
4572% application's responsibility.
4573%
4574% Performance is maximized if the selected region is part of one row, or
4575% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004576% pixels in-place (without a copy) if the image is in memory, or in a
4577% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004578% by the user.
4579%
4580% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004581% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4582% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4583% obtain the meta-content (of type void) corresponding to the region.
4584% Once the Quantum (and/or Quantum) array has been updated, the
4585% changes must be saved back to the underlying image using
4586% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004587%
4588% The format of the QueueAuthenticPixels() method is:
4589%
cristy4c08aed2011-07-01 19:47:50 +00004590% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004591% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004592% ExceptionInfo *exception)
4593%
4594% A description of each parameter follows:
4595%
4596% o image: the image.
4597%
4598% o x,y,columns,rows: These values define the perimeter of a region of
4599% pixels.
4600%
4601% o exception: return any errors or warnings in this structure.
4602%
4603*/
cristy4c08aed2011-07-01 19:47:50 +00004604MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004605 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004606 ExceptionInfo *exception)
4607{
4608 CacheInfo
4609 *cache_info;
4610
cristy2036f5c2010-09-19 21:18:17 +00004611 const int
4612 id = GetOpenMPThreadId();
4613
cristy4c08aed2011-07-01 19:47:50 +00004614 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004615 *q;
cristy4c08aed2011-07-01 19:47:50 +00004616
cristy3ed852e2009-09-05 21:47:34 +00004617 assert(image != (Image *) NULL);
4618 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004619 assert(image->cache != (Cache) NULL);
4620 cache_info=(CacheInfo *) image->cache;
4621 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004622 if (cache_info->methods.queue_authentic_pixels_handler !=
4623 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004624 {
cristyacd2ed22011-08-30 01:44:23 +00004625 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004626 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004627 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004628 }
cristy2036f5c2010-09-19 21:18:17 +00004629 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00004630 q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
cristy4c08aed2011-07-01 19:47:50 +00004631 exception);
cristyacd2ed22011-08-30 01:44:23 +00004632 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004633}
4634
4635/*
4636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4637% %
4638% %
4639% %
cristy4c08aed2011-07-01 19:47:50 +00004640+ 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 +00004641% %
4642% %
4643% %
4644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4645%
cristy4c08aed2011-07-01 19:47:50 +00004646% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004647% the pixel cache.
4648%
cristy4c08aed2011-07-01 19:47:50 +00004649% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004650%
cristy4c08aed2011-07-01 19:47:50 +00004651% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004652% NexusInfo *nexus_info,ExceptionInfo *exception)
4653%
4654% A description of each parameter follows:
4655%
4656% o cache_info: the pixel cache.
4657%
cristy4c08aed2011-07-01 19:47:50 +00004658% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004659%
4660% o exception: return any errors or warnings in this structure.
4661%
4662*/
cristy4c08aed2011-07-01 19:47:50 +00004663static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004664 NexusInfo *nexus_info,ExceptionInfo *exception)
4665{
4666 MagickOffsetType
4667 count,
4668 offset;
4669
4670 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004671 extent,
4672 length;
cristy3ed852e2009-09-05 21:47:34 +00004673
cristybb503372010-05-27 20:51:26 +00004674 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004675 y;
4676
cristy4c08aed2011-07-01 19:47:50 +00004677 register unsigned char
4678 *restrict q;
4679
cristybb503372010-05-27 20:51:26 +00004680 size_t
cristy3ed852e2009-09-05 21:47:34 +00004681 rows;
4682
cristy4c08aed2011-07-01 19:47:50 +00004683 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004684 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004685 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004686 return(MagickTrue);
4687 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4688 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004689 length=(MagickSizeType) nexus_info->region.width*
4690 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004691 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004692 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004693 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004694 switch (cache_info->type)
4695 {
4696 case MemoryCache:
4697 case MapCache:
4698 {
cristy4c08aed2011-07-01 19:47:50 +00004699 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004700 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004701
4702 /*
cristy4c08aed2011-07-01 19:47:50 +00004703 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004704 */
cristydd341db2010-03-04 19:06:38 +00004705 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004706 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004707 {
cristy48078b12010-09-23 17:11:01 +00004708 length=extent;
cristydd341db2010-03-04 19:06:38 +00004709 rows=1UL;
4710 }
cristy4c08aed2011-07-01 19:47:50 +00004711 p=(unsigned char *) cache_info->metacontent+offset*
4712 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004713 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004714 {
cristy8f036fe2010-09-18 02:02:00 +00004715 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004716 p+=cache_info->metacontent_extent*cache_info->columns;
4717 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004718 }
4719 break;
4720 }
4721 case DiskCache:
4722 {
4723 /*
cristy4c08aed2011-07-01 19:47:50 +00004724 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004725 */
4726 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4727 {
4728 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4729 cache_info->cache_filename);
4730 return(MagickFalse);
4731 }
cristydd341db2010-03-04 19:06:38 +00004732 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004733 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004734 {
cristy48078b12010-09-23 17:11:01 +00004735 length=extent;
cristydd341db2010-03-04 19:06:38 +00004736 rows=1UL;
4737 }
cristy48078b12010-09-23 17:11:01 +00004738 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004739 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004740 {
cristy48078b12010-09-23 17:11:01 +00004741 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004742 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004743 cache_info->metacontent_extent,length,(unsigned char *) q);
4744 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004745 break;
4746 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004747 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004748 }
cristybb503372010-05-27 20:51:26 +00004749 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004750 {
4751 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4752 cache_info->cache_filename);
4753 return(MagickFalse);
4754 }
4755 break;
4756 }
4757 default:
4758 break;
4759 }
4760 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004761 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004762 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004763 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004764 nexus_info->region.width,(double) nexus_info->region.height,(double)
4765 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004766 return(MagickTrue);
4767}
4768
4769/*
4770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4771% %
4772% %
4773% %
4774+ R e a d P i x e l C a c h e P i x e l s %
4775% %
4776% %
4777% %
4778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4779%
4780% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4781% cache.
4782%
4783% The format of the ReadPixelCachePixels() method is:
4784%
4785% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4786% NexusInfo *nexus_info,ExceptionInfo *exception)
4787%
4788% A description of each parameter follows:
4789%
4790% o cache_info: the pixel cache.
4791%
4792% o nexus_info: the cache nexus to read the pixels.
4793%
4794% o exception: return any errors or warnings in this structure.
4795%
4796*/
4797static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4798 NexusInfo *nexus_info,ExceptionInfo *exception)
4799{
4800 MagickOffsetType
4801 count,
4802 offset;
4803
4804 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004805 extent,
4806 length;
cristy3ed852e2009-09-05 21:47:34 +00004807
cristy4c08aed2011-07-01 19:47:50 +00004808 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004809 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004810
cristye076a6e2010-08-15 19:59:43 +00004811 register ssize_t
4812 y;
4813
cristybb503372010-05-27 20:51:26 +00004814 size_t
cristy3ed852e2009-09-05 21:47:34 +00004815 rows;
4816
cristy4c08aed2011-07-01 19:47:50 +00004817 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004818 return(MagickTrue);
4819 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4820 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004821 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004822 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004823 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004824 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004825 q=nexus_info->pixels;
4826 switch (cache_info->type)
4827 {
4828 case MemoryCache:
4829 case MapCache:
4830 {
cristy4c08aed2011-07-01 19:47:50 +00004831 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004832 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004833
4834 /*
4835 Read pixels from memory.
4836 */
cristydd341db2010-03-04 19:06:38 +00004837 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004838 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004839 {
cristy48078b12010-09-23 17:11:01 +00004840 length=extent;
cristydd341db2010-03-04 19:06:38 +00004841 rows=1UL;
4842 }
cristyed231572011-07-14 02:18:59 +00004843 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004844 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004845 {
cristy8f036fe2010-09-18 02:02:00 +00004846 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004847 p+=cache_info->number_channels*cache_info->columns;
4848 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004849 }
4850 break;
4851 }
4852 case DiskCache:
4853 {
4854 /*
4855 Read pixels from disk.
4856 */
4857 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4858 {
4859 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4860 cache_info->cache_filename);
4861 return(MagickFalse);
4862 }
cristydd341db2010-03-04 19:06:38 +00004863 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004864 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004865 {
cristy48078b12010-09-23 17:11:01 +00004866 length=extent;
cristydd341db2010-03-04 19:06:38 +00004867 rows=1UL;
4868 }
cristybb503372010-05-27 20:51:26 +00004869 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004870 {
4871 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004872 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004873 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004874 break;
4875 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004876 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004877 }
cristybb503372010-05-27 20:51:26 +00004878 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004879 {
4880 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4881 cache_info->cache_filename);
4882 return(MagickFalse);
4883 }
4884 break;
4885 }
4886 default:
4887 break;
4888 }
4889 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004890 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004891 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004892 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004893 nexus_info->region.width,(double) nexus_info->region.height,(double)
4894 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004895 return(MagickTrue);
4896}
4897
4898/*
4899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4900% %
4901% %
4902% %
4903+ R e f e r e n c e P i x e l C a c h e %
4904% %
4905% %
4906% %
4907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4908%
4909% ReferencePixelCache() increments the reference count associated with the
4910% pixel cache returning a pointer to the cache.
4911%
4912% The format of the ReferencePixelCache method is:
4913%
4914% Cache ReferencePixelCache(Cache cache_info)
4915%
4916% A description of each parameter follows:
4917%
4918% o cache_info: the pixel cache.
4919%
4920*/
cristya6577ff2011-09-02 19:54:26 +00004921MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004922{
4923 CacheInfo
4924 *cache_info;
4925
4926 assert(cache != (Cache *) NULL);
4927 cache_info=(CacheInfo *) cache;
4928 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004929 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004930 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004931 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004932 return(cache_info);
4933}
4934
4935/*
4936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4937% %
4938% %
4939% %
4940+ S e t P i x e l C a c h e M e t h o d s %
4941% %
4942% %
4943% %
4944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4945%
4946% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4947%
4948% The format of the SetPixelCacheMethods() method is:
4949%
4950% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4951%
4952% A description of each parameter follows:
4953%
4954% o cache: the pixel cache.
4955%
4956% o cache_methods: Specifies a pointer to a CacheMethods structure.
4957%
4958*/
cristya6577ff2011-09-02 19:54:26 +00004959MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004960{
4961 CacheInfo
4962 *cache_info;
4963
4964 GetOneAuthenticPixelFromHandler
4965 get_one_authentic_pixel_from_handler;
4966
4967 GetOneVirtualPixelFromHandler
4968 get_one_virtual_pixel_from_handler;
4969
4970 /*
4971 Set cache pixel methods.
4972 */
4973 assert(cache != (Cache) NULL);
4974 assert(cache_methods != (CacheMethods *) NULL);
4975 cache_info=(CacheInfo *) cache;
4976 assert(cache_info->signature == MagickSignature);
4977 if (cache_info->debug != MagickFalse)
4978 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4979 cache_info->filename);
4980 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4981 cache_info->methods.get_virtual_pixel_handler=
4982 cache_methods->get_virtual_pixel_handler;
4983 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4984 cache_info->methods.destroy_pixel_handler=
4985 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004986 if (cache_methods->get_virtual_metacontent_from_handler !=
4987 (GetVirtualMetacontentFromHandler) NULL)
4988 cache_info->methods.get_virtual_metacontent_from_handler=
4989 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004990 if (cache_methods->get_authentic_pixels_handler !=
4991 (GetAuthenticPixelsHandler) NULL)
4992 cache_info->methods.get_authentic_pixels_handler=
4993 cache_methods->get_authentic_pixels_handler;
4994 if (cache_methods->queue_authentic_pixels_handler !=
4995 (QueueAuthenticPixelsHandler) NULL)
4996 cache_info->methods.queue_authentic_pixels_handler=
4997 cache_methods->queue_authentic_pixels_handler;
4998 if (cache_methods->sync_authentic_pixels_handler !=
4999 (SyncAuthenticPixelsHandler) NULL)
5000 cache_info->methods.sync_authentic_pixels_handler=
5001 cache_methods->sync_authentic_pixels_handler;
5002 if (cache_methods->get_authentic_pixels_from_handler !=
5003 (GetAuthenticPixelsFromHandler) NULL)
5004 cache_info->methods.get_authentic_pixels_from_handler=
5005 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00005006 if (cache_methods->get_authentic_metacontent_from_handler !=
5007 (GetAuthenticMetacontentFromHandler) NULL)
5008 cache_info->methods.get_authentic_metacontent_from_handler=
5009 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00005010 get_one_virtual_pixel_from_handler=
5011 cache_info->methods.get_one_virtual_pixel_from_handler;
5012 if (get_one_virtual_pixel_from_handler !=
5013 (GetOneVirtualPixelFromHandler) NULL)
5014 cache_info->methods.get_one_virtual_pixel_from_handler=
5015 cache_methods->get_one_virtual_pixel_from_handler;
5016 get_one_authentic_pixel_from_handler=
5017 cache_methods->get_one_authentic_pixel_from_handler;
5018 if (get_one_authentic_pixel_from_handler !=
5019 (GetOneAuthenticPixelFromHandler) NULL)
5020 cache_info->methods.get_one_authentic_pixel_from_handler=
5021 cache_methods->get_one_authentic_pixel_from_handler;
5022}
5023
5024/*
5025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5026% %
5027% %
5028% %
5029+ S e t P i x e l C a c h e N e x u s P i x e l s %
5030% %
5031% %
5032% %
5033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5034%
5035% SetPixelCacheNexusPixels() defines the region of the cache for the
5036% specified cache nexus.
5037%
5038% The format of the SetPixelCacheNexusPixels() method is:
5039%
cristy4c08aed2011-07-01 19:47:50 +00005040% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005041% const RectangleInfo *region,NexusInfo *nexus_info,
5042% ExceptionInfo *exception)
5043%
5044% A description of each parameter follows:
5045%
5046% o image: the image.
5047%
5048% o region: A pointer to the RectangleInfo structure that defines the
5049% region of this particular cache nexus.
5050%
5051% o nexus_info: the cache nexus to set.
5052%
5053% o exception: return any errors or warnings in this structure.
5054%
5055*/
cristyabd6e372010-09-15 19:11:26 +00005056
5057static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5058 NexusInfo *nexus_info,ExceptionInfo *exception)
5059{
5060 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5061 return(MagickFalse);
5062 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005063 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005064 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005065 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005066 {
5067 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005068 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005069 nexus_info->length);
5070 }
cristy4c08aed2011-07-01 19:47:50 +00005071 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005072 {
5073 (void) ThrowMagickException(exception,GetMagickModule(),
5074 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5075 cache_info->filename);
5076 return(MagickFalse);
5077 }
5078 return(MagickTrue);
5079}
5080
cristy4c08aed2011-07-01 19:47:50 +00005081static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005082 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5083{
5084 CacheInfo
5085 *cache_info;
5086
5087 MagickBooleanType
5088 status;
5089
cristy3ed852e2009-09-05 21:47:34 +00005090 MagickSizeType
5091 length,
5092 number_pixels;
5093
cristy3ed852e2009-09-05 21:47:34 +00005094 cache_info=(CacheInfo *) image->cache;
5095 assert(cache_info->signature == MagickSignature);
5096 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005097 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005098 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005099 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5100 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005101 {
cristybb503372010-05-27 20:51:26 +00005102 ssize_t
cristybad067a2010-02-15 17:20:55 +00005103 x,
5104 y;
cristy3ed852e2009-09-05 21:47:34 +00005105
cristyeaedf062010-05-29 22:36:02 +00005106 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5107 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005108 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5109 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005110 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005111 ((nexus_info->region.width == cache_info->columns) ||
5112 ((nexus_info->region.width % cache_info->columns) == 0)))))
5113 {
5114 MagickOffsetType
5115 offset;
5116
5117 /*
5118 Pixels are accessed directly from memory.
5119 */
5120 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5121 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005122 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005123 offset;
5124 nexus_info->metacontent=(void *) NULL;
5125 if (cache_info->metacontent_extent != 0)
5126 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5127 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005128 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005129 }
5130 }
5131 /*
5132 Pixels are stored in a cache region until they are synced to the cache.
5133 */
5134 number_pixels=(MagickSizeType) nexus_info->region.width*
5135 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005136 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005137 if (cache_info->metacontent_extent != 0)
5138 length+=number_pixels*cache_info->metacontent_extent;
5139 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005140 {
5141 nexus_info->length=length;
5142 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5143 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005144 {
5145 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005146 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005147 }
cristy3ed852e2009-09-05 21:47:34 +00005148 }
5149 else
5150 if (nexus_info->length != length)
5151 {
5152 RelinquishCacheNexusPixels(nexus_info);
5153 nexus_info->length=length;
5154 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5155 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005156 {
5157 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005158 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005159 }
cristy3ed852e2009-09-05 21:47:34 +00005160 }
5161 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005162 nexus_info->metacontent=(void *) NULL;
5163 if (cache_info->metacontent_extent != 0)
5164 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005165 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005166 return(nexus_info->pixels);
5167}
5168
5169/*
5170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5171% %
5172% %
5173% %
5174% 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 %
5175% %
5176% %
5177% %
5178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179%
5180% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5181% pixel cache and returns the previous setting. A virtual pixel is any pixel
5182% access that is outside the boundaries of the image cache.
5183%
5184% The format of the SetPixelCacheVirtualMethod() method is:
5185%
5186% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5187% const VirtualPixelMethod virtual_pixel_method)
5188%
5189% A description of each parameter follows:
5190%
5191% o image: the image.
5192%
5193% o virtual_pixel_method: choose the type of virtual pixel.
5194%
5195*/
cristyd1dd6e42011-09-04 01:46:08 +00005196MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005197 const VirtualPixelMethod virtual_pixel_method)
5198{
5199 CacheInfo
5200 *cache_info;
5201
5202 VirtualPixelMethod
5203 method;
5204
5205 assert(image != (Image *) NULL);
5206 assert(image->signature == MagickSignature);
5207 if (image->debug != MagickFalse)
5208 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5209 assert(image->cache != (Cache) NULL);
5210 cache_info=(CacheInfo *) image->cache;
5211 assert(cache_info->signature == MagickSignature);
5212 method=cache_info->virtual_pixel_method;
5213 cache_info->virtual_pixel_method=virtual_pixel_method;
5214 return(method);
5215}
5216
5217/*
5218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5219% %
5220% %
5221% %
5222+ 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 %
5223% %
5224% %
5225% %
5226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5227%
5228% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5229% in-memory or disk cache. The method returns MagickTrue if the pixel region
5230% is synced, otherwise MagickFalse.
5231%
5232% The format of the SyncAuthenticPixelCacheNexus() method is:
5233%
5234% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5235% NexusInfo *nexus_info,ExceptionInfo *exception)
5236%
5237% A description of each parameter follows:
5238%
5239% o image: the image.
5240%
5241% o nexus_info: the cache nexus to sync.
5242%
5243% o exception: return any errors or warnings in this structure.
5244%
5245*/
cristya6577ff2011-09-02 19:54:26 +00005246MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005247 NexusInfo *nexus_info,ExceptionInfo *exception)
5248{
5249 CacheInfo
5250 *cache_info;
5251
5252 MagickBooleanType
5253 status;
5254
5255 /*
5256 Transfer pixels to the cache.
5257 */
5258 assert(image != (Image *) NULL);
5259 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005260 if (image->cache == (Cache) NULL)
5261 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5262 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005263 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005264 if (cache_info->type == UndefinedCache)
5265 return(MagickFalse);
5266 if ((image->clip_mask != (Image *) NULL) &&
5267 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5268 return(MagickFalse);
5269 if ((image->mask != (Image *) NULL) &&
5270 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5271 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005272 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005273 return(MagickTrue);
5274 assert(cache_info->signature == MagickSignature);
5275 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005276 if ((cache_info->metacontent_extent != 0) &&
5277 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005278 return(MagickFalse);
5279 return(status);
5280}
5281
5282/*
5283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5284% %
5285% %
5286% %
5287+ S y n c A u t h e n t i c P i x e l C a c h e %
5288% %
5289% %
5290% %
5291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5292%
5293% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5294% or disk cache. The method returns MagickTrue if the pixel region is synced,
5295% otherwise MagickFalse.
5296%
5297% The format of the SyncAuthenticPixelsCache() method is:
5298%
5299% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5300% ExceptionInfo *exception)
5301%
5302% A description of each parameter follows:
5303%
5304% o image: the image.
5305%
5306% o exception: return any errors or warnings in this structure.
5307%
5308*/
5309static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5310 ExceptionInfo *exception)
5311{
5312 CacheInfo
5313 *cache_info;
5314
cristy5c9e6f22010-09-17 17:31:01 +00005315 const int
5316 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005317
cristy4c08aed2011-07-01 19:47:50 +00005318 MagickBooleanType
5319 status;
5320
cristye7cc7cf2010-09-21 13:26:47 +00005321 assert(image != (Image *) NULL);
5322 assert(image->signature == MagickSignature);
5323 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005324 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005325 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005326 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005327 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5328 exception);
5329 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005330}
5331
5332/*
5333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5334% %
5335% %
5336% %
5337% S y n c A u t h e n t i c P i x e l s %
5338% %
5339% %
5340% %
5341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5342%
5343% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5344% The method returns MagickTrue if the pixel region is flushed, otherwise
5345% MagickFalse.
5346%
5347% The format of the SyncAuthenticPixels() method is:
5348%
5349% MagickBooleanType SyncAuthenticPixels(Image *image,
5350% ExceptionInfo *exception)
5351%
5352% A description of each parameter follows:
5353%
5354% o image: the image.
5355%
5356% o exception: return any errors or warnings in this structure.
5357%
5358*/
5359MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5360 ExceptionInfo *exception)
5361{
5362 CacheInfo
5363 *cache_info;
5364
cristy2036f5c2010-09-19 21:18:17 +00005365 const int
5366 id = GetOpenMPThreadId();
5367
cristy4c08aed2011-07-01 19:47:50 +00005368 MagickBooleanType
5369 status;
5370
cristy3ed852e2009-09-05 21:47:34 +00005371 assert(image != (Image *) NULL);
5372 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005373 assert(image->cache != (Cache) NULL);
5374 cache_info=(CacheInfo *) image->cache;
5375 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005376 if (cache_info->methods.sync_authentic_pixels_handler !=
5377 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005378 {
5379 status=cache_info->methods.sync_authentic_pixels_handler(image,
5380 exception);
5381 return(status);
5382 }
cristy2036f5c2010-09-19 21:18:17 +00005383 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005384 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5385 exception);
5386 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005387}
5388
5389/*
5390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5391% %
5392% %
5393% %
cristyd1dd6e42011-09-04 01:46:08 +00005394+ 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 +00005395% %
5396% %
5397% %
5398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5399%
5400% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5401% The method returns MagickTrue if the pixel region is flushed, otherwise
5402% MagickFalse.
5403%
5404% The format of the SyncImagePixelCache() method is:
5405%
5406% MagickBooleanType SyncImagePixelCache(Image *image,
5407% ExceptionInfo *exception)
5408%
5409% A description of each parameter follows:
5410%
5411% o image: the image.
5412%
5413% o exception: return any errors or warnings in this structure.
5414%
5415*/
cristyd1dd6e42011-09-04 01:46:08 +00005416MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005417 ExceptionInfo *exception)
5418{
5419 CacheInfo
5420 *cache_info;
5421
5422 assert(image != (Image *) NULL);
5423 assert(exception != (ExceptionInfo *) NULL);
5424 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5425 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5426}
5427
5428/*
5429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5430% %
5431% %
5432% %
cristy4c08aed2011-07-01 19:47:50 +00005433+ 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 +00005434% %
5435% %
5436% %
5437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5438%
cristy4c08aed2011-07-01 19:47:50 +00005439% WritePixelCacheMetacontent() writes the meta-content to the specified region
5440% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005441%
cristy4c08aed2011-07-01 19:47:50 +00005442% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005443%
cristy4c08aed2011-07-01 19:47:50 +00005444% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005445% NexusInfo *nexus_info,ExceptionInfo *exception)
5446%
5447% A description of each parameter follows:
5448%
5449% o cache_info: the pixel cache.
5450%
cristy4c08aed2011-07-01 19:47:50 +00005451% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005452%
5453% o exception: return any errors or warnings in this structure.
5454%
5455*/
cristy4c08aed2011-07-01 19:47:50 +00005456static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005457 NexusInfo *nexus_info,ExceptionInfo *exception)
5458{
5459 MagickOffsetType
5460 count,
5461 offset;
5462
5463 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005464 extent,
5465 length;
cristy3ed852e2009-09-05 21:47:34 +00005466
cristy4c08aed2011-07-01 19:47:50 +00005467 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005468 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005469
cristybb503372010-05-27 20:51:26 +00005470 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005471 y;
5472
cristybb503372010-05-27 20:51:26 +00005473 size_t
cristy3ed852e2009-09-05 21:47:34 +00005474 rows;
5475
cristy4c08aed2011-07-01 19:47:50 +00005476 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005477 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005478 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005479 return(MagickTrue);
5480 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5481 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005482 length=(MagickSizeType) nexus_info->region.width*
5483 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005484 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005485 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005486 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005487 switch (cache_info->type)
5488 {
5489 case MemoryCache:
5490 case MapCache:
5491 {
cristy4c08aed2011-07-01 19:47:50 +00005492 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005493 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005494
5495 /*
cristy4c08aed2011-07-01 19:47:50 +00005496 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005497 */
cristydd341db2010-03-04 19:06:38 +00005498 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005499 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005500 {
cristy48078b12010-09-23 17:11:01 +00005501 length=extent;
cristydd341db2010-03-04 19:06:38 +00005502 rows=1UL;
5503 }
cristy4c08aed2011-07-01 19:47:50 +00005504 q=(unsigned char *) cache_info->metacontent+offset*
5505 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005506 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005507 {
cristy8f036fe2010-09-18 02:02:00 +00005508 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005509 p+=nexus_info->region.width*cache_info->metacontent_extent;
5510 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005511 }
5512 break;
5513 }
5514 case DiskCache:
5515 {
5516 /*
cristy4c08aed2011-07-01 19:47:50 +00005517 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005518 */
5519 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5520 {
5521 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5522 cache_info->cache_filename);
5523 return(MagickFalse);
5524 }
cristydd341db2010-03-04 19:06:38 +00005525 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005526 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005527 {
cristy48078b12010-09-23 17:11:01 +00005528 length=extent;
cristydd341db2010-03-04 19:06:38 +00005529 rows=1UL;
5530 }
cristy48078b12010-09-23 17:11:01 +00005531 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005532 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005533 {
cristy48078b12010-09-23 17:11:01 +00005534 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005535 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005536 cache_info->metacontent_extent,length,(const unsigned char *) p);
5537 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005538 break;
cristy4c08aed2011-07-01 19:47:50 +00005539 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005540 offset+=cache_info->columns;
5541 }
cristybb503372010-05-27 20:51:26 +00005542 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005543 {
5544 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5545 cache_info->cache_filename);
5546 return(MagickFalse);
5547 }
5548 break;
5549 }
5550 default:
5551 break;
5552 }
5553 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005554 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005555 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005556 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005557 nexus_info->region.width,(double) nexus_info->region.height,(double)
5558 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005559 return(MagickTrue);
5560}
5561
5562/*
5563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5564% %
5565% %
5566% %
5567+ W r i t e C a c h e P i x e l s %
5568% %
5569% %
5570% %
5571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5572%
5573% WritePixelCachePixels() writes image pixels to the specified region of the
5574% pixel cache.
5575%
5576% The format of the WritePixelCachePixels() method is:
5577%
5578% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5579% NexusInfo *nexus_info,ExceptionInfo *exception)
5580%
5581% A description of each parameter follows:
5582%
5583% o cache_info: the pixel cache.
5584%
5585% o nexus_info: the cache nexus to write the pixels.
5586%
5587% o exception: return any errors or warnings in this structure.
5588%
5589*/
5590static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5591 NexusInfo *nexus_info,ExceptionInfo *exception)
5592{
5593 MagickOffsetType
5594 count,
5595 offset;
5596
5597 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005598 extent,
5599 length;
cristy3ed852e2009-09-05 21:47:34 +00005600
cristy4c08aed2011-07-01 19:47:50 +00005601 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005602 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005603
cristybb503372010-05-27 20:51:26 +00005604 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005605 y;
5606
cristybb503372010-05-27 20:51:26 +00005607 size_t
cristy3ed852e2009-09-05 21:47:34 +00005608 rows;
5609
cristy4c08aed2011-07-01 19:47:50 +00005610 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005611 return(MagickTrue);
5612 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5613 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005614 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005615 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005616 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005617 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005618 p=nexus_info->pixels;
5619 switch (cache_info->type)
5620 {
5621 case MemoryCache:
5622 case MapCache:
5623 {
cristy4c08aed2011-07-01 19:47:50 +00005624 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005625 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005626
5627 /*
5628 Write pixels to memory.
5629 */
cristydd341db2010-03-04 19:06:38 +00005630 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005631 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005632 {
cristy48078b12010-09-23 17:11:01 +00005633 length=extent;
cristydd341db2010-03-04 19:06:38 +00005634 rows=1UL;
5635 }
cristyed231572011-07-14 02:18:59 +00005636 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005637 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005638 {
cristy8f036fe2010-09-18 02:02:00 +00005639 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005640 p+=nexus_info->region.width*cache_info->number_channels;
5641 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005642 }
5643 break;
5644 }
5645 case DiskCache:
5646 {
5647 /*
5648 Write pixels to disk.
5649 */
5650 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5651 {
5652 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5653 cache_info->cache_filename);
5654 return(MagickFalse);
5655 }
cristydd341db2010-03-04 19:06:38 +00005656 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005657 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005658 {
cristy48078b12010-09-23 17:11:01 +00005659 length=extent;
cristydd341db2010-03-04 19:06:38 +00005660 rows=1UL;
5661 }
cristybb503372010-05-27 20:51:26 +00005662 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005663 {
5664 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005665 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005666 p);
5667 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005668 break;
cristyed231572011-07-14 02:18:59 +00005669 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005670 offset+=cache_info->columns;
5671 }
cristybb503372010-05-27 20:51:26 +00005672 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005673 {
5674 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5675 cache_info->cache_filename);
5676 return(MagickFalse);
5677 }
5678 break;
5679 }
5680 default:
5681 break;
5682 }
5683 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005684 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005685 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005686 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005687 nexus_info->region.width,(double) nexus_info->region.height,(double)
5688 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005689 return(MagickTrue);
5690}