blob: 63c806354f1ded29ec3a4bfa6627a1fd40b32644 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78
79/*
cristy3ed852e2009-09-05 21:47:34 +000080 Typedef declarations.
81*/
82typedef struct _MagickModulo
83{
cristybb503372010-05-27 20:51:26 +000084 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000085 quotient,
86 remainder;
87} MagickModulo;
88
89struct _NexusInfo
90{
91 MagickBooleanType
92 mapped;
93
94 RectangleInfo
95 region;
96
97 MagickSizeType
98 length;
99
cristy4c08aed2011-07-01 19:47:50 +0000100 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000101 *cache,
102 *pixels;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 void
105 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000106
cristybb503372010-05-27 20:51:26 +0000107 size_t
cristy3ed852e2009-09-05 21:47:34 +0000108 signature;
109};
110
111/*
112 Forward declarations.
113*/
114#if defined(__cplusplus) || defined(c_plusplus)
115extern "C" {
116#endif
117
cristy4c08aed2011-07-01 19:47:50 +0000118static const Quantum
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
cristy4c08aed2011-07-01 19:47:50 +0000123static const void
124 *GetVirtualMetacontentFromCache(const Image *);
125
cristy3ed852e2009-09-05 21:47:34 +0000126static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000128 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
137
cristy4c08aed2011-07-01 19:47:50 +0000138static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000144 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146#if defined(__cplusplus) || defined(c_plusplus)
147}
148#endif
149
150/*
151 Global declarations.
152*/
153static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
155
156static SemaphoreInfo
157 *cache_semaphore = (SemaphoreInfo *) NULL;
158
159static SplayTreeInfo
160 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167+ A c q u i r e P i x e l C a c h e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquirePixelCache() acquires a pixel cache.
174%
175% The format of the AcquirePixelCache() method is:
176%
cristybb503372010-05-27 20:51:26 +0000177% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178%
179% A description of each parameter follows:
180%
181% o number_threads: the number of nexus threads.
182%
183*/
cristya6577ff2011-09-02 19:54:26 +0000184MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000185{
186 CacheInfo
187 *cache_info;
188
cristya64b85d2011-09-14 01:02:31 +0000189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000194 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristya6577ff2011-09-02 19:54:26 +0000250MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristya64b85d2011-09-14 01:02:31 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
cristyd1dd6e42011-09-04 01:46:08 +0000301MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
cristy5ff4eaf2011-09-03 01:38:02 +0000339MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
cristy5ff4eaf2011-09-03 01:38:02 +0000363MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000387% mask. It returns MagickTrue if the pixel region is clipped, otherwise
388% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
cristy4c08aed2011-07-01 19:47:50 +0000417 register const Quantum
418 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristy4c08aed2011-07-01 19:47:50 +0000421 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristye076a6e2010-08-15 19:59:43 +0000424 register ssize_t
425 i;
426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
428 Apply clip mask.
429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000434 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000445 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000451 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy4c08aed2011-07-01 19:47:50 +0000453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000454 break;
cristy4c08aed2011-07-01 19:47:50 +0000455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000456 {
cristy4c08aed2011-07-01 19:47:50 +0000457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000463 }
cristyed231572011-07-14 02:18:59 +0000464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000467 }
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000470 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000471 return(MagickFalse);
472 return(MagickTrue);
473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
480+ C l o n e P i x e l C a c h e %
481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
486% ClonePixelCache() clones a pixel cache.
487%
488% The format of the ClonePixelCache() method is:
489%
490% Cache ClonePixelCache(const Cache cache)
491%
492% A description of each parameter follows:
493%
494% o cache: the pixel cache.
495%
496*/
cristya6577ff2011-09-02 19:54:26 +0000497MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000498{
499 CacheInfo
500 *clone_info;
501
502 const CacheInfo
503 *cache_info;
504
cristy9f027d12011-09-21 01:17:17 +0000505 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
516}
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520% %
521% %
522% %
cristy60c44a82009-10-07 00:58:49 +0000523+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000524% %
525% %
526% %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528% ClonePixelCachePixels() clones the source pixel cache to the destination
529% cache.
530%
531% The format of the ClonePixelCachePixels() method is:
532%
533% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534% CacheInfo *source_info,ExceptionInfo *exception)
535%
536% A description of each parameter follows:
537%
538% o cache_info: the pixel cache.
539%
540% o source_info: the source pixel cache.
541%
542% o exception: return any errors or warnings in this structure.
543%
544*/
545
546static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
547{
548 int
549 status;
550
cristy5ee247a2010-02-12 15:42:34 +0000551 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000552 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000553 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000554 {
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
558 }
cristyf84a1932010-01-03 18:00:18 +0000559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000560 return(status == -1 ? MagickFalse : MagickTrue);
561}
562
563static void LimitPixelCacheDescriptors(void)
564{
565 register CacheInfo
566 *p,
567 *q;
568
569 /*
570 Limit # of open file descriptors.
571 */
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
573 return;
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (cache_resources == (SplayTreeInfo *) NULL)
576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return;
579 }
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
583 {
584 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000585 break;
cristy3ed852e2009-09-05 21:47:34 +0000586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 }
588 for (q=p; p != (CacheInfo *) NULL; )
589 {
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000592 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
594 }
595 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000596 {
597 /*
598 Close least recently used cache.
599 */
600 (void) close(q->file);
601 q->file=(-1);
602 }
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604}
605
606static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
608{
609 if (x > y)
610 return(x);
611 return(y);
612}
613
614static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x < y)
618 return(x);
619 return(y);
620}
621
622static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
623 const MapMode mode)
624{
625 int
626 file;
627
628 /*
629 Open pixel cache on disk.
630 */
cristyf84a1932010-01-03 18:00:18 +0000631 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000632 if (cache_info->file != -1)
633 {
cristyf84a1932010-01-03 18:00:18 +0000634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 return(MagickTrue); /* cache already open */
636 }
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
640 else
641 switch (mode)
642 {
643 case ReadMode:
644 {
cristy18c6c272011-09-23 14:40:37 +0000645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 case WriteMode:
649 {
cristy18c6c272011-09-23 14:40:37 +0000650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000652 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case IOMode:
657 default:
658 {
cristy18c6c272011-09-23 14:40:37 +0000659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000660 O_EXCL,S_MODE);
661 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
664 }
665 }
666 if (file == -1)
667 {
cristyf84a1932010-01-03 18:00:18 +0000668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000669 return(MagickFalse);
670 }
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
673 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000674 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000675 return(MagickTrue);
676}
677
678static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
679 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000680 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000681{
682 register MagickOffsetType
683 i;
684
685 ssize_t
686 count;
687
cristy08a88202010-03-04 19:18:05 +0000688 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000689#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000690 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000691 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristyf84a1932010-01-03 18:00:18 +0000693 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 return((MagickOffsetType) -1);
695 }
696#endif
697 count=0;
698 for (i=0; i < (MagickOffsetType) length; i+=count)
699 {
700#if !defined(MAGICKCORE_HAVE_PREAD)
701 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX));
703#else
704 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000705 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000706#endif
707 if (count > 0)
708 continue;
709 count=0;
710 if (errno != EINTR)
711 {
712 i=(-1);
713 break;
714 }
715 }
716#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000717 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000718#endif
719 return(i);
720}
721
722static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
723 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000724 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000725{
726 register MagickOffsetType
727 i;
728
729 ssize_t
730 count;
731
cristy08a88202010-03-04 19:18:05 +0000732 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000733#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000734 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000735 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000736 {
cristyf84a1932010-01-03 18:00:18 +0000737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 return((MagickOffsetType) -1);
739 }
740#endif
741 count=0;
742 for (i=0; i < (MagickOffsetType) length; i+=count)
743 {
744#if !defined(MAGICKCORE_HAVE_PWRITE)
745 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX));
747#else
748 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000749 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000750#endif
751 if (count > 0)
752 continue;
753 count=0;
754 if (errno != EINTR)
755 {
756 i=(-1);
757 break;
758 }
759 }
760#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000761 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000762#endif
763 return(i);
764}
765
cristy4c08aed2011-07-01 19:47:50 +0000766static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000767 CacheInfo *cache_info,ExceptionInfo *exception)
768{
769 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000770 count;
cristy3ed852e2009-09-05 21:47:34 +0000771
cristy4c08aed2011-07-01 19:47:50 +0000772 register MagickOffsetType
773 i;
cristye076a6e2010-08-15 19:59:43 +0000774
cristybb503372010-05-27 20:51:26 +0000775 size_t
cristy4c08aed2011-07-01 19:47:50 +0000776 length;
cristy3ed852e2009-09-05 21:47:34 +0000777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
780
781 /*
782 Clone pixel cache (both caches on disk).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000786 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000787 sizeof(*blob));
788 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000789 {
cristy4c08aed2011-07-01 19:47:50 +0000790 (void) ThrowMagickException(exception,GetMagickModule(),
791 ResourceLimitError,"MemoryAllocationFailed","`%s'",
792 cache_info->filename);
793 return(MagickFalse);
794 }
cristy3dedf062011-07-02 14:07:40 +0000795 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000796 {
797 blob=(unsigned char *) RelinquishMagickMemory(blob);
798 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
799 cache_info->cache_filename);
800 return(MagickFalse);
801 }
cristy3dedf062011-07-02 14:07:40 +0000802 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000803 {
804 (void) ClosePixelCacheOnDisk(cache_info);
805 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000806 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
807 clone_info->cache_filename);
808 return(MagickFalse);
809 }
cristy4c08aed2011-07-01 19:47:50 +0000810 count=0;
811 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
814 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
815 blob);
816 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000817 {
cristy4c08aed2011-07-01 19:47:50 +0000818 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
819 cache_info->cache_filename);
820 break;
cristy3ed852e2009-09-05 21:47:34 +0000821 }
cristy4c08aed2011-07-01 19:47:50 +0000822 length=(size_t) count;
823 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
824 if ((MagickSizeType) count != length)
825 {
826 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
827 clone_info->cache_filename);
828 break;
829 }
830 }
831 (void) ClosePixelCacheOnDisk(clone_info);
832 (void) ClosePixelCacheOnDisk(cache_info);
833 blob=(unsigned char *) RelinquishMagickMemory(blob);
834 if (i < (MagickOffsetType) cache_info->length)
835 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000836 return(MagickTrue);
837}
838
cristy4c08aed2011-07-01 19:47:50 +0000839static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000840 CacheInfo *cache_info,ExceptionInfo *exception)
841{
842 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000843 count;
cristy3ed852e2009-09-05 21:47:34 +0000844
cristy4c08aed2011-07-01 19:47:50 +0000845 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000846 {
cristy3ed852e2009-09-05 21:47:34 +0000847 /*
cristy4c08aed2011-07-01 19:47:50 +0000848 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000849 */
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->debug != MagickFalse)
851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
852 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
853 cache_info->length);
854 return(MagickTrue);
855 }
856 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
857 {
858 /*
859 Clone pixel cache (one cache on disk, one in memory).
860 */
861 if (cache_info->debug != MagickFalse)
862 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
863 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy4c08aed2011-07-01 19:47:50 +0000865 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000866 cache_info->cache_filename);
867 return(MagickFalse);
868 }
cristy4c08aed2011-07-01 19:47:50 +0000869 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
870 cache_info->length,(unsigned char *) clone_info->pixels);
871 (void) ClosePixelCacheOnDisk(cache_info);
872 if ((MagickSizeType) count != cache_info->length)
873 {
874 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
875 cache_info->cache_filename);
876 return(MagickFalse);
877 }
878 return(MagickTrue);
879 }
880 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
881 {
882 /*
883 Clone pixel cache (one cache on disk, one in memory).
884 */
885 if (clone_info->debug != MagickFalse)
886 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
887 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
888 {
889 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
890 clone_info->cache_filename);
891 return(MagickFalse);
892 }
893 count=WritePixelCacheRegion(clone_info,clone_info->offset,
894 clone_info->length,(unsigned char *) cache_info->pixels);
895 (void) ClosePixelCacheOnDisk(clone_info);
896 if ((MagickSizeType) count != clone_info->length)
897 {
898 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
899 clone_info->cache_filename);
900 return(MagickFalse);
901 }
902 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000903 }
904 /*
cristy4c08aed2011-07-01 19:47:50 +0000905 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000906 */
cristy4c08aed2011-07-01 19:47:50 +0000907 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000908}
909
cristy4c08aed2011-07-01 19:47:50 +0000910static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000911 CacheInfo *cache_info,ExceptionInfo *exception)
912{
cristy4c08aed2011-07-01 19:47:50 +0000913 MagickBooleanType
914 status;
cristy3ed852e2009-09-05 21:47:34 +0000915
cristy4c08aed2011-07-01 19:47:50 +0000916 MagickOffsetType
917 cache_offset,
918 clone_offset,
919 count;
920
921 register ssize_t
922 x;
923
924 size_t
cristy3ed852e2009-09-05 21:47:34 +0000925 length;
926
cristy4c08aed2011-07-01 19:47:50 +0000927 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000928 y;
929
cristy4c08aed2011-07-01 19:47:50 +0000930 unsigned char
931 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000932
cristy4c08aed2011-07-01 19:47:50 +0000933 /*
934 Clone pixel cache (unoptimized).
935 */
cristy3ed852e2009-09-05 21:47:34 +0000936 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000937 {
cristy4c08aed2011-07-01 19:47:50 +0000938 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
939 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
940 else
941 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
942 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
943 else
944 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
946 else
947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
948 }
cristyed231572011-07-14 02:18:59 +0000949 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
950 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000951 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000952 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000953 if (blob == (unsigned char *) NULL)
954 {
955 (void) ThrowMagickException(exception,GetMagickModule(),
956 ResourceLimitError,"MemoryAllocationFailed","`%s'",
957 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000958 return(MagickFalse);
959 }
cristy4c08aed2011-07-01 19:47:50 +0000960 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
961 cache_offset=0;
962 clone_offset=0;
963 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000964 {
cristy4c08aed2011-07-01 19:47:50 +0000965 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
cristy4c08aed2011-07-01 19:47:50 +0000967 blob=(unsigned char *) RelinquishMagickMemory(blob);
968 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
cristy4c08aed2011-07-01 19:47:50 +0000972 cache_offset=cache_info->offset;
973 }
974 if (clone_info->type == DiskCache)
975 {
cristy3dedf062011-07-02 14:07:40 +0000976 if ((cache_info->type == DiskCache) &&
977 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
978 {
979 (void) ClosePixelCacheOnDisk(clone_info);
980 *clone_info->cache_filename='\0';
981 }
982 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000983 {
cristy4c08aed2011-07-01 19:47:50 +0000984 if (cache_info->type == DiskCache)
985 (void) ClosePixelCacheOnDisk(cache_info);
986 blob=(unsigned char *) RelinquishMagickMemory(blob);
987 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
988 clone_info->cache_filename);
989 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000990 }
cristy4c08aed2011-07-01 19:47:50 +0000991 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000992 }
993 /*
cristy4c08aed2011-07-01 19:47:50 +0000994 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000995 */
cristy4c08aed2011-07-01 19:47:50 +0000996 status=MagickTrue;
997 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
cristy4c08aed2011-07-01 19:47:50 +0000999 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001000 {
cristy3ed852e2009-09-05 21:47:34 +00001001 /*
cristy4c08aed2011-07-01 19:47:50 +00001002 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001003 */
cristyed231572011-07-14 02:18:59 +00001004 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001005 if (cache_info->type != DiskCache)
1006 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1007 length);
cristy3ed852e2009-09-05 21:47:34 +00001008 else
1009 {
cristy4c08aed2011-07-01 19:47:50 +00001010 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1011 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001012 {
cristy4c08aed2011-07-01 19:47:50 +00001013 status=MagickFalse;
1014 break;
cristy3ed852e2009-09-05 21:47:34 +00001015 }
1016 }
cristy4c08aed2011-07-01 19:47:50 +00001017 cache_offset+=length;
1018 if ((y < (ssize_t) clone_info->rows) &&
1019 (x < (ssize_t) clone_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00001020 {
cristy4c08aed2011-07-01 19:47:50 +00001021 /*
1022 Write a set of pixel channels.
1023 */
cristyed231572011-07-14 02:18:59 +00001024 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001025 if (clone_info->type != DiskCache)
1026 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1027 blob,length);
1028 else
1029 {
cristy208b1002011-08-07 18:51:50 +00001030 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001031 if ((MagickSizeType) count != length)
1032 {
1033 status=MagickFalse;
1034 break;
1035 }
1036 }
1037 clone_offset+=length;
cristy3ed852e2009-09-05 21:47:34 +00001038 }
1039 }
cristyed231572011-07-14 02:18:59 +00001040 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001041 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1042 for ( ; x < (ssize_t) clone_info->columns; x++)
1043 {
1044 /*
1045 Set remaining columns with transparent pixel channels.
1046 */
1047 if (clone_info->type != DiskCache)
1048 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1049 length);
1050 else
1051 {
1052 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1053 if ((MagickSizeType) count != length)
1054 {
1055 status=MagickFalse;
1056 break;
1057 }
1058 }
1059 clone_offset+=length;
1060 }
1061 }
cristyed231572011-07-14 02:18:59 +00001062 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001063 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1064 for ( ; y < (ssize_t) clone_info->rows; y++)
1065 {
1066 /*
1067 Set remaining rows with transparent pixels.
1068 */
1069 for (x=0; x < (ssize_t) clone_info->columns; x++)
1070 {
1071 if (clone_info->type != DiskCache)
1072 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1073 length);
1074 else
1075 {
1076 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1077 if ((MagickSizeType) count != length)
1078 {
1079 status=MagickFalse;
1080 break;
1081 }
1082 }
1083 clone_offset+=length;
1084 }
1085 }
1086 if ((cache_info->metacontent_extent != 0) &&
1087 (clone_info->metacontent_extent != 0))
1088 {
1089 /*
1090 Clone metacontent.
1091 */
1092 for (y=0; y < (ssize_t) cache_info->rows; y++)
1093 {
1094 for (x=0; x < (ssize_t) cache_info->columns; x++)
1095 {
1096 /*
1097 Read a set of metacontent.
1098 */
1099 length=cache_info->metacontent_extent;
1100 if (cache_info->type != DiskCache)
1101 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1102 cache_offset,length);
1103 else
1104 {
1105 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1106 if ((MagickSizeType) count != length)
1107 {
1108 status=MagickFalse;
1109 break;
1110 }
1111 }
1112 cache_offset+=length;
1113 if ((y < (ssize_t) clone_info->rows) &&
1114 (x < (ssize_t) clone_info->columns))
1115 {
1116 /*
1117 Write a set of metacontent.
1118 */
1119 length=clone_info->metacontent_extent;
1120 if (clone_info->type != DiskCache)
1121 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1122 blob,length);
1123 else
1124 {
1125 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1126 blob);
1127 if ((MagickSizeType) count != length)
1128 {
1129 status=MagickFalse;
1130 break;
1131 }
1132 }
1133 clone_offset+=length;
1134 }
1135 }
1136 length=clone_info->metacontent_extent;
1137 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1138 for ( ; x < (ssize_t) clone_info->columns; x++)
1139 {
1140 /*
1141 Set remaining columns with metacontent.
1142 */
1143 if (clone_info->type != DiskCache)
1144 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1145 blob,length);
1146 else
1147 {
cristy208b1002011-08-07 18:51:50 +00001148 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001149 if ((MagickSizeType) count != length)
1150 {
1151 status=MagickFalse;
1152 break;
1153 }
1154 }
1155 clone_offset+=length;
1156 }
1157 }
1158 length=clone_info->metacontent_extent;
1159 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1160 for ( ; y < (ssize_t) clone_info->rows; y++)
1161 {
1162 /*
1163 Set remaining rows with metacontent.
1164 */
1165 for (x=0; x < (ssize_t) clone_info->columns; x++)
1166 {
1167 if (clone_info->type != DiskCache)
1168 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1169 blob,length);
1170 else
1171 {
1172 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1173 if ((MagickSizeType) count != length)
1174 {
1175 status=MagickFalse;
1176 break;
1177 }
1178 }
1179 clone_offset+=length;
1180 }
1181 }
1182 }
1183 if (clone_info->type == DiskCache)
1184 (void) ClosePixelCacheOnDisk(clone_info);
1185 if (cache_info->type == DiskCache)
1186 (void) ClosePixelCacheOnDisk(cache_info);
1187 blob=(unsigned char *) RelinquishMagickMemory(blob);
1188 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001189}
1190
1191static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1192 CacheInfo *cache_info,ExceptionInfo *exception)
1193{
cristy5a7fbfb2010-11-06 16:10:59 +00001194 if (cache_info->type == PingCache)
1195 return(MagickTrue);
cristy4c08aed2011-07-01 19:47:50 +00001196 if ((cache_info->columns == clone_info->columns) &&
1197 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001198 (cache_info->number_channels == clone_info->number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00001199 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1200 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1201 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001202}
1203
1204/*
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206% %
1207% %
1208% %
1209+ C l o n e P i x e l C a c h e M e t h o d s %
1210% %
1211% %
1212% %
1213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214%
1215% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1216% another.
1217%
1218% The format of the ClonePixelCacheMethods() method is:
1219%
1220% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1221%
1222% A description of each parameter follows:
1223%
1224% o clone: Specifies a pointer to a Cache structure.
1225%
1226% o cache: the pixel cache.
1227%
1228*/
cristya6577ff2011-09-02 19:54:26 +00001229MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001230{
1231 CacheInfo
1232 *cache_info,
1233 *source_info;
1234
1235 assert(clone != (Cache) NULL);
1236 source_info=(CacheInfo *) clone;
1237 assert(source_info->signature == MagickSignature);
1238 if (source_info->debug != MagickFalse)
1239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1240 source_info->filename);
1241 assert(cache != (Cache) NULL);
1242 cache_info=(CacheInfo *) cache;
1243 assert(cache_info->signature == MagickSignature);
1244 source_info->methods=cache_info->methods;
1245}
1246
1247/*
1248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249% %
1250% %
1251% %
1252+ D e s t r o y I m a g e P i x e l C a c h e %
1253% %
1254% %
1255% %
1256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257%
1258% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1259%
1260% The format of the DestroyImagePixelCache() method is:
1261%
1262% void DestroyImagePixelCache(Image *image)
1263%
1264% A description of each parameter follows:
1265%
1266% o image: the image.
1267%
1268*/
1269static void DestroyImagePixelCache(Image *image)
1270{
1271 assert(image != (Image *) NULL);
1272 assert(image->signature == MagickSignature);
1273 if (image->debug != MagickFalse)
1274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1275 if (image->cache == (void *) NULL)
1276 return;
1277 image->cache=DestroyPixelCache(image->cache);
1278}
1279
1280/*
1281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282% %
1283% %
1284% %
1285+ D e s t r o y I m a g e P i x e l s %
1286% %
1287% %
1288% %
1289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290%
1291% DestroyImagePixels() deallocates memory associated with the pixel cache.
1292%
1293% The format of the DestroyImagePixels() method is:
1294%
1295% void DestroyImagePixels(Image *image)
1296%
1297% A description of each parameter follows:
1298%
1299% o image: the image.
1300%
1301*/
1302MagickExport void DestroyImagePixels(Image *image)
1303{
1304 CacheInfo
1305 *cache_info;
1306
1307 assert(image != (const Image *) NULL);
1308 assert(image->signature == MagickSignature);
1309 if (image->debug != MagickFalse)
1310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1311 assert(image->cache != (Cache) NULL);
1312 cache_info=(CacheInfo *) image->cache;
1313 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001314 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1315 {
1316 cache_info->methods.destroy_pixel_handler(image);
1317 return;
1318 }
cristy2036f5c2010-09-19 21:18:17 +00001319 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001320}
1321
1322/*
1323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324% %
1325% %
1326% %
1327+ D e s t r o y P i x e l C a c h e %
1328% %
1329% %
1330% %
1331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332%
1333% DestroyPixelCache() deallocates memory associated with the pixel cache.
1334%
1335% The format of the DestroyPixelCache() method is:
1336%
1337% Cache DestroyPixelCache(Cache cache)
1338%
1339% A description of each parameter follows:
1340%
1341% o cache: the pixel cache.
1342%
1343*/
1344
1345static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1346{
1347 switch (cache_info->type)
1348 {
1349 case MemoryCache:
1350 {
1351 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001352 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001353 cache_info->pixels);
1354 else
cristy4c08aed2011-07-01 19:47:50 +00001355 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001356 (size_t) cache_info->length);
1357 RelinquishMagickResource(MemoryResource,cache_info->length);
1358 break;
1359 }
1360 case MapCache:
1361 {
cristy4c08aed2011-07-01 19:47:50 +00001362 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001363 cache_info->length);
1364 RelinquishMagickResource(MapResource,cache_info->length);
1365 }
1366 case DiskCache:
1367 {
1368 if (cache_info->file != -1)
1369 (void) ClosePixelCacheOnDisk(cache_info);
1370 RelinquishMagickResource(DiskResource,cache_info->length);
1371 break;
1372 }
1373 default:
1374 break;
1375 }
1376 cache_info->type=UndefinedCache;
1377 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001378 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001379}
1380
cristya6577ff2011-09-02 19:54:26 +00001381MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001382{
1383 CacheInfo
1384 *cache_info;
1385
cristy3ed852e2009-09-05 21:47:34 +00001386 assert(cache != (Cache) NULL);
1387 cache_info=(CacheInfo *) cache;
1388 assert(cache_info->signature == MagickSignature);
1389 if (cache_info->debug != MagickFalse)
1390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1391 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001392 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001393 cache_info->reference_count--;
1394 if (cache_info->reference_count != 0)
1395 {
cristyf84a1932010-01-03 18:00:18 +00001396 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001397 return((Cache) NULL);
1398 }
cristyf84a1932010-01-03 18:00:18 +00001399 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001400 if (cache_resources != (SplayTreeInfo *) NULL)
1401 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001402 if (cache_info->debug != MagickFalse)
1403 {
1404 char
1405 message[MaxTextExtent];
1406
cristyb51dff52011-05-19 16:55:47 +00001407 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001408 cache_info->filename);
1409 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1410 }
cristyc2e1bdd2009-09-10 23:43:34 +00001411 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1412 (cache_info->type != DiskCache)))
1413 RelinquishPixelCachePixels(cache_info);
1414 else
1415 {
1416 RelinquishPixelCachePixels(cache_info);
1417 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1418 }
cristy3ed852e2009-09-05 21:47:34 +00001419 *cache_info->cache_filename='\0';
1420 if (cache_info->nexus_info != (NexusInfo **) NULL)
1421 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1422 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001423 if (cache_info->random_info != (RandomInfo *) NULL)
1424 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001425 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1426 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1427 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1428 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001429 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001430 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001431 cache=(Cache) NULL;
1432 return(cache);
1433}
1434
1435/*
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437% %
1438% %
1439% %
1440+ D e s t r o y P i x e l C a c h e N e x u s %
1441% %
1442% %
1443% %
1444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445%
1446% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1447%
1448% The format of the DestroyPixelCacheNexus() method is:
1449%
1450% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001451% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001452%
1453% A description of each parameter follows:
1454%
1455% o nexus_info: the nexus to destroy.
1456%
1457% o number_threads: the number of nexus threads.
1458%
1459*/
1460
1461static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1462{
1463 if (nexus_info->mapped == MagickFalse)
1464 (void) RelinquishMagickMemory(nexus_info->cache);
1465 else
1466 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001467 nexus_info->cache=(Quantum *) NULL;
1468 nexus_info->pixels=(Quantum *) NULL;
1469 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001470 nexus_info->length=0;
1471 nexus_info->mapped=MagickFalse;
1472}
1473
cristya6577ff2011-09-02 19:54:26 +00001474MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001475 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001476{
cristybb503372010-05-27 20:51:26 +00001477 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001478 i;
1479
1480 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001481 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001482 {
cristy4c08aed2011-07-01 19:47:50 +00001483 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001484 RelinquishCacheNexusPixels(nexus_info[i]);
1485 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001486 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001487 }
cristyb41ee102010-10-04 16:46:15 +00001488 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001489 return(nexus_info);
1490}
1491
1492/*
1493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494% %
1495% %
1496% %
cristy4c08aed2011-07-01 19:47:50 +00001497% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001498% %
1499% %
1500% %
1501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502%
cristy4c08aed2011-07-01 19:47:50 +00001503% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1504% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1505% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001506%
cristy4c08aed2011-07-01 19:47:50 +00001507% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001508%
cristy4c08aed2011-07-01 19:47:50 +00001509% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001510%
1511% A description of each parameter follows:
1512%
1513% o image: the image.
1514%
1515*/
cristy4c08aed2011-07-01 19:47:50 +00001516MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001517{
1518 CacheInfo
1519 *cache_info;
1520
cristy5c9e6f22010-09-17 17:31:01 +00001521 const int
1522 id = GetOpenMPThreadId();
1523
cristy4c08aed2011-07-01 19:47:50 +00001524 void
1525 *metacontent;
1526
cristye7cc7cf2010-09-21 13:26:47 +00001527 assert(image != (const Image *) NULL);
1528 assert(image->signature == MagickSignature);
1529 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001530 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001531 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001532 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1533 (GetAuthenticMetacontentFromHandler) NULL)
1534 {
1535 metacontent=cache_info->methods.
1536 get_authentic_metacontent_from_handler(image);
1537 return(metacontent);
1538 }
cristy6ebe97c2010-07-03 01:17:28 +00001539 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001540 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1541 cache_info->nexus_info[id]);
1542 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001543}
1544
1545/*
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547% %
1548% %
1549% %
cristy4c08aed2011-07-01 19:47:50 +00001550+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001551% %
1552% %
1553% %
1554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555%
cristy4c08aed2011-07-01 19:47:50 +00001556% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1557% with the last call to QueueAuthenticPixelsCache() or
1558% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001559%
cristy4c08aed2011-07-01 19:47:50 +00001560% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001561%
cristy4c08aed2011-07-01 19:47:50 +00001562% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001563%
1564% A description of each parameter follows:
1565%
1566% o image: the image.
1567%
1568*/
cristy4c08aed2011-07-01 19:47:50 +00001569static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001570{
1571 CacheInfo
1572 *cache_info;
1573
cristy2036f5c2010-09-19 21:18:17 +00001574 const int
1575 id = GetOpenMPThreadId();
1576
cristy4c08aed2011-07-01 19:47:50 +00001577 void
1578 *metacontent;
1579
cristy3ed852e2009-09-05 21:47:34 +00001580 assert(image != (const Image *) NULL);
1581 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001582 assert(image->cache != (Cache) NULL);
1583 cache_info=(CacheInfo *) image->cache;
1584 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001585 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001586 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1587 cache_info->nexus_info[id]);
1588 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001589}
1590
1591/*
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593% %
1594% %
1595% %
1596+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1597% %
1598% %
1599% %
1600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601%
1602% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1603% disk pixel cache as defined by the geometry parameters. A pointer to the
1604% pixels is returned if the pixels are transferred, otherwise a NULL is
1605% returned.
1606%
1607% The format of the GetAuthenticPixelCacheNexus() method is:
1608%
cristy4c08aed2011-07-01 19:47:50 +00001609% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001610% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001611% NexusInfo *nexus_info,ExceptionInfo *exception)
1612%
1613% A description of each parameter follows:
1614%
1615% o image: the image.
1616%
1617% o x,y,columns,rows: These values define the perimeter of a region of
1618% pixels.
1619%
1620% o nexus_info: the cache nexus to return.
1621%
1622% o exception: return any errors or warnings in this structure.
1623%
1624*/
1625
cristy4c08aed2011-07-01 19:47:50 +00001626static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001627 NexusInfo *nexus_info)
1628{
cristy4c08aed2011-07-01 19:47:50 +00001629 MagickBooleanType
1630 status;
1631
cristy3ed852e2009-09-05 21:47:34 +00001632 MagickOffsetType
1633 offset;
1634
cristy73724512010-04-12 14:43:14 +00001635 if (cache_info->type == PingCache)
1636 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001637 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1638 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001639 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001640 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001641 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001642}
1643
cristya6577ff2011-09-02 19:54:26 +00001644MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001645 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001646 NexusInfo *nexus_info,ExceptionInfo *exception)
1647{
1648 CacheInfo
1649 *cache_info;
1650
cristy4c08aed2011-07-01 19:47:50 +00001651 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001652 *q;
cristy3ed852e2009-09-05 21:47:34 +00001653
1654 /*
1655 Transfer pixels from the cache.
1656 */
1657 assert(image != (Image *) NULL);
1658 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001659 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001660 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001661 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001662 cache_info=(CacheInfo *) image->cache;
1663 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001664 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001665 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001666 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001667 return((Quantum *) NULL);
1668 if (cache_info->metacontent_extent != 0)
1669 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1670 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001671 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001672}
1673
1674/*
1675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676% %
1677% %
1678% %
1679+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1680% %
1681% %
1682% %
1683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684%
1685% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1686% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1687%
1688% The format of the GetAuthenticPixelsFromCache() method is:
1689%
cristy4c08aed2011-07-01 19:47:50 +00001690% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001691%
1692% A description of each parameter follows:
1693%
1694% o image: the image.
1695%
1696*/
cristy4c08aed2011-07-01 19:47:50 +00001697static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001698{
1699 CacheInfo
1700 *cache_info;
1701
cristy5c9e6f22010-09-17 17:31:01 +00001702 const int
1703 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001704
cristye7cc7cf2010-09-21 13:26:47 +00001705 assert(image != (const Image *) NULL);
1706 assert(image->signature == MagickSignature);
1707 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001708 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001709 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001710 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001711 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001712}
1713
1714/*
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716% %
1717% %
1718% %
1719% G e t A u t h e n t i c P i x e l Q u e u e %
1720% %
1721% %
1722% %
1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724%
cristy4c08aed2011-07-01 19:47:50 +00001725% GetAuthenticPixelQueue() returns the authentic pixels associated
1726% corresponding with the last call to QueueAuthenticPixels() or
1727% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001728%
1729% The format of the GetAuthenticPixelQueue() method is:
1730%
cristy4c08aed2011-07-01 19:47:50 +00001731% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001732%
1733% A description of each parameter follows:
1734%
1735% o image: the image.
1736%
1737*/
cristy4c08aed2011-07-01 19:47:50 +00001738MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001739{
1740 CacheInfo
1741 *cache_info;
1742
cristy2036f5c2010-09-19 21:18:17 +00001743 const int
1744 id = GetOpenMPThreadId();
1745
cristy3ed852e2009-09-05 21:47:34 +00001746 assert(image != (const Image *) NULL);
1747 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001748 assert(image->cache != (Cache) NULL);
1749 cache_info=(CacheInfo *) image->cache;
1750 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001751 if (cache_info->methods.get_authentic_pixels_from_handler !=
1752 (GetAuthenticPixelsFromHandler) NULL)
1753 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001754 assert(id < (int) cache_info->number_threads);
1755 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001756}
1757
1758/*
1759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760% %
1761% %
1762% %
1763% G e t A u t h e n t i c P i x e l s %
1764% %
1765% %
cristy4c08aed2011-07-01 19:47:50 +00001766% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001767%
1768% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001769% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001770% representing the region is returned, otherwise NULL is returned.
1771%
1772% The returned pointer may point to a temporary working copy of the pixels
1773% or it may point to the original pixels in memory. Performance is maximized
1774% if the selected region is part of one row, or one or more full rows, since
1775% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001776% if the image is in memory, or in a memory-mapped file. The returned pointer
1777% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001778%
1779% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001780% Quantum. If the image has corresponding metacontent,call
1781% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1782% meta-content corresponding to the region. Once the Quantum array has
1783% been updated, the changes must be saved back to the underlying image using
1784% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001785%
1786% The format of the GetAuthenticPixels() method is:
1787%
cristy4c08aed2011-07-01 19:47:50 +00001788% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001789% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001790% ExceptionInfo *exception)
1791%
1792% A description of each parameter follows:
1793%
1794% o image: the image.
1795%
1796% o x,y,columns,rows: These values define the perimeter of a region of
1797% pixels.
1798%
1799% o exception: return any errors or warnings in this structure.
1800%
1801*/
cristy4c08aed2011-07-01 19:47:50 +00001802MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001803 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001804 ExceptionInfo *exception)
1805{
1806 CacheInfo
1807 *cache_info;
1808
cristy2036f5c2010-09-19 21:18:17 +00001809 const int
1810 id = GetOpenMPThreadId();
1811
cristy4c08aed2011-07-01 19:47:50 +00001812 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001813 *q;
cristy4c08aed2011-07-01 19:47:50 +00001814
cristy3ed852e2009-09-05 21:47:34 +00001815 assert(image != (Image *) NULL);
1816 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001817 assert(image->cache != (Cache) NULL);
1818 cache_info=(CacheInfo *) image->cache;
1819 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001820 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001821 (GetAuthenticPixelsHandler) NULL)
1822 {
cristyacd2ed22011-08-30 01:44:23 +00001823 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1824 exception);
1825 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001826 }
cristy2036f5c2010-09-19 21:18:17 +00001827 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001828 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001829 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001830 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001831}
1832
1833/*
1834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835% %
1836% %
1837% %
1838+ G e t A u t h e n t i c P i x e l s C a c h e %
1839% %
1840% %
1841% %
1842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1843%
1844% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1845% as defined by the geometry parameters. A pointer to the pixels is returned
1846% if the pixels are transferred, otherwise a NULL is returned.
1847%
1848% The format of the GetAuthenticPixelsCache() method is:
1849%
cristy4c08aed2011-07-01 19:47:50 +00001850% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001851% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001852% ExceptionInfo *exception)
1853%
1854% A description of each parameter follows:
1855%
1856% o image: the image.
1857%
1858% o x,y,columns,rows: These values define the perimeter of a region of
1859% pixels.
1860%
1861% o exception: return any errors or warnings in this structure.
1862%
1863*/
cristy4c08aed2011-07-01 19:47:50 +00001864static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001865 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001866 ExceptionInfo *exception)
1867{
1868 CacheInfo
1869 *cache_info;
1870
cristy5c9e6f22010-09-17 17:31:01 +00001871 const int
1872 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001873
cristy4c08aed2011-07-01 19:47:50 +00001874 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001875 *q;
cristy4c08aed2011-07-01 19:47:50 +00001876
cristye7cc7cf2010-09-21 13:26:47 +00001877 assert(image != (const Image *) NULL);
1878 assert(image->signature == MagickSignature);
1879 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001880 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001881 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001882 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001883 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001884 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001885 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001886 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001887 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001888}
1889
1890/*
1891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892% %
1893% %
1894% %
1895+ G e t I m a g e E x t e n t %
1896% %
1897% %
1898% %
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900%
cristy4c08aed2011-07-01 19:47:50 +00001901% GetImageExtent() returns the extent of the pixels associated corresponding
1902% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001903%
1904% The format of the GetImageExtent() method is:
1905%
1906% MagickSizeType GetImageExtent(const Image *image)
1907%
1908% A description of each parameter follows:
1909%
1910% o image: the image.
1911%
1912*/
1913MagickExport MagickSizeType GetImageExtent(const Image *image)
1914{
1915 CacheInfo
1916 *cache_info;
1917
cristy5c9e6f22010-09-17 17:31:01 +00001918 const int
1919 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001920
cristy3ed852e2009-09-05 21:47:34 +00001921 assert(image != (Image *) NULL);
1922 assert(image->signature == MagickSignature);
1923 if (image->debug != MagickFalse)
1924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1925 assert(image->cache != (Cache) NULL);
1926 cache_info=(CacheInfo *) image->cache;
1927 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001928 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001929 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001930}
1931
1932/*
1933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1934% %
1935% %
1936% %
1937+ G e t I m a g e P i x e l C a c h e %
1938% %
1939% %
1940% %
1941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942%
1943% GetImagePixelCache() ensures that there is only a single reference to the
1944% pixel cache to be modified, updating the provided cache pointer to point to
1945% a clone of the original pixel cache if necessary.
1946%
1947% The format of the GetImagePixelCache method is:
1948%
1949% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1950% ExceptionInfo *exception)
1951%
1952% A description of each parameter follows:
1953%
1954% o image: the image.
1955%
1956% o clone: any value other than MagickFalse clones the cache pixels.
1957%
1958% o exception: return any errors or warnings in this structure.
1959%
1960*/
cristyaf894d72011-08-06 23:03:10 +00001961
cristy3ed852e2009-09-05 21:47:34 +00001962static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1963{
1964 CacheInfo
1965 *cache_info;
1966
1967 /*
1968 Does the image match the pixel cache morphology?
1969 */
1970 cache_info=(CacheInfo *) image->cache;
1971 if ((image->storage_class != cache_info->storage_class) ||
1972 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001973 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00001974 (image->columns != cache_info->columns) ||
1975 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001976 (image->number_channels != cache_info->number_channels) ||
cristy4c08aed2011-07-01 19:47:50 +00001977 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001978 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1979 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1980 return(MagickFalse);
1981 return(MagickTrue);
1982}
1983
cristycd01fae2011-08-06 23:52:42 +00001984static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1985 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001986{
1987 CacheInfo
1988 *cache_info;
1989
cristy3ed852e2009-09-05 21:47:34 +00001990 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001991 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001992 status;
1993
cristy50a10922010-02-15 18:35:25 +00001994 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001995 cpu_throttle = 0,
1996 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001997 time_limit = 0;
1998
cristy1ea34962010-07-01 19:49:21 +00001999 static time_t
cristy208b1002011-08-07 18:51:50 +00002000 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002001
cristyc4f9f132010-03-04 18:50:01 +00002002 status=MagickTrue;
2003 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002004 if (cpu_throttle == 0)
2005 {
2006 char
2007 *limit;
2008
2009 /*
2010 Set CPU throttle in milleseconds.
2011 */
2012 cpu_throttle=MagickResourceInfinity;
2013 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2014 if (limit == (char *) NULL)
2015 limit=GetPolicyValue("throttle");
2016 if (limit != (char *) NULL)
2017 {
2018 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2019 limit=DestroyString(limit);
2020 }
2021 }
2022 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2023 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002024 if (time_limit == 0)
2025 {
cristy6ebe97c2010-07-03 01:17:28 +00002026 /*
2027 Set the exire time in seconds.
2028 */
cristy1ea34962010-07-01 19:49:21 +00002029 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002030 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002031 }
2032 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002033 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002034 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002035 assert(image->cache != (Cache) NULL);
2036 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002037 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002038 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002039 {
cristyceb55ee2010-11-06 16:05:49 +00002040 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002041 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002042 {
cristyceb55ee2010-11-06 16:05:49 +00002043 Image
2044 clone_image;
2045
2046 CacheInfo
2047 *clone_info;
2048
2049 /*
2050 Clone pixel cache.
2051 */
2052 clone_image=(*image);
2053 clone_image.semaphore=AllocateSemaphoreInfo();
2054 clone_image.reference_count=1;
2055 clone_image.cache=ClonePixelCache(cache_info);
2056 clone_info=(CacheInfo *) clone_image.cache;
2057 status=OpenPixelCache(&clone_image,IOMode,exception);
2058 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002059 {
cristy5a7fbfb2010-11-06 16:10:59 +00002060 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002061 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002062 if (status != MagickFalse)
2063 {
cristy979bf772011-08-08 00:04:15 +00002064 if (cache_info->mode == ReadMode)
2065 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002066 destroy=MagickTrue;
2067 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002068 }
2069 }
cristyceb55ee2010-11-06 16:05:49 +00002070 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002071 }
cristyceb55ee2010-11-06 16:05:49 +00002072 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002073 }
cristy4320e0e2009-09-10 15:00:08 +00002074 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002075 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002076 if (status != MagickFalse)
2077 {
2078 /*
2079 Ensure the image matches the pixel cache morphology.
2080 */
2081 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002082 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002083 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2084 status=OpenPixelCache(image,IOMode,exception);
2085 }
cristyf84a1932010-01-03 18:00:18 +00002086 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002087 if (status == MagickFalse)
2088 return((Cache) NULL);
2089 return(image->cache);
2090}
2091
2092/*
2093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094% %
2095% %
2096% %
2097% G e t O n e A u t h e n t i c P i x e l %
2098% %
2099% %
2100% %
2101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102%
2103% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2104% location. The image background color is returned if an error occurs.
2105%
2106% The format of the GetOneAuthenticPixel() method is:
2107%
cristybb503372010-05-27 20:51:26 +00002108% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002109% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002110%
2111% A description of each parameter follows:
2112%
2113% o image: the image.
2114%
2115% o x,y: These values define the location of the pixel to return.
2116%
2117% o pixel: return a pixel at the specified (x,y) location.
2118%
2119% o exception: return any errors or warnings in this structure.
2120%
2121*/
cristyacbbb7c2010-06-30 18:56:48 +00002122MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002123 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002124{
2125 CacheInfo
2126 *cache_info;
2127
cristy4c08aed2011-07-01 19:47:50 +00002128 register Quantum
2129 *q;
cristy2036f5c2010-09-19 21:18:17 +00002130
cristy2ed42f62011-10-02 19:49:57 +00002131 register ssize_t
2132 i;
2133
cristy3ed852e2009-09-05 21:47:34 +00002134 assert(image != (Image *) NULL);
2135 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002136 assert(image->cache != (Cache) NULL);
2137 cache_info=(CacheInfo *) image->cache;
2138 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002139 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002140 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2141 (GetOneAuthenticPixelFromHandler) NULL)
2142 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2143 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002144 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2145 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002146 {
2147 pixel[RedPixelChannel]=image->background_color.red;
2148 pixel[GreenPixelChannel]=image->background_color.green;
2149 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002150 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002151 pixel[AlphaPixelChannel]=image->background_color.alpha;
2152 return(MagickFalse);
2153 }
2154 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2155 {
2156 PixelChannel
2157 channel;
2158
2159 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2160 pixel[channel]=q[i];
2161 }
cristy2036f5c2010-09-19 21:18:17 +00002162 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002163}
2164
2165/*
2166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167% %
2168% %
2169% %
2170+ 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 %
2171% %
2172% %
2173% %
2174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2175%
2176% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2177% location. The image background color is returned if an error occurs.
2178%
2179% The format of the GetOneAuthenticPixelFromCache() method is:
2180%
2181% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002182% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002183% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002184%
2185% A description of each parameter follows:
2186%
2187% o image: the image.
2188%
2189% o x,y: These values define the location of the pixel to return.
2190%
2191% o pixel: return a pixel at the specified (x,y) location.
2192%
2193% o exception: return any errors or warnings in this structure.
2194%
2195*/
2196static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002197 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002198{
cristy098f78c2010-09-23 17:28:44 +00002199 CacheInfo
2200 *cache_info;
2201
2202 const int
2203 id = GetOpenMPThreadId();
2204
cristy4c08aed2011-07-01 19:47:50 +00002205 register Quantum
2206 *q;
cristy3ed852e2009-09-05 21:47:34 +00002207
cristy2ed42f62011-10-02 19:49:57 +00002208 register ssize_t
2209 i;
2210
cristy0158a4b2010-09-20 13:59:45 +00002211 assert(image != (const Image *) NULL);
2212 assert(image->signature == MagickSignature);
2213 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002214 cache_info=(CacheInfo *) image->cache;
2215 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002216 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002217 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002218 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2219 exception);
2220 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002221 {
2222 pixel[RedPixelChannel]=image->background_color.red;
2223 pixel[GreenPixelChannel]=image->background_color.green;
2224 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002225 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002226 pixel[AlphaPixelChannel]=image->background_color.alpha;
2227 return(MagickFalse);
2228 }
2229 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2230 {
2231 PixelChannel
2232 channel;
2233
2234 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2235 pixel[channel]=q[i];
2236 }
cristy3ed852e2009-09-05 21:47:34 +00002237 return(MagickTrue);
2238}
2239
2240/*
2241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242% %
2243% %
2244% %
2245% G e t O n e V i r t u a l M a g i c k P i x e l %
2246% %
2247% %
2248% %
2249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250%
2251% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2252% location. The image background color is returned if an error occurs. If
2253% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2254%
2255% The format of the GetOneVirtualMagickPixel() method is:
2256%
2257% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002258% const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002259% ExceptionInfo exception)
2260%
2261% A description of each parameter follows:
2262%
2263% o image: the image.
2264%
2265% o x,y: these values define the location of the pixel to return.
2266%
2267% o pixel: return a pixel at the specified (x,y) location.
2268%
2269% o exception: return any errors or warnings in this structure.
2270%
2271*/
2272MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyec061ec2011-10-21 17:41:17 +00002273 const ssize_t x,const ssize_t y,PixelInfo *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002274{
2275 CacheInfo
2276 *cache_info;
2277
cristy0158a4b2010-09-20 13:59:45 +00002278 const int
2279 id = GetOpenMPThreadId();
2280
cristy4c08aed2011-07-01 19:47:50 +00002281 register const Quantum
cristyacd2ed22011-08-30 01:44:23 +00002282 *p;
cristy3ed852e2009-09-05 21:47:34 +00002283
2284 assert(image != (const Image *) NULL);
2285 assert(image->signature == MagickSignature);
2286 assert(image->cache != (Cache) NULL);
2287 cache_info=(CacheInfo *) image->cache;
2288 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002289 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00002290 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002291 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002292 GetPixelInfo(image,pixel);
cristyacd2ed22011-08-30 01:44:23 +00002293 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002294 return(MagickFalse);
cristyacd2ed22011-08-30 01:44:23 +00002295 SetPixelInfo(image,p,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002296 return(MagickTrue);
2297}
2298
2299/*
2300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2301% %
2302% %
2303% %
2304% G e t O n e V i r t u a l M e t h o d P i x e l %
2305% %
2306% %
2307% %
2308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2309%
2310% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2311% location as defined by specified pixel method. The image background color
2312% is returned if an error occurs. If you plan to modify the pixel, use
2313% GetOneAuthenticPixel() instead.
2314%
2315% The format of the GetOneVirtualMethodPixel() method is:
2316%
2317% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002318% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002319% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002320%
2321% A description of each parameter follows:
2322%
2323% o image: the image.
2324%
2325% o virtual_pixel_method: the virtual pixel method.
2326%
2327% o x,y: These values define the location of the pixel to return.
2328%
2329% o pixel: return a pixel at the specified (x,y) location.
2330%
2331% o exception: return any errors or warnings in this structure.
2332%
2333*/
2334MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002335 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002336 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002337{
cristy3ed852e2009-09-05 21:47:34 +00002338 CacheInfo
2339 *cache_info;
2340
cristy0158a4b2010-09-20 13:59:45 +00002341 const int
2342 id = GetOpenMPThreadId();
2343
cristy4c08aed2011-07-01 19:47:50 +00002344 const Quantum
2345 *p;
cristy2036f5c2010-09-19 21:18:17 +00002346
cristy2ed42f62011-10-02 19:49:57 +00002347 register ssize_t
2348 i;
2349
cristy3ed852e2009-09-05 21:47:34 +00002350 assert(image != (const Image *) NULL);
2351 assert(image->signature == MagickSignature);
2352 assert(image->cache != (Cache) NULL);
2353 cache_info=(CacheInfo *) image->cache;
2354 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002355 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002356 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2357 (GetOneVirtualPixelFromHandler) NULL)
2358 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2359 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002360 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002361 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002362 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002363 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002364 {
2365 pixel[RedPixelChannel]=image->background_color.red;
2366 pixel[GreenPixelChannel]=image->background_color.green;
2367 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002368 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002369 pixel[AlphaPixelChannel]=image->background_color.alpha;
2370 return(MagickFalse);
2371 }
2372 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2373 {
2374 PixelChannel
2375 channel;
2376
2377 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2378 pixel[channel]=p[i];
2379 }
cristy2036f5c2010-09-19 21:18:17 +00002380 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002381}
2382
2383/*
2384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2385% %
2386% %
2387% %
2388% G e t O n e V i r t u a l P i x e l %
2389% %
2390% %
2391% %
2392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2393%
2394% GetOneVirtualPixel() returns a single virtual pixel at the specified
2395% (x,y) location. The image background color is returned if an error occurs.
2396% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2397%
2398% The format of the GetOneVirtualPixel() method is:
2399%
cristybb503372010-05-27 20:51:26 +00002400% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002401% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002402%
2403% A description of each parameter follows:
2404%
2405% o image: the image.
2406%
2407% o x,y: These values define the location of the pixel to return.
2408%
2409% o pixel: return a pixel at the specified (x,y) location.
2410%
2411% o exception: return any errors or warnings in this structure.
2412%
2413*/
2414MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002415 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002416{
cristy3ed852e2009-09-05 21:47:34 +00002417 CacheInfo
2418 *cache_info;
2419
cristy0158a4b2010-09-20 13:59:45 +00002420 const int
2421 id = GetOpenMPThreadId();
2422
cristy4c08aed2011-07-01 19:47:50 +00002423 const Quantum
2424 *p;
cristy2036f5c2010-09-19 21:18:17 +00002425
cristy2ed42f62011-10-02 19:49:57 +00002426 register ssize_t
2427 i;
2428
cristy3ed852e2009-09-05 21:47:34 +00002429 assert(image != (const Image *) NULL);
2430 assert(image->signature == MagickSignature);
2431 assert(image->cache != (Cache) NULL);
2432 cache_info=(CacheInfo *) image->cache;
2433 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002434 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002435 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2436 (GetOneVirtualPixelFromHandler) NULL)
2437 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2438 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002439 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002440 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002441 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002442 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002443 {
2444 pixel[RedPixelChannel]=image->background_color.red;
2445 pixel[GreenPixelChannel]=image->background_color.green;
2446 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002447 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002448 pixel[AlphaPixelChannel]=image->background_color.alpha;
2449 return(MagickFalse);
2450 }
2451 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2452 {
2453 PixelChannel
2454 channel;
2455
2456 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2457 pixel[channel]=p[i];
2458 }
cristy2036f5c2010-09-19 21:18:17 +00002459 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002460}
2461
2462/*
2463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464% %
2465% %
2466% %
2467+ 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 %
2468% %
2469% %
2470% %
2471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2472%
2473% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2474% specified (x,y) location. The image background color is returned if an
2475% error occurs.
2476%
2477% The format of the GetOneVirtualPixelFromCache() method is:
2478%
2479% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002480% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002481% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002482%
2483% A description of each parameter follows:
2484%
2485% o image: the image.
2486%
2487% o virtual_pixel_method: the virtual pixel method.
2488%
2489% o x,y: These values define the location of the pixel to return.
2490%
2491% o pixel: return a pixel at the specified (x,y) location.
2492%
2493% o exception: return any errors or warnings in this structure.
2494%
2495*/
2496static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002497 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002498 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002499{
cristy0158a4b2010-09-20 13:59:45 +00002500 CacheInfo
2501 *cache_info;
2502
2503 const int
2504 id = GetOpenMPThreadId();
2505
cristy4c08aed2011-07-01 19:47:50 +00002506 const Quantum
2507 *p;
cristy3ed852e2009-09-05 21:47:34 +00002508
cristy2ed42f62011-10-02 19:49:57 +00002509 register ssize_t
2510 i;
2511
cristye7cc7cf2010-09-21 13:26:47 +00002512 assert(image != (const Image *) NULL);
2513 assert(image->signature == MagickSignature);
2514 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002515 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002516 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002517 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002518 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002519 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002520 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002521 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002522 {
2523 pixel[RedPixelChannel]=image->background_color.red;
2524 pixel[GreenPixelChannel]=image->background_color.green;
2525 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002526 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002527 pixel[AlphaPixelChannel]=image->background_color.alpha;
2528 return(MagickFalse);
2529 }
2530 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2531 {
2532 PixelChannel
2533 channel;
2534
2535 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2536 pixel[channel]=p[i];
2537 }
cristy3ed852e2009-09-05 21:47:34 +00002538 return(MagickTrue);
2539}
2540
2541/*
2542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543% %
2544% %
2545% %
2546+ G e t P i x e l C a c h e C o l o r s p a c e %
2547% %
2548% %
2549% %
2550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551%
2552% GetPixelCacheColorspace() returns the class type of the pixel cache.
2553%
2554% The format of the GetPixelCacheColorspace() method is:
2555%
2556% Colorspace GetPixelCacheColorspace(Cache cache)
2557%
2558% A description of each parameter follows:
2559%
2560% o cache: the pixel cache.
2561%
2562*/
cristya6577ff2011-09-02 19:54:26 +00002563MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002564{
2565 CacheInfo
2566 *cache_info;
2567
2568 assert(cache != (Cache) NULL);
2569 cache_info=(CacheInfo *) cache;
2570 assert(cache_info->signature == MagickSignature);
2571 if (cache_info->debug != MagickFalse)
2572 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2573 cache_info->filename);
2574 return(cache_info->colorspace);
2575}
2576
2577/*
2578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2579% %
2580% %
2581% %
2582+ G e t P i x e l C a c h e M e t h o d s %
2583% %
2584% %
2585% %
2586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2587%
2588% GetPixelCacheMethods() initializes the CacheMethods structure.
2589%
2590% The format of the GetPixelCacheMethods() method is:
2591%
2592% void GetPixelCacheMethods(CacheMethods *cache_methods)
2593%
2594% A description of each parameter follows:
2595%
2596% o cache_methods: Specifies a pointer to a CacheMethods structure.
2597%
2598*/
cristya6577ff2011-09-02 19:54:26 +00002599MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002600{
2601 assert(cache_methods != (CacheMethods *) NULL);
2602 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2603 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2604 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002605 cache_methods->get_virtual_metacontent_from_handler=
2606 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002607 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2608 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002609 cache_methods->get_authentic_metacontent_from_handler=
2610 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002611 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2612 cache_methods->get_one_authentic_pixel_from_handler=
2613 GetOneAuthenticPixelFromCache;
2614 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2615 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2616 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2617}
2618
2619/*
2620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2621% %
2622% %
2623% %
2624+ G e t P i x e l C a c h e N e x u s E x t e n t %
2625% %
2626% %
2627% %
2628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629%
cristy4c08aed2011-07-01 19:47:50 +00002630% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2631% corresponding with the last call to SetPixelCacheNexusPixels() or
2632% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002633%
2634% The format of the GetPixelCacheNexusExtent() method is:
2635%
2636% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2637% NexusInfo *nexus_info)
2638%
2639% A description of each parameter follows:
2640%
2641% o nexus_info: the nexus info.
2642%
2643*/
cristya6577ff2011-09-02 19:54:26 +00002644MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002645 NexusInfo *nexus_info)
2646{
2647 CacheInfo
2648 *cache_info;
2649
2650 MagickSizeType
2651 extent;
2652
cristy9f027d12011-09-21 01:17:17 +00002653 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002654 cache_info=(CacheInfo *) cache;
2655 assert(cache_info->signature == MagickSignature);
2656 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2657 if (extent == 0)
2658 return((MagickSizeType) cache_info->columns*cache_info->rows);
2659 return(extent);
2660}
2661
2662/*
2663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2664% %
2665% %
2666% %
cristy4c08aed2011-07-01 19:47:50 +00002667+ 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 +00002668% %
2669% %
2670% %
2671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2672%
cristy4c08aed2011-07-01 19:47:50 +00002673% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2674% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002675%
cristy4c08aed2011-07-01 19:47:50 +00002676% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002677%
cristy4c08aed2011-07-01 19:47:50 +00002678% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002679% NexusInfo *nexus_info)
2680%
2681% A description of each parameter follows:
2682%
2683% o cache: the pixel cache.
2684%
cristy4c08aed2011-07-01 19:47:50 +00002685% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002686%
2687*/
cristya6577ff2011-09-02 19:54:26 +00002688MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002689 NexusInfo *nexus_info)
2690{
2691 CacheInfo
2692 *cache_info;
2693
cristy9f027d12011-09-21 01:17:17 +00002694 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002695 cache_info=(CacheInfo *) cache;
2696 assert(cache_info->signature == MagickSignature);
2697 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002698 return((void *) NULL);
2699 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002700}
2701
2702/*
2703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2704% %
2705% %
2706% %
2707+ G e t P i x e l C a c h e N e x u s P i x e l s %
2708% %
2709% %
2710% %
2711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712%
2713% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2714% cache nexus.
2715%
2716% The format of the GetPixelCacheNexusPixels() method is:
2717%
cristy4c08aed2011-07-01 19:47:50 +00002718% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002719% NexusInfo *nexus_info)
2720%
2721% A description of each parameter follows:
2722%
2723% o cache: the pixel cache.
2724%
2725% o nexus_info: the cache nexus to return the pixels.
2726%
2727*/
cristya6577ff2011-09-02 19:54:26 +00002728MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002729 NexusInfo *nexus_info)
2730{
2731 CacheInfo
2732 *cache_info;
2733
cristy9f027d12011-09-21 01:17:17 +00002734 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002735 cache_info=(CacheInfo *) cache;
2736 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002737 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002738 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002739 return(nexus_info->pixels);
2740}
2741
2742/*
2743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2744% %
2745% %
2746% %
cristy056ba772010-01-02 23:33:54 +00002747+ G e t P i x e l C a c h e P i x e l s %
2748% %
2749% %
2750% %
2751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752%
2753% GetPixelCachePixels() returns the pixels associated with the specified image.
2754%
2755% The format of the GetPixelCachePixels() method is:
2756%
cristyf84a1932010-01-03 18:00:18 +00002757% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2758% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002759%
2760% A description of each parameter follows:
2761%
2762% o image: the image.
2763%
2764% o length: the pixel cache length.
2765%
cristyf84a1932010-01-03 18:00:18 +00002766% o exception: return any errors or warnings in this structure.
2767%
cristy056ba772010-01-02 23:33:54 +00002768*/
cristyd1dd6e42011-09-04 01:46:08 +00002769MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002770 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002771{
2772 CacheInfo
2773 *cache_info;
2774
2775 assert(image != (const Image *) NULL);
2776 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002777 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002778 assert(length != (MagickSizeType *) NULL);
2779 assert(exception != (ExceptionInfo *) NULL);
2780 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002781 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002782 assert(cache_info->signature == MagickSignature);
2783 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002784 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002785 return((void *) NULL);
2786 *length=cache_info->length;
2787 return((void *) cache_info->pixels);
2788}
2789
2790/*
2791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2792% %
2793% %
2794% %
cristyb32b90a2009-09-07 21:45:48 +00002795+ 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 +00002796% %
2797% %
2798% %
2799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2800%
2801% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2802%
2803% The format of the GetPixelCacheStorageClass() method is:
2804%
2805% ClassType GetPixelCacheStorageClass(Cache cache)
2806%
2807% A description of each parameter follows:
2808%
2809% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2810%
2811% o cache: the pixel cache.
2812%
2813*/
cristya6577ff2011-09-02 19:54:26 +00002814MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002815{
2816 CacheInfo
2817 *cache_info;
2818
2819 assert(cache != (Cache) NULL);
2820 cache_info=(CacheInfo *) cache;
2821 assert(cache_info->signature == MagickSignature);
2822 if (cache_info->debug != MagickFalse)
2823 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2824 cache_info->filename);
2825 return(cache_info->storage_class);
2826}
2827
2828/*
2829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2830% %
2831% %
2832% %
cristyb32b90a2009-09-07 21:45:48 +00002833+ G e t P i x e l C a c h e T i l e S i z e %
2834% %
2835% %
2836% %
2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838%
2839% GetPixelCacheTileSize() returns the pixel cache tile size.
2840%
2841% The format of the GetPixelCacheTileSize() method is:
2842%
cristybb503372010-05-27 20:51:26 +00002843% void GetPixelCacheTileSize(const Image *image,size_t *width,
2844% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002845%
2846% A description of each parameter follows:
2847%
2848% o image: the image.
2849%
2850% o width: the optimize cache tile width in pixels.
2851%
2852% o height: the optimize cache tile height in pixels.
2853%
2854*/
cristya6577ff2011-09-02 19:54:26 +00002855MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002856 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002857{
cristy4c08aed2011-07-01 19:47:50 +00002858 CacheInfo
2859 *cache_info;
2860
cristyb32b90a2009-09-07 21:45:48 +00002861 assert(image != (Image *) NULL);
2862 assert(image->signature == MagickSignature);
2863 if (image->debug != MagickFalse)
2864 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002865 cache_info=(CacheInfo *) image->cache;
2866 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002867 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002868 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002869 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002870 *height=(*width);
2871}
2872
2873/*
2874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875% %
2876% %
2877% %
2878+ G e t P i x e l C a c h e T y p e %
2879% %
2880% %
2881% %
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883%
2884% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2885%
2886% The format of the GetPixelCacheType() method is:
2887%
2888% CacheType GetPixelCacheType(const Image *image)
2889%
2890% A description of each parameter follows:
2891%
2892% o image: the image.
2893%
2894*/
cristya6577ff2011-09-02 19:54:26 +00002895MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002896{
2897 CacheInfo
2898 *cache_info;
2899
2900 assert(image != (Image *) NULL);
2901 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002902 assert(image->cache != (Cache) NULL);
2903 cache_info=(CacheInfo *) image->cache;
2904 assert(cache_info->signature == MagickSignature);
2905 return(cache_info->type);
2906}
2907
2908/*
2909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2910% %
2911% %
2912% %
cristy3ed852e2009-09-05 21:47:34 +00002913+ 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 %
2914% %
2915% %
2916% %
2917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2918%
2919% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2920% pixel cache. A virtual pixel is any pixel access that is outside the
2921% boundaries of the image cache.
2922%
2923% The format of the GetPixelCacheVirtualMethod() method is:
2924%
2925% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2926%
2927% A description of each parameter follows:
2928%
2929% o image: the image.
2930%
2931*/
cristyd1dd6e42011-09-04 01:46:08 +00002932MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002933{
2934 CacheInfo
2935 *cache_info;
2936
2937 assert(image != (Image *) NULL);
2938 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002939 assert(image->cache != (Cache) NULL);
2940 cache_info=(CacheInfo *) image->cache;
2941 assert(cache_info->signature == MagickSignature);
2942 return(cache_info->virtual_pixel_method);
2943}
2944
2945/*
2946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2947% %
2948% %
2949% %
cristy4c08aed2011-07-01 19:47:50 +00002950+ 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 +00002951% %
2952% %
2953% %
2954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2955%
cristy4c08aed2011-07-01 19:47:50 +00002956% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2957% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002958%
cristy4c08aed2011-07-01 19:47:50 +00002959% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002960%
cristy4c08aed2011-07-01 19:47:50 +00002961% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002962%
2963% A description of each parameter follows:
2964%
2965% o image: the image.
2966%
2967*/
cristy4c08aed2011-07-01 19:47:50 +00002968static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002969{
2970 CacheInfo
2971 *cache_info;
2972
cristy5c9e6f22010-09-17 17:31:01 +00002973 const int
2974 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002975
cristy4c08aed2011-07-01 19:47:50 +00002976 const void
2977 *metacontent;
2978
cristye7cc7cf2010-09-21 13:26:47 +00002979 assert(image != (const Image *) NULL);
2980 assert(image->signature == MagickSignature);
2981 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002982 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002983 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002984 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002985 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2986 cache_info->nexus_info[id]);
2987 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002988}
2989
2990/*
2991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2992% %
2993% %
2994% %
cristy4c08aed2011-07-01 19:47:50 +00002995+ 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 +00002996% %
2997% %
2998% %
2999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3000%
cristy4c08aed2011-07-01 19:47:50 +00003001% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
3002% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00003003%
cristy4c08aed2011-07-01 19:47:50 +00003004% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00003005%
cristy4c08aed2011-07-01 19:47:50 +00003006% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003007% NexusInfo *nexus_info)
3008%
3009% A description of each parameter follows:
3010%
3011% o cache: the pixel cache.
3012%
cristy4c08aed2011-07-01 19:47:50 +00003013% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00003014%
3015*/
cristya6577ff2011-09-02 19:54:26 +00003016MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00003017 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00003018{
3019 CacheInfo
3020 *cache_info;
3021
cristye7cc7cf2010-09-21 13:26:47 +00003022 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003023 cache_info=(CacheInfo *) cache;
3024 assert(cache_info->signature == MagickSignature);
3025 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003026 return((void *) NULL);
3027 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003028}
3029
3030/*
3031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3032% %
3033% %
3034% %
cristy4c08aed2011-07-01 19:47:50 +00003035% 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 +00003036% %
3037% %
3038% %
3039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040%
cristy4c08aed2011-07-01 19:47:50 +00003041% GetVirtualMetacontent() returns the virtual metacontent corresponding with
3042% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3043% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003044%
cristy4c08aed2011-07-01 19:47:50 +00003045% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003046%
cristy4c08aed2011-07-01 19:47:50 +00003047% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003048%
3049% A description of each parameter follows:
3050%
3051% o image: the image.
3052%
3053*/
cristy4c08aed2011-07-01 19:47:50 +00003054MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003055{
3056 CacheInfo
3057 *cache_info;
3058
cristy2036f5c2010-09-19 21:18:17 +00003059 const int
3060 id = GetOpenMPThreadId();
3061
cristy4c08aed2011-07-01 19:47:50 +00003062 const void
3063 *metacontent;
3064
cristy3ed852e2009-09-05 21:47:34 +00003065 assert(image != (const Image *) NULL);
3066 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003067 assert(image->cache != (Cache) NULL);
3068 cache_info=(CacheInfo *) image->cache;
3069 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003070 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3071 (GetVirtualMetacontentFromHandler) NULL)
3072 {
3073 metacontent=cache_info->methods.
3074 get_virtual_metacontent_from_handler(image);
3075 return(metacontent);
3076 }
cristy2036f5c2010-09-19 21:18:17 +00003077 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003078 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3079 cache_info->nexus_info[id]);
3080 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003081}
3082
3083/*
3084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3085% %
3086% %
3087% %
3088+ 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 %
3089% %
3090% %
3091% %
3092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3093%
3094% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3095% pixel cache as defined by the geometry parameters. A pointer to the pixels
3096% is returned if the pixels are transferred, otherwise a NULL is returned.
3097%
3098% The format of the GetVirtualPixelsFromNexus() method is:
3099%
cristy4c08aed2011-07-01 19:47:50 +00003100% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003101% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003102% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3103% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003104%
3105% A description of each parameter follows:
3106%
3107% o image: the image.
3108%
3109% o virtual_pixel_method: the virtual pixel method.
3110%
3111% o x,y,columns,rows: These values define the perimeter of a region of
3112% pixels.
3113%
3114% o nexus_info: the cache nexus to acquire.
3115%
3116% o exception: return any errors or warnings in this structure.
3117%
3118*/
3119
cristybb503372010-05-27 20:51:26 +00003120static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003121 DitherMatrix[64] =
3122 {
3123 0, 48, 12, 60, 3, 51, 15, 63,
3124 32, 16, 44, 28, 35, 19, 47, 31,
3125 8, 56, 4, 52, 11, 59, 7, 55,
3126 40, 24, 36, 20, 43, 27, 39, 23,
3127 2, 50, 14, 62, 1, 49, 13, 61,
3128 34, 18, 46, 30, 33, 17, 45, 29,
3129 10, 58, 6, 54, 9, 57, 5, 53,
3130 42, 26, 38, 22, 41, 25, 37, 21
3131 };
3132
cristybb503372010-05-27 20:51:26 +00003133static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003134{
cristybb503372010-05-27 20:51:26 +00003135 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003136 index;
3137
3138 index=x+DitherMatrix[x & 0x07]-32L;
3139 if (index < 0L)
3140 return(0L);
cristybb503372010-05-27 20:51:26 +00003141 if (index >= (ssize_t) columns)
3142 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003143 return(index);
3144}
3145
cristybb503372010-05-27 20:51:26 +00003146static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003147{
cristybb503372010-05-27 20:51:26 +00003148 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003149 index;
3150
3151 index=y+DitherMatrix[y & 0x07]-32L;
3152 if (index < 0L)
3153 return(0L);
cristybb503372010-05-27 20:51:26 +00003154 if (index >= (ssize_t) rows)
3155 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003156 return(index);
3157}
3158
cristybb503372010-05-27 20:51:26 +00003159static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003160{
3161 if (x < 0L)
3162 return(0L);
cristybb503372010-05-27 20:51:26 +00003163 if (x >= (ssize_t) columns)
3164 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003165 return(x);
3166}
3167
cristybb503372010-05-27 20:51:26 +00003168static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003169{
3170 if (y < 0L)
3171 return(0L);
cristybb503372010-05-27 20:51:26 +00003172 if (y >= (ssize_t) rows)
3173 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003174 return(y);
3175}
3176
cristybb503372010-05-27 20:51:26 +00003177static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003178{
cristybb503372010-05-27 20:51:26 +00003179 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003180}
3181
cristybb503372010-05-27 20:51:26 +00003182static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003183{
cristybb503372010-05-27 20:51:26 +00003184 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003185}
3186
cristybb503372010-05-27 20:51:26 +00003187static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3188 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003189{
3190 MagickModulo
3191 modulo;
3192
cristy6162bb42011-07-18 11:34:09 +00003193 /*
3194 Compute the remainder of dividing offset by extent. It returns not only
3195 the quotient (tile the offset falls in) but also the positive remainer
3196 within that tile such that 0 <= remainder < extent. This method is
3197 essentially a ldiv() using a floored modulo division rather than the
3198 normal default truncated modulo division.
3199 */
cristybb503372010-05-27 20:51:26 +00003200 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003201 if (offset < 0L)
3202 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003203 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003204 return(modulo);
3205}
3206
cristya6577ff2011-09-02 19:54:26 +00003207MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003208 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3209 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003210 ExceptionInfo *exception)
3211{
3212 CacheInfo
3213 *cache_info;
3214
3215 MagickOffsetType
3216 offset;
3217
3218 MagickSizeType
3219 length,
3220 number_pixels;
3221
3222 NexusInfo
3223 **virtual_nexus;
3224
cristy4c08aed2011-07-01 19:47:50 +00003225 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003226 *pixels,
cristy105ba3c2011-07-18 02:28:38 +00003227 virtual_pixel[MaxPixelChannels];
cristy3ed852e2009-09-05 21:47:34 +00003228
3229 RectangleInfo
3230 region;
3231
cristy4c08aed2011-07-01 19:47:50 +00003232 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003233 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003234
cristy4c08aed2011-07-01 19:47:50 +00003235 register const void
3236 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003237
cristy4c08aed2011-07-01 19:47:50 +00003238 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003239 *restrict q;
3240
cristybb503372010-05-27 20:51:26 +00003241 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003242 i,
3243 u;
cristy3ed852e2009-09-05 21:47:34 +00003244
cristy4c08aed2011-07-01 19:47:50 +00003245 register unsigned char
3246 *restrict s;
3247
cristy105ba3c2011-07-18 02:28:38 +00003248 ssize_t
3249 v;
3250
cristy4c08aed2011-07-01 19:47:50 +00003251 void
cristy105ba3c2011-07-18 02:28:38 +00003252 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003253
cristy3ed852e2009-09-05 21:47:34 +00003254 /*
3255 Acquire pixels.
3256 */
cristye7cc7cf2010-09-21 13:26:47 +00003257 assert(image != (const Image *) NULL);
3258 assert(image->signature == MagickSignature);
3259 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003260 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003261 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003262 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003263 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003264 region.x=x;
3265 region.y=y;
3266 region.width=columns;
3267 region.height=rows;
3268 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003269 if (pixels == (Quantum *) NULL)
3270 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003271 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003272 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3273 nexus_info->region.x;
3274 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3275 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003276 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3277 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003278 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3279 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003280 {
3281 MagickBooleanType
3282 status;
3283
3284 /*
3285 Pixel request is inside cache extents.
3286 */
cristy4c08aed2011-07-01 19:47:50 +00003287 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003288 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003289 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3290 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003291 return((const Quantum *) NULL);
3292 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003293 {
cristy4c08aed2011-07-01 19:47:50 +00003294 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003295 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003296 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003297 }
cristyacd2ed22011-08-30 01:44:23 +00003298 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003299 }
3300 /*
3301 Pixel request is outside cache extents.
3302 */
cristy4c08aed2011-07-01 19:47:50 +00003303 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003304 virtual_nexus=AcquirePixelCacheNexus(1);
3305 if (virtual_nexus == (NexusInfo **) NULL)
3306 {
cristy4c08aed2011-07-01 19:47:50 +00003307 if (virtual_nexus != (NexusInfo **) NULL)
3308 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003309 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3310 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003311 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003312 }
cristy105ba3c2011-07-18 02:28:38 +00003313 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3314 sizeof(*virtual_pixel));
3315 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003316 switch (virtual_pixel_method)
3317 {
cristy4c08aed2011-07-01 19:47:50 +00003318 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003319 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003320 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003321 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003322 case MaskVirtualPixelMethod:
3323 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003324 case EdgeVirtualPixelMethod:
3325 case CheckerTileVirtualPixelMethod:
3326 case HorizontalTileVirtualPixelMethod:
3327 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003328 {
cristy4c08aed2011-07-01 19:47:50 +00003329 if (cache_info->metacontent_extent != 0)
3330 {
cristy6162bb42011-07-18 11:34:09 +00003331 /*
3332 Acquire a metacontent buffer.
3333 */
cristya64b85d2011-09-14 01:02:31 +00003334 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003335 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003336 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003337 {
cristy4c08aed2011-07-01 19:47:50 +00003338 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3339 (void) ThrowMagickException(exception,GetMagickModule(),
3340 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3341 return((const Quantum *) NULL);
3342 }
cristy105ba3c2011-07-18 02:28:38 +00003343 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003344 cache_info->metacontent_extent);
3345 }
3346 switch (virtual_pixel_method)
3347 {
3348 case BlackVirtualPixelMethod:
3349 {
cristy30301712011-07-18 15:06:51 +00003350 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3351 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003352 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3353 break;
3354 }
3355 case GrayVirtualPixelMethod:
3356 {
cristy30301712011-07-18 15:06:51 +00003357 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003358 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3359 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003360 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3361 break;
3362 }
3363 case TransparentVirtualPixelMethod:
3364 {
cristy30301712011-07-18 15:06:51 +00003365 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3366 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003367 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3368 break;
3369 }
3370 case MaskVirtualPixelMethod:
3371 case WhiteVirtualPixelMethod:
3372 {
cristy30301712011-07-18 15:06:51 +00003373 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3374 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003375 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3376 break;
3377 }
3378 default:
3379 {
3380 SetPixelRed(image,image->background_color.red,virtual_pixel);
3381 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3382 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003383 if (image->colorspace == CMYKColorspace)
3384 SetPixelBlack(image,image->background_color.black,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003385 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3386 break;
3387 }
3388 }
cristy3ed852e2009-09-05 21:47:34 +00003389 break;
3390 }
3391 default:
cristy3ed852e2009-09-05 21:47:34 +00003392 break;
cristy3ed852e2009-09-05 21:47:34 +00003393 }
cristybb503372010-05-27 20:51:26 +00003394 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003395 {
cristybb503372010-05-27 20:51:26 +00003396 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003397 {
3398 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003399 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003400 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3401 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003402 {
3403 MagickModulo
3404 x_modulo,
3405 y_modulo;
3406
3407 /*
3408 Transfer a single pixel.
3409 */
3410 length=(MagickSizeType) 1;
3411 switch (virtual_pixel_method)
3412 {
cristy3ed852e2009-09-05 21:47:34 +00003413 default:
3414 {
3415 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003416 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003417 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003418 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003419 break;
3420 }
3421 case RandomVirtualPixelMethod:
3422 {
3423 if (cache_info->random_info == (RandomInfo *) NULL)
3424 cache_info->random_info=AcquireRandomInfo();
3425 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003426 RandomX(cache_info->random_info,cache_info->columns),
3427 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003428 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003429 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003430 break;
3431 }
3432 case DitherVirtualPixelMethod:
3433 {
3434 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003435 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003436 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003437 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003438 break;
3439 }
3440 case TileVirtualPixelMethod:
3441 {
3442 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3443 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3444 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003445 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003446 exception);
cristy4c08aed2011-07-01 19:47:50 +00003447 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003448 break;
3449 }
3450 case MirrorVirtualPixelMethod:
3451 {
3452 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3453 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003454 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003455 x_modulo.remainder-1L;
3456 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3457 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003458 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003459 y_modulo.remainder-1L;
3460 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003461 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003462 exception);
cristy4c08aed2011-07-01 19:47:50 +00003463 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003464 break;
3465 }
3466 case HorizontalTileEdgeVirtualPixelMethod:
3467 {
3468 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3469 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003470 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003471 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003472 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003473 break;
3474 }
3475 case VerticalTileEdgeVirtualPixelMethod:
3476 {
3477 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3478 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003479 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003480 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003481 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3482 break;
3483 }
3484 case BackgroundVirtualPixelMethod:
3485 case BlackVirtualPixelMethod:
3486 case GrayVirtualPixelMethod:
3487 case TransparentVirtualPixelMethod:
3488 case MaskVirtualPixelMethod:
3489 case WhiteVirtualPixelMethod:
3490 {
3491 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003492 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003493 break;
3494 }
3495 case EdgeVirtualPixelMethod:
3496 case CheckerTileVirtualPixelMethod:
3497 {
3498 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3499 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3500 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3501 {
3502 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003503 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003504 break;
3505 }
3506 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3507 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3508 exception);
3509 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3510 break;
3511 }
3512 case HorizontalTileVirtualPixelMethod:
3513 {
3514 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3515 {
3516 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003517 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003518 break;
3519 }
3520 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3521 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3522 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3523 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3524 exception);
3525 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3526 break;
3527 }
3528 case VerticalTileVirtualPixelMethod:
3529 {
3530 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3531 {
3532 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003533 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003534 break;
3535 }
3536 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3537 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3538 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3539 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3540 exception);
3541 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003542 break;
3543 }
3544 }
cristy4c08aed2011-07-01 19:47:50 +00003545 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003546 break;
cristyed231572011-07-14 02:18:59 +00003547 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003548 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003549 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003550 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003551 {
3552 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3553 s+=cache_info->metacontent_extent;
3554 }
cristy3ed852e2009-09-05 21:47:34 +00003555 continue;
3556 }
3557 /*
3558 Transfer a run of pixels.
3559 */
cristy4c08aed2011-07-01 19:47:50 +00003560 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3561 length,1UL,*virtual_nexus,exception);
3562 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003563 break;
cristy4c08aed2011-07-01 19:47:50 +00003564 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003565 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3566 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003567 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003568 {
cristy4c08aed2011-07-01 19:47:50 +00003569 (void) memcpy(s,r,(size_t) length);
3570 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003571 }
3572 }
3573 }
cristy4c08aed2011-07-01 19:47:50 +00003574 /*
3575 Free resources.
3576 */
cristy105ba3c2011-07-18 02:28:38 +00003577 if (virtual_metacontent != (void *) NULL)
3578 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003579 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3580 return(pixels);
3581}
3582
3583/*
3584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3585% %
3586% %
3587% %
3588+ G e t V i r t u a l P i x e l C a c h e %
3589% %
3590% %
3591% %
3592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3593%
3594% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3595% cache as defined by the geometry parameters. A pointer to the pixels
3596% is returned if the pixels are transferred, otherwise a NULL is returned.
3597%
3598% The format of the GetVirtualPixelCache() method is:
3599%
cristy4c08aed2011-07-01 19:47:50 +00003600% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003601% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3602% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003603% ExceptionInfo *exception)
3604%
3605% A description of each parameter follows:
3606%
3607% o image: the image.
3608%
3609% o virtual_pixel_method: the virtual pixel method.
3610%
3611% o x,y,columns,rows: These values define the perimeter of a region of
3612% pixels.
3613%
3614% o exception: return any errors or warnings in this structure.
3615%
3616*/
cristy4c08aed2011-07-01 19:47:50 +00003617static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003618 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3619 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003620{
3621 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003622 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003623
cristy5c9e6f22010-09-17 17:31:01 +00003624 const int
3625 id = GetOpenMPThreadId();
3626
cristy4c08aed2011-07-01 19:47:50 +00003627 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003628 *p;
cristy4c08aed2011-07-01 19:47:50 +00003629
cristye7cc7cf2010-09-21 13:26:47 +00003630 assert(image != (const Image *) NULL);
3631 assert(image->signature == MagickSignature);
3632 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003633 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003634 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003635 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003636 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003637 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003638 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003639}
3640
3641/*
3642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3643% %
3644% %
3645% %
3646% G e t V i r t u a l P i x e l Q u e u e %
3647% %
3648% %
3649% %
3650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3651%
cristy4c08aed2011-07-01 19:47:50 +00003652% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3653% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003654%
3655% The format of the GetVirtualPixelQueue() method is:
3656%
cristy4c08aed2011-07-01 19:47:50 +00003657% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003658%
3659% A description of each parameter follows:
3660%
3661% o image: the image.
3662%
3663*/
cristy4c08aed2011-07-01 19:47:50 +00003664MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003665{
3666 CacheInfo
3667 *cache_info;
3668
cristy2036f5c2010-09-19 21:18:17 +00003669 const int
3670 id = GetOpenMPThreadId();
3671
cristy3ed852e2009-09-05 21:47:34 +00003672 assert(image != (const Image *) NULL);
3673 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003674 assert(image->cache != (Cache) NULL);
3675 cache_info=(CacheInfo *) image->cache;
3676 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003677 if (cache_info->methods.get_virtual_pixels_handler !=
3678 (GetVirtualPixelsHandler) NULL)
3679 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003680 assert(id < (int) cache_info->number_threads);
3681 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003682}
3683
3684/*
3685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3686% %
3687% %
3688% %
3689% G e t V i r t u a l P i x e l s %
3690% %
3691% %
3692% %
3693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3694%
3695% GetVirtualPixels() returns an immutable pixel region. If the
3696% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003697% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003698% copy of the pixels or it may point to the original pixels in memory.
3699% Performance is maximized if the selected region is part of one row, or one
3700% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003701% (without a copy) if the image is in memory, or in a memory-mapped file. The
3702% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003703%
3704% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003705% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3706% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3707% access the meta-content (of type void) corresponding to the the
3708% region.
cristy3ed852e2009-09-05 21:47:34 +00003709%
3710% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3711%
3712% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3713% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3714% GetCacheViewAuthenticPixels() instead.
3715%
3716% The format of the GetVirtualPixels() method is:
3717%
cristy4c08aed2011-07-01 19:47:50 +00003718% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003719% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003720% ExceptionInfo *exception)
3721%
3722% A description of each parameter follows:
3723%
3724% o image: the image.
3725%
3726% o x,y,columns,rows: These values define the perimeter of a region of
3727% pixels.
3728%
3729% o exception: return any errors or warnings in this structure.
3730%
3731*/
cristy4c08aed2011-07-01 19:47:50 +00003732MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003733 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3734 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003735{
3736 CacheInfo
3737 *cache_info;
3738
cristy2036f5c2010-09-19 21:18:17 +00003739 const int
3740 id = GetOpenMPThreadId();
3741
cristy4c08aed2011-07-01 19:47:50 +00003742 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003743 *p;
cristy4c08aed2011-07-01 19:47:50 +00003744
cristy3ed852e2009-09-05 21:47:34 +00003745 assert(image != (const Image *) NULL);
3746 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003747 assert(image->cache != (Cache) NULL);
3748 cache_info=(CacheInfo *) image->cache;
3749 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003750 if (cache_info->methods.get_virtual_pixel_handler !=
3751 (GetVirtualPixelHandler) NULL)
3752 return(cache_info->methods.get_virtual_pixel_handler(image,
3753 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003754 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003755 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003756 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003757 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003758}
3759
3760/*
3761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3762% %
3763% %
3764% %
3765+ 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 %
3766% %
3767% %
3768% %
3769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3770%
cristy4c08aed2011-07-01 19:47:50 +00003771% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3772% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003773%
3774% The format of the GetVirtualPixelsCache() method is:
3775%
cristy4c08aed2011-07-01 19:47:50 +00003776% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003777%
3778% A description of each parameter follows:
3779%
3780% o image: the image.
3781%
3782*/
cristy4c08aed2011-07-01 19:47:50 +00003783static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003784{
3785 CacheInfo
3786 *cache_info;
3787
cristy5c9e6f22010-09-17 17:31:01 +00003788 const int
3789 id = GetOpenMPThreadId();
3790
cristye7cc7cf2010-09-21 13:26:47 +00003791 assert(image != (const Image *) NULL);
3792 assert(image->signature == MagickSignature);
3793 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003794 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003795 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003796 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003797 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003798}
3799
3800/*
3801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3802% %
3803% %
3804% %
3805+ G e t V i r t u a l P i x e l s N e x u s %
3806% %
3807% %
3808% %
3809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3810%
3811% GetVirtualPixelsNexus() returns the pixels associated with the specified
3812% cache nexus.
3813%
3814% The format of the GetVirtualPixelsNexus() method is:
3815%
cristy4c08aed2011-07-01 19:47:50 +00003816% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003817% NexusInfo *nexus_info)
3818%
3819% A description of each parameter follows:
3820%
3821% o cache: the pixel cache.
3822%
3823% o nexus_info: the cache nexus to return the colormap pixels.
3824%
3825*/
cristya6577ff2011-09-02 19:54:26 +00003826MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003827 NexusInfo *nexus_info)
3828{
3829 CacheInfo
3830 *cache_info;
3831
cristye7cc7cf2010-09-21 13:26:47 +00003832 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003833 cache_info=(CacheInfo *) cache;
3834 assert(cache_info->signature == MagickSignature);
3835 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003836 return((Quantum *) NULL);
3837 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003838}
3839
3840/*
3841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3842% %
3843% %
3844% %
3845+ M a s k P i x e l C a c h e N e x u s %
3846% %
3847% %
3848% %
3849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3850%
3851% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3852% The method returns MagickTrue if the pixel region is masked, otherwise
3853% MagickFalse.
3854%
3855% The format of the MaskPixelCacheNexus() method is:
3856%
3857% MagickBooleanType MaskPixelCacheNexus(Image *image,
3858% NexusInfo *nexus_info,ExceptionInfo *exception)
3859%
3860% A description of each parameter follows:
3861%
3862% o image: the image.
3863%
3864% o nexus_info: the cache nexus to clip.
3865%
3866% o exception: return any errors or warnings in this structure.
3867%
3868*/
3869
cristy4c08aed2011-07-01 19:47:50 +00003870static inline void MagickPixelCompositeMask(const PixelInfo *p,
3871 const MagickRealType alpha,const PixelInfo *q,
3872 const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003873{
3874 MagickRealType
3875 gamma;
3876
cristyaa83c2c2011-09-21 13:36:25 +00003877 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003878 {
3879 *composite=(*q);
3880 return;
3881 }
3882 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3883 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003884 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3885 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3886 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003887 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003888 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003889}
3890
3891static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3892 ExceptionInfo *exception)
3893{
3894 CacheInfo
3895 *cache_info;
3896
cristy4c08aed2011-07-01 19:47:50 +00003897 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003898 alpha,
3899 beta;
3900
3901 MagickSizeType
3902 number_pixels;
3903
3904 NexusInfo
3905 **clip_nexus,
3906 **image_nexus;
3907
cristy4c08aed2011-07-01 19:47:50 +00003908 register const Quantum
3909 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003910 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003911
cristy4c08aed2011-07-01 19:47:50 +00003912 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003913 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003914
cristye076a6e2010-08-15 19:59:43 +00003915 register ssize_t
3916 i;
3917
cristy3ed852e2009-09-05 21:47:34 +00003918 /*
3919 Apply clip mask.
3920 */
3921 if (image->debug != MagickFalse)
3922 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3923 if (image->mask == (Image *) NULL)
3924 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003925 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003926 if (cache_info == (Cache) NULL)
3927 return(MagickFalse);
3928 image_nexus=AcquirePixelCacheNexus(1);
3929 clip_nexus=AcquirePixelCacheNexus(1);
3930 if ((image_nexus == (NexusInfo **) NULL) ||
3931 (clip_nexus == (NexusInfo **) NULL))
3932 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003933 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3934 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3935 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003936 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003937 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3938 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003939 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003940 GetPixelInfo(image,&alpha);
3941 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003942 number_pixels=(MagickSizeType) nexus_info->region.width*
3943 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003944 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003945 {
cristy4c08aed2011-07-01 19:47:50 +00003946 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003947 break;
cristy4c08aed2011-07-01 19:47:50 +00003948 SetPixelInfo(image,p,&alpha);
3949 SetPixelInfo(image,q,&beta);
3950 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3951 &alpha,alpha.alpha,&beta);
3952 SetPixelRed(image,ClampToQuantum(beta.red),q);
3953 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3954 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3955 if (cache_info->colorspace == CMYKColorspace)
3956 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3957 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003958 p++;
3959 q++;
3960 r++;
3961 }
3962 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3963 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003964 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003965 return(MagickFalse);
3966 return(MagickTrue);
3967}
3968
3969/*
3970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3971% %
3972% %
3973% %
3974+ O p e n P i x e l C a c h e %
3975% %
3976% %
3977% %
3978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3979%
3980% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3981% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003982% metacontent, and memory mapping the cache if it is disk based. The cache
3983% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003984%
3985% The format of the OpenPixelCache() method is:
3986%
3987% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3988% ExceptionInfo *exception)
3989%
3990% A description of each parameter follows:
3991%
3992% o image: the image.
3993%
3994% o mode: ReadMode, WriteMode, or IOMode.
3995%
3996% o exception: return any errors or warnings in this structure.
3997%
3998*/
3999
cristyd43a46b2010-01-21 02:13:41 +00004000static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004001{
4002 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00004003 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00004004 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004005 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004006 {
4007 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004008 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00004009 cache_info->length);
4010 }
4011}
4012
4013static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4014{
4015 CacheInfo
4016 *cache_info;
4017
4018 MagickOffsetType
4019 count,
4020 extent,
4021 offset;
4022
4023 cache_info=(CacheInfo *) image->cache;
4024 if (image->debug != MagickFalse)
4025 {
4026 char
4027 format[MaxTextExtent],
4028 message[MaxTextExtent];
4029
cristyb9080c92009-12-01 20:13:26 +00004030 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004031 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004032 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004033 cache_info->cache_filename,cache_info->file,format);
4034 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4035 }
4036 if (length != (MagickSizeType) ((MagickOffsetType) length))
4037 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004038 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004039 if (extent < 0)
4040 return(MagickFalse);
4041 if ((MagickSizeType) extent >= length)
4042 return(MagickTrue);
4043 offset=(MagickOffsetType) length-1;
4044 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4045 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4046}
4047
4048static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4049 ExceptionInfo *exception)
4050{
cristy3ed852e2009-09-05 21:47:34 +00004051 CacheInfo
4052 *cache_info,
4053 source_info;
4054
cristyf3a6a9d2010-11-07 21:02:56 +00004055 char
4056 format[MaxTextExtent],
4057 message[MaxTextExtent];
4058
cristy4c08aed2011-07-01 19:47:50 +00004059 MagickBooleanType
4060 status;
4061
cristy3ed852e2009-09-05 21:47:34 +00004062 MagickSizeType
4063 length,
4064 number_pixels;
4065
cristy3ed852e2009-09-05 21:47:34 +00004066 size_t
cristye076a6e2010-08-15 19:59:43 +00004067 columns,
cristy3ed852e2009-09-05 21:47:34 +00004068 packet_size;
4069
cristye7cc7cf2010-09-21 13:26:47 +00004070 assert(image != (const Image *) NULL);
4071 assert(image->signature == MagickSignature);
4072 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004073 if (image->debug != MagickFalse)
4074 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4075 if ((image->columns == 0) || (image->rows == 0))
4076 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4077 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004078 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004079 source_info=(*cache_info);
4080 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004081 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004082 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004083 cache_info->storage_class=image->storage_class;
4084 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004085 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004086 cache_info->rows=image->rows;
4087 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004088 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004089 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004090 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004091 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004092 if (image->ping != MagickFalse)
4093 {
cristy73724512010-04-12 14:43:14 +00004094 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004095 cache_info->pixels=(Quantum *) NULL;
4096 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004097 cache_info->length=0;
4098 return(MagickTrue);
4099 }
cristy3ed852e2009-09-05 21:47:34 +00004100 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004101 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004102 if (image->metacontent_extent != 0)
4103 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004104 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004105 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004106 if (cache_info->columns != columns)
4107 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4108 image->filename);
4109 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004110 if ((cache_info->type != UndefinedCache) &&
4111 (cache_info->columns <= source_info.columns) &&
4112 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004113 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004114 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4115 {
4116 /*
4117 Inline pixel cache clone optimization.
4118 */
4119 if ((cache_info->columns == source_info.columns) &&
4120 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004121 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004122 (cache_info->metacontent_extent == source_info.metacontent_extent))
4123 return(MagickTrue);
4124 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4125 }
cristy3ed852e2009-09-05 21:47:34 +00004126 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004127 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004128 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004129 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4130 {
4131 status=AcquireMagickResource(MemoryResource,cache_info->length);
4132 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4133 (cache_info->type == MemoryCache))
4134 {
cristyd43a46b2010-01-21 02:13:41 +00004135 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004136 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004137 cache_info->pixels=source_info.pixels;
4138 else
4139 {
4140 /*
4141 Create memory pixel cache.
4142 */
cristy4c08aed2011-07-01 19:47:50 +00004143 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004144 if (image->debug != MagickFalse)
4145 {
cristy97e7a572009-12-05 15:07:53 +00004146 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004147 format);
cristyb51dff52011-05-19 16:55:47 +00004148 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004149 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4150 cache_info->filename,cache_info->mapped != MagickFalse ?
4151 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004152 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004153 format);
cristy3ed852e2009-09-05 21:47:34 +00004154 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4155 message);
4156 }
cristy3ed852e2009-09-05 21:47:34 +00004157 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004158 cache_info->metacontent=(void *) NULL;
4159 if (cache_info->metacontent_extent != 0)
4160 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004161 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004162 if (source_info.storage_class != UndefinedClass)
4163 {
cristy4c08aed2011-07-01 19:47:50 +00004164 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004165 exception);
4166 RelinquishPixelCachePixels(&source_info);
4167 }
cristy4c08aed2011-07-01 19:47:50 +00004168 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004169 }
4170 }
4171 RelinquishMagickResource(MemoryResource,cache_info->length);
4172 }
4173 /*
4174 Create pixel cache on disk.
4175 */
4176 status=AcquireMagickResource(DiskResource,cache_info->length);
4177 if (status == MagickFalse)
4178 {
4179 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4180 "CacheResourcesExhausted","`%s'",image->filename);
4181 return(MagickFalse);
4182 }
4183 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4184 {
4185 RelinquishMagickResource(DiskResource,cache_info->length);
4186 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4187 image->filename);
4188 return(MagickFalse);
4189 }
4190 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4191 cache_info->length);
4192 if (status == MagickFalse)
4193 {
4194 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4195 image->filename);
4196 return(MagickFalse);
4197 }
cristyed231572011-07-14 02:18:59 +00004198 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004199 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004200 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004201 cache_info->type=DiskCache;
4202 else
4203 {
4204 status=AcquireMagickResource(MapResource,cache_info->length);
4205 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4206 (cache_info->type != MemoryCache))
4207 cache_info->type=DiskCache;
4208 else
4209 {
cristy4c08aed2011-07-01 19:47:50 +00004210 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004211 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004212 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004213 {
cristy3ed852e2009-09-05 21:47:34 +00004214 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004215 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004216 }
4217 else
4218 {
4219 /*
4220 Create file-backed memory-mapped pixel cache.
4221 */
cristy4c08aed2011-07-01 19:47:50 +00004222 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004223 (void) ClosePixelCacheOnDisk(cache_info);
4224 cache_info->type=MapCache;
4225 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004226 cache_info->metacontent=(void *) NULL;
4227 if (cache_info->metacontent_extent != 0)
4228 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004229 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004230 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004231 {
4232 status=ClonePixelCachePixels(cache_info,&source_info,
4233 exception);
4234 RelinquishPixelCachePixels(&source_info);
4235 }
4236 if (image->debug != MagickFalse)
4237 {
cristy97e7a572009-12-05 15:07:53 +00004238 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004239 format);
cristyb51dff52011-05-19 16:55:47 +00004240 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004241 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004242 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004243 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004244 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004245 format);
cristy3ed852e2009-09-05 21:47:34 +00004246 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4247 message);
4248 }
cristy4c08aed2011-07-01 19:47:50 +00004249 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004250 }
4251 }
4252 RelinquishMagickResource(MapResource,cache_info->length);
4253 }
cristy4c08aed2011-07-01 19:47:50 +00004254 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004255 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4256 {
4257 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4258 RelinquishPixelCachePixels(&source_info);
4259 }
4260 if (image->debug != MagickFalse)
4261 {
cristyb9080c92009-12-01 20:13:26 +00004262 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004263 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004264 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004265 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004266 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004267 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004268 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4269 }
cristy4c08aed2011-07-01 19:47:50 +00004270 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004271}
4272
4273/*
4274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4275% %
4276% %
4277% %
4278+ P e r s i s t P i x e l C a c h e %
4279% %
4280% %
4281% %
4282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4283%
4284% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4285% persistent pixel cache is one that resides on disk and is not destroyed
4286% when the program exits.
4287%
4288% The format of the PersistPixelCache() method is:
4289%
4290% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4291% const MagickBooleanType attach,MagickOffsetType *offset,
4292% ExceptionInfo *exception)
4293%
4294% A description of each parameter follows:
4295%
4296% o image: the image.
4297%
4298% o filename: the persistent pixel cache filename.
4299%
cristyf3a6a9d2010-11-07 21:02:56 +00004300% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004301%
cristy3ed852e2009-09-05 21:47:34 +00004302% o initialize: A value other than zero initializes the persistent pixel
4303% cache.
4304%
4305% o offset: the offset in the persistent cache to store pixels.
4306%
4307% o exception: return any errors or warnings in this structure.
4308%
4309*/
4310MagickExport MagickBooleanType PersistPixelCache(Image *image,
4311 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4312 ExceptionInfo *exception)
4313{
4314 CacheInfo
4315 *cache_info,
4316 *clone_info;
4317
4318 Image
4319 clone_image;
4320
cristy3ed852e2009-09-05 21:47:34 +00004321 MagickBooleanType
4322 status;
4323
cristye076a6e2010-08-15 19:59:43 +00004324 ssize_t
4325 page_size;
4326
cristy3ed852e2009-09-05 21:47:34 +00004327 assert(image != (Image *) NULL);
4328 assert(image->signature == MagickSignature);
4329 if (image->debug != MagickFalse)
4330 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4331 assert(image->cache != (void *) NULL);
4332 assert(filename != (const char *) NULL);
4333 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004334 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004335 cache_info=(CacheInfo *) image->cache;
4336 assert(cache_info->signature == MagickSignature);
4337 if (attach != MagickFalse)
4338 {
4339 /*
cristy01b7eb02009-09-10 23:10:14 +00004340 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004341 */
4342 if (image->debug != MagickFalse)
4343 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004344 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004345 (void) CopyMagickString(cache_info->cache_filename,filename,
4346 MaxTextExtent);
4347 cache_info->type=DiskCache;
4348 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004349 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004350 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004351 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004352 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004353 }
cristy01b7eb02009-09-10 23:10:14 +00004354 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4355 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004356 {
cristyf84a1932010-01-03 18:00:18 +00004357 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004358 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004359 (cache_info->reference_count == 1))
4360 {
4361 int
4362 status;
4363
4364 /*
cristy01b7eb02009-09-10 23:10:14 +00004365 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004366 */
cristy320684d2011-09-23 14:55:47 +00004367 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004368 if (status == 0)
4369 {
4370 (void) CopyMagickString(cache_info->cache_filename,filename,
4371 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004372 *offset+=cache_info->length+page_size-(cache_info->length %
4373 page_size);
cristyf84a1932010-01-03 18:00:18 +00004374 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004375 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004376 if (image->debug != MagickFalse)
4377 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4378 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004379 return(MagickTrue);
4380 }
4381 }
cristyf84a1932010-01-03 18:00:18 +00004382 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004383 }
4384 /*
cristy01b7eb02009-09-10 23:10:14 +00004385 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004386 */
4387 clone_image=(*image);
4388 clone_info=(CacheInfo *) clone_image.cache;
4389 image->cache=ClonePixelCache(cache_info);
4390 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4391 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4392 cache_info->type=DiskCache;
4393 cache_info->offset=(*offset);
4394 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004395 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004396 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004397 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004398 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004399 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4400 return(status);
4401}
4402
4403/*
4404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4405% %
4406% %
4407% %
4408+ Q u e u e A u t h e n t i c N e x u s %
4409% %
4410% %
4411% %
4412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4413%
4414% QueueAuthenticNexus() allocates an region to store image pixels as defined
4415% by the region rectangle and returns a pointer to the region. This region is
4416% subsequently transferred from the pixel cache with
4417% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4418% pixels are transferred, otherwise a NULL is returned.
4419%
4420% The format of the QueueAuthenticNexus() method is:
4421%
cristy4c08aed2011-07-01 19:47:50 +00004422% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004423% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004424% const MagickBooleanType clone,NexusInfo *nexus_info,
4425% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004426%
4427% A description of each parameter follows:
4428%
4429% o image: the image.
4430%
4431% o x,y,columns,rows: These values define the perimeter of a region of
4432% pixels.
4433%
4434% o nexus_info: the cache nexus to set.
4435%
cristy65dbf172011-10-06 17:32:04 +00004436% o clone: clone the pixel cache.
4437%
cristy3ed852e2009-09-05 21:47:34 +00004438% o exception: return any errors or warnings in this structure.
4439%
4440*/
cristya6577ff2011-09-02 19:54:26 +00004441MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004442 const ssize_t y,const size_t columns,const size_t rows,
4443 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004444{
4445 CacheInfo
4446 *cache_info;
4447
4448 MagickOffsetType
4449 offset;
4450
4451 MagickSizeType
4452 number_pixels;
4453
4454 RectangleInfo
4455 region;
4456
4457 /*
4458 Validate pixel cache geometry.
4459 */
cristye7cc7cf2010-09-21 13:26:47 +00004460 assert(image != (const Image *) NULL);
4461 assert(image->signature == MagickSignature);
4462 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004463 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004464 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004465 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004466 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004467 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4468 {
4469 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4470 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004471 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004472 }
cristybb503372010-05-27 20:51:26 +00004473 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4474 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004475 {
4476 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4477 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004478 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004479 }
4480 offset=(MagickOffsetType) y*cache_info->columns+x;
4481 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004482 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004483 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4484 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4485 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004486 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004487 /*
4488 Return pixel cache.
4489 */
4490 region.x=x;
4491 region.y=y;
4492 region.width=columns;
4493 region.height=rows;
4494 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4495}
4496
4497/*
4498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4499% %
4500% %
4501% %
4502+ 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 %
4503% %
4504% %
4505% %
4506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4507%
4508% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4509% defined by the region rectangle and returns a pointer to the region. This
4510% region is subsequently transferred from the pixel cache with
4511% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4512% pixels are transferred, otherwise a NULL is returned.
4513%
4514% The format of the QueueAuthenticPixelsCache() method is:
4515%
cristy4c08aed2011-07-01 19:47:50 +00004516% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004517% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004518% ExceptionInfo *exception)
4519%
4520% A description of each parameter follows:
4521%
4522% o image: the image.
4523%
4524% o x,y,columns,rows: These values define the perimeter of a region of
4525% pixels.
4526%
4527% o exception: return any errors or warnings in this structure.
4528%
4529*/
cristy4c08aed2011-07-01 19:47:50 +00004530static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004531 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004532 ExceptionInfo *exception)
4533{
4534 CacheInfo
4535 *cache_info;
4536
cristy5c9e6f22010-09-17 17:31:01 +00004537 const int
4538 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004539
cristy4c08aed2011-07-01 19:47:50 +00004540 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004541 *q;
cristy4c08aed2011-07-01 19:47:50 +00004542
cristye7cc7cf2010-09-21 13:26:47 +00004543 assert(image != (const Image *) NULL);
4544 assert(image->signature == MagickSignature);
4545 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004546 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004547 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004548 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004549 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4550 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004551 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004552}
4553
4554/*
4555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4556% %
4557% %
4558% %
4559% Q u e u e A u t h e n t i c P i x e l s %
4560% %
4561% %
4562% %
4563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4564%
4565% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004566% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004567% region is returned, otherwise NULL is returned. The returned pointer may
4568% point to a temporary working buffer for the pixels or it may point to the
4569% final location of the pixels in memory.
4570%
4571% Write-only access means that any existing pixel values corresponding to
4572% the region are ignored. This is useful if the initial image is being
4573% created from scratch, or if the existing pixel values are to be
4574% completely replaced without need to refer to their pre-existing values.
4575% The application is free to read and write the pixel buffer returned by
4576% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4577% initialize the pixel array values. Initializing pixel array values is the
4578% application's responsibility.
4579%
4580% Performance is maximized if the selected region is part of one row, or
4581% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004582% pixels in-place (without a copy) if the image is in memory, or in a
4583% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004584% by the user.
4585%
4586% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004587% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4588% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4589% obtain the meta-content (of type void) corresponding to the region.
4590% Once the Quantum (and/or Quantum) array has been updated, the
4591% changes must be saved back to the underlying image using
4592% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004593%
4594% The format of the QueueAuthenticPixels() method is:
4595%
cristy4c08aed2011-07-01 19:47:50 +00004596% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004597% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004598% ExceptionInfo *exception)
4599%
4600% A description of each parameter follows:
4601%
4602% o image: the image.
4603%
4604% o x,y,columns,rows: These values define the perimeter of a region of
4605% pixels.
4606%
4607% o exception: return any errors or warnings in this structure.
4608%
4609*/
cristy4c08aed2011-07-01 19:47:50 +00004610MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004611 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004612 ExceptionInfo *exception)
4613{
4614 CacheInfo
4615 *cache_info;
4616
cristy2036f5c2010-09-19 21:18:17 +00004617 const int
4618 id = GetOpenMPThreadId();
4619
cristy4c08aed2011-07-01 19:47:50 +00004620 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004621 *q;
cristy4c08aed2011-07-01 19:47:50 +00004622
cristy3ed852e2009-09-05 21:47:34 +00004623 assert(image != (Image *) NULL);
4624 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004625 assert(image->cache != (Cache) NULL);
4626 cache_info=(CacheInfo *) image->cache;
4627 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004628 if (cache_info->methods.queue_authentic_pixels_handler !=
4629 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004630 {
cristyacd2ed22011-08-30 01:44:23 +00004631 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004632 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004633 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004634 }
cristy2036f5c2010-09-19 21:18:17 +00004635 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004636 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4637 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004638 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004639}
4640
4641/*
4642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4643% %
4644% %
4645% %
cristy4c08aed2011-07-01 19:47:50 +00004646+ 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 +00004647% %
4648% %
4649% %
4650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4651%
cristy4c08aed2011-07-01 19:47:50 +00004652% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004653% the pixel cache.
4654%
cristy4c08aed2011-07-01 19:47:50 +00004655% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004656%
cristy4c08aed2011-07-01 19:47:50 +00004657% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004658% NexusInfo *nexus_info,ExceptionInfo *exception)
4659%
4660% A description of each parameter follows:
4661%
4662% o cache_info: the pixel cache.
4663%
cristy4c08aed2011-07-01 19:47:50 +00004664% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004665%
4666% o exception: return any errors or warnings in this structure.
4667%
4668*/
cristy4c08aed2011-07-01 19:47:50 +00004669static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004670 NexusInfo *nexus_info,ExceptionInfo *exception)
4671{
4672 MagickOffsetType
4673 count,
4674 offset;
4675
4676 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004677 extent,
4678 length;
cristy3ed852e2009-09-05 21:47:34 +00004679
cristybb503372010-05-27 20:51:26 +00004680 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004681 y;
4682
cristy4c08aed2011-07-01 19:47:50 +00004683 register unsigned char
4684 *restrict q;
4685
cristybb503372010-05-27 20:51:26 +00004686 size_t
cristy3ed852e2009-09-05 21:47:34 +00004687 rows;
4688
cristy4c08aed2011-07-01 19:47:50 +00004689 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004690 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004691 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004692 return(MagickTrue);
4693 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4694 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004695 length=(MagickSizeType) nexus_info->region.width*
4696 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004697 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004698 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004699 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004700 switch (cache_info->type)
4701 {
4702 case MemoryCache:
4703 case MapCache:
4704 {
cristy4c08aed2011-07-01 19:47:50 +00004705 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004706 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004707
4708 /*
cristy4c08aed2011-07-01 19:47:50 +00004709 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004710 */
cristydd341db2010-03-04 19:06:38 +00004711 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004712 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004713 {
cristy48078b12010-09-23 17:11:01 +00004714 length=extent;
cristydd341db2010-03-04 19:06:38 +00004715 rows=1UL;
4716 }
cristy4c08aed2011-07-01 19:47:50 +00004717 p=(unsigned char *) cache_info->metacontent+offset*
4718 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004719 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004720 {
cristy8f036fe2010-09-18 02:02:00 +00004721 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004722 p+=cache_info->metacontent_extent*cache_info->columns;
4723 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004724 }
4725 break;
4726 }
4727 case DiskCache:
4728 {
4729 /*
cristy4c08aed2011-07-01 19:47:50 +00004730 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004731 */
4732 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4733 {
4734 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4735 cache_info->cache_filename);
4736 return(MagickFalse);
4737 }
cristydd341db2010-03-04 19:06:38 +00004738 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004739 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004740 {
cristy48078b12010-09-23 17:11:01 +00004741 length=extent;
cristydd341db2010-03-04 19:06:38 +00004742 rows=1UL;
4743 }
cristy48078b12010-09-23 17:11:01 +00004744 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004745 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004746 {
cristy48078b12010-09-23 17:11:01 +00004747 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004748 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004749 cache_info->metacontent_extent,length,(unsigned char *) q);
4750 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004751 break;
4752 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004753 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004754 }
cristybb503372010-05-27 20:51:26 +00004755 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004756 {
4757 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4758 cache_info->cache_filename);
4759 return(MagickFalse);
4760 }
4761 break;
4762 }
4763 default:
4764 break;
4765 }
4766 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004767 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004768 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004769 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004770 nexus_info->region.width,(double) nexus_info->region.height,(double)
4771 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004772 return(MagickTrue);
4773}
4774
4775/*
4776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4777% %
4778% %
4779% %
4780+ R e a d P i x e l C a c h e P i x e l s %
4781% %
4782% %
4783% %
4784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4785%
4786% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4787% cache.
4788%
4789% The format of the ReadPixelCachePixels() method is:
4790%
4791% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4792% NexusInfo *nexus_info,ExceptionInfo *exception)
4793%
4794% A description of each parameter follows:
4795%
4796% o cache_info: the pixel cache.
4797%
4798% o nexus_info: the cache nexus to read the pixels.
4799%
4800% o exception: return any errors or warnings in this structure.
4801%
4802*/
4803static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4804 NexusInfo *nexus_info,ExceptionInfo *exception)
4805{
4806 MagickOffsetType
4807 count,
4808 offset;
4809
4810 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004811 extent,
4812 length;
cristy3ed852e2009-09-05 21:47:34 +00004813
cristy4c08aed2011-07-01 19:47:50 +00004814 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004815 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004816
cristye076a6e2010-08-15 19:59:43 +00004817 register ssize_t
4818 y;
4819
cristybb503372010-05-27 20:51:26 +00004820 size_t
cristy3ed852e2009-09-05 21:47:34 +00004821 rows;
4822
cristy4c08aed2011-07-01 19:47:50 +00004823 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004824 return(MagickTrue);
4825 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4826 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004827 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004828 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004829 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004830 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004831 q=nexus_info->pixels;
4832 switch (cache_info->type)
4833 {
4834 case MemoryCache:
4835 case MapCache:
4836 {
cristy4c08aed2011-07-01 19:47:50 +00004837 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004838 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004839
4840 /*
4841 Read pixels from memory.
4842 */
cristydd341db2010-03-04 19:06:38 +00004843 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004844 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004845 {
cristy48078b12010-09-23 17:11:01 +00004846 length=extent;
cristydd341db2010-03-04 19:06:38 +00004847 rows=1UL;
4848 }
cristyed231572011-07-14 02:18:59 +00004849 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004850 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004851 {
cristy8f036fe2010-09-18 02:02:00 +00004852 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004853 p+=cache_info->number_channels*cache_info->columns;
4854 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004855 }
4856 break;
4857 }
4858 case DiskCache:
4859 {
4860 /*
4861 Read pixels from disk.
4862 */
4863 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4864 {
4865 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4866 cache_info->cache_filename);
4867 return(MagickFalse);
4868 }
cristydd341db2010-03-04 19:06:38 +00004869 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004870 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004871 {
cristy48078b12010-09-23 17:11:01 +00004872 length=extent;
cristydd341db2010-03-04 19:06:38 +00004873 rows=1UL;
4874 }
cristybb503372010-05-27 20:51:26 +00004875 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004876 {
4877 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004878 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004879 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004880 break;
4881 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004882 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004883 }
cristybb503372010-05-27 20:51:26 +00004884 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004885 {
4886 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4887 cache_info->cache_filename);
4888 return(MagickFalse);
4889 }
4890 break;
4891 }
4892 default:
4893 break;
4894 }
4895 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004896 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004897 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004898 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004899 nexus_info->region.width,(double) nexus_info->region.height,(double)
4900 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004901 return(MagickTrue);
4902}
4903
4904/*
4905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4906% %
4907% %
4908% %
4909+ R e f e r e n c e P i x e l C a c h e %
4910% %
4911% %
4912% %
4913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4914%
4915% ReferencePixelCache() increments the reference count associated with the
4916% pixel cache returning a pointer to the cache.
4917%
4918% The format of the ReferencePixelCache method is:
4919%
4920% Cache ReferencePixelCache(Cache cache_info)
4921%
4922% A description of each parameter follows:
4923%
4924% o cache_info: the pixel cache.
4925%
4926*/
cristya6577ff2011-09-02 19:54:26 +00004927MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004928{
4929 CacheInfo
4930 *cache_info;
4931
4932 assert(cache != (Cache *) NULL);
4933 cache_info=(CacheInfo *) cache;
4934 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004935 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004936 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004937 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004938 return(cache_info);
4939}
4940
4941/*
4942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4943% %
4944% %
4945% %
4946+ S e t P i x e l C a c h e M e t h o d s %
4947% %
4948% %
4949% %
4950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4951%
4952% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4953%
4954% The format of the SetPixelCacheMethods() method is:
4955%
4956% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4957%
4958% A description of each parameter follows:
4959%
4960% o cache: the pixel cache.
4961%
4962% o cache_methods: Specifies a pointer to a CacheMethods structure.
4963%
4964*/
cristya6577ff2011-09-02 19:54:26 +00004965MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004966{
4967 CacheInfo
4968 *cache_info;
4969
4970 GetOneAuthenticPixelFromHandler
4971 get_one_authentic_pixel_from_handler;
4972
4973 GetOneVirtualPixelFromHandler
4974 get_one_virtual_pixel_from_handler;
4975
4976 /*
4977 Set cache pixel methods.
4978 */
4979 assert(cache != (Cache) NULL);
4980 assert(cache_methods != (CacheMethods *) NULL);
4981 cache_info=(CacheInfo *) cache;
4982 assert(cache_info->signature == MagickSignature);
4983 if (cache_info->debug != MagickFalse)
4984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4985 cache_info->filename);
4986 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4987 cache_info->methods.get_virtual_pixel_handler=
4988 cache_methods->get_virtual_pixel_handler;
4989 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4990 cache_info->methods.destroy_pixel_handler=
4991 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004992 if (cache_methods->get_virtual_metacontent_from_handler !=
4993 (GetVirtualMetacontentFromHandler) NULL)
4994 cache_info->methods.get_virtual_metacontent_from_handler=
4995 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004996 if (cache_methods->get_authentic_pixels_handler !=
4997 (GetAuthenticPixelsHandler) NULL)
4998 cache_info->methods.get_authentic_pixels_handler=
4999 cache_methods->get_authentic_pixels_handler;
5000 if (cache_methods->queue_authentic_pixels_handler !=
5001 (QueueAuthenticPixelsHandler) NULL)
5002 cache_info->methods.queue_authentic_pixels_handler=
5003 cache_methods->queue_authentic_pixels_handler;
5004 if (cache_methods->sync_authentic_pixels_handler !=
5005 (SyncAuthenticPixelsHandler) NULL)
5006 cache_info->methods.sync_authentic_pixels_handler=
5007 cache_methods->sync_authentic_pixels_handler;
5008 if (cache_methods->get_authentic_pixels_from_handler !=
5009 (GetAuthenticPixelsFromHandler) NULL)
5010 cache_info->methods.get_authentic_pixels_from_handler=
5011 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00005012 if (cache_methods->get_authentic_metacontent_from_handler !=
5013 (GetAuthenticMetacontentFromHandler) NULL)
5014 cache_info->methods.get_authentic_metacontent_from_handler=
5015 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00005016 get_one_virtual_pixel_from_handler=
5017 cache_info->methods.get_one_virtual_pixel_from_handler;
5018 if (get_one_virtual_pixel_from_handler !=
5019 (GetOneVirtualPixelFromHandler) NULL)
5020 cache_info->methods.get_one_virtual_pixel_from_handler=
5021 cache_methods->get_one_virtual_pixel_from_handler;
5022 get_one_authentic_pixel_from_handler=
5023 cache_methods->get_one_authentic_pixel_from_handler;
5024 if (get_one_authentic_pixel_from_handler !=
5025 (GetOneAuthenticPixelFromHandler) NULL)
5026 cache_info->methods.get_one_authentic_pixel_from_handler=
5027 cache_methods->get_one_authentic_pixel_from_handler;
5028}
5029
5030/*
5031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5032% %
5033% %
5034% %
5035+ S e t P i x e l C a c h e N e x u s P i x e l s %
5036% %
5037% %
5038% %
5039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5040%
5041% SetPixelCacheNexusPixels() defines the region of the cache for the
5042% specified cache nexus.
5043%
5044% The format of the SetPixelCacheNexusPixels() method is:
5045%
cristy4c08aed2011-07-01 19:47:50 +00005046% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005047% const RectangleInfo *region,NexusInfo *nexus_info,
5048% ExceptionInfo *exception)
5049%
5050% A description of each parameter follows:
5051%
5052% o image: the image.
5053%
5054% o region: A pointer to the RectangleInfo structure that defines the
5055% region of this particular cache nexus.
5056%
5057% o nexus_info: the cache nexus to set.
5058%
5059% o exception: return any errors or warnings in this structure.
5060%
5061*/
cristyabd6e372010-09-15 19:11:26 +00005062
5063static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5064 NexusInfo *nexus_info,ExceptionInfo *exception)
5065{
5066 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5067 return(MagickFalse);
5068 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005069 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005070 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005071 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005072 {
5073 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005074 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005075 nexus_info->length);
5076 }
cristy4c08aed2011-07-01 19:47:50 +00005077 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005078 {
5079 (void) ThrowMagickException(exception,GetMagickModule(),
5080 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5081 cache_info->filename);
5082 return(MagickFalse);
5083 }
5084 return(MagickTrue);
5085}
5086
cristy4c08aed2011-07-01 19:47:50 +00005087static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005088 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5089{
5090 CacheInfo
5091 *cache_info;
5092
5093 MagickBooleanType
5094 status;
5095
cristy3ed852e2009-09-05 21:47:34 +00005096 MagickSizeType
5097 length,
5098 number_pixels;
5099
cristy3ed852e2009-09-05 21:47:34 +00005100 cache_info=(CacheInfo *) image->cache;
5101 assert(cache_info->signature == MagickSignature);
5102 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005103 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005104 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005105 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5106 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005107 {
cristybb503372010-05-27 20:51:26 +00005108 ssize_t
cristybad067a2010-02-15 17:20:55 +00005109 x,
5110 y;
cristy3ed852e2009-09-05 21:47:34 +00005111
cristyeaedf062010-05-29 22:36:02 +00005112 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5113 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005114 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5115 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005116 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005117 ((nexus_info->region.width == cache_info->columns) ||
5118 ((nexus_info->region.width % cache_info->columns) == 0)))))
5119 {
5120 MagickOffsetType
5121 offset;
5122
5123 /*
5124 Pixels are accessed directly from memory.
5125 */
5126 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5127 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005128 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005129 offset;
5130 nexus_info->metacontent=(void *) NULL;
5131 if (cache_info->metacontent_extent != 0)
5132 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5133 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005134 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005135 }
5136 }
5137 /*
5138 Pixels are stored in a cache region until they are synced to the cache.
5139 */
5140 number_pixels=(MagickSizeType) nexus_info->region.width*
5141 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005142 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005143 if (cache_info->metacontent_extent != 0)
5144 length+=number_pixels*cache_info->metacontent_extent;
5145 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005146 {
5147 nexus_info->length=length;
5148 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5149 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005150 {
5151 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005152 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005153 }
cristy3ed852e2009-09-05 21:47:34 +00005154 }
5155 else
5156 if (nexus_info->length != length)
5157 {
5158 RelinquishCacheNexusPixels(nexus_info);
5159 nexus_info->length=length;
5160 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5161 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005162 {
5163 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005164 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005165 }
cristy3ed852e2009-09-05 21:47:34 +00005166 }
5167 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005168 nexus_info->metacontent=(void *) NULL;
5169 if (cache_info->metacontent_extent != 0)
5170 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005171 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005172 return(nexus_info->pixels);
5173}
5174
5175/*
5176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5177% %
5178% %
5179% %
5180% 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 %
5181% %
5182% %
5183% %
5184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5185%
5186% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5187% pixel cache and returns the previous setting. A virtual pixel is any pixel
5188% access that is outside the boundaries of the image cache.
5189%
5190% The format of the SetPixelCacheVirtualMethod() method is:
5191%
5192% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5193% const VirtualPixelMethod virtual_pixel_method)
5194%
5195% A description of each parameter follows:
5196%
5197% o image: the image.
5198%
5199% o virtual_pixel_method: choose the type of virtual pixel.
5200%
5201*/
cristyd1dd6e42011-09-04 01:46:08 +00005202MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005203 const VirtualPixelMethod virtual_pixel_method)
5204{
5205 CacheInfo
5206 *cache_info;
5207
5208 VirtualPixelMethod
5209 method;
5210
5211 assert(image != (Image *) NULL);
5212 assert(image->signature == MagickSignature);
5213 if (image->debug != MagickFalse)
5214 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5215 assert(image->cache != (Cache) NULL);
5216 cache_info=(CacheInfo *) image->cache;
5217 assert(cache_info->signature == MagickSignature);
5218 method=cache_info->virtual_pixel_method;
5219 cache_info->virtual_pixel_method=virtual_pixel_method;
5220 return(method);
5221}
5222
5223/*
5224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5225% %
5226% %
5227% %
5228+ 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 %
5229% %
5230% %
5231% %
5232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5233%
5234% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5235% in-memory or disk cache. The method returns MagickTrue if the pixel region
5236% is synced, otherwise MagickFalse.
5237%
5238% The format of the SyncAuthenticPixelCacheNexus() method is:
5239%
5240% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5241% NexusInfo *nexus_info,ExceptionInfo *exception)
5242%
5243% A description of each parameter follows:
5244%
5245% o image: the image.
5246%
5247% o nexus_info: the cache nexus to sync.
5248%
5249% o exception: return any errors or warnings in this structure.
5250%
5251*/
cristya6577ff2011-09-02 19:54:26 +00005252MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005253 NexusInfo *nexus_info,ExceptionInfo *exception)
5254{
5255 CacheInfo
5256 *cache_info;
5257
5258 MagickBooleanType
5259 status;
5260
5261 /*
5262 Transfer pixels to the cache.
5263 */
5264 assert(image != (Image *) NULL);
5265 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005266 if (image->cache == (Cache) NULL)
5267 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5268 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005269 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005270 if (cache_info->type == UndefinedCache)
5271 return(MagickFalse);
5272 if ((image->clip_mask != (Image *) NULL) &&
5273 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5274 return(MagickFalse);
5275 if ((image->mask != (Image *) NULL) &&
5276 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5277 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005278 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005279 return(MagickTrue);
5280 assert(cache_info->signature == MagickSignature);
5281 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005282 if ((cache_info->metacontent_extent != 0) &&
5283 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005284 return(MagickFalse);
5285 return(status);
5286}
5287
5288/*
5289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5290% %
5291% %
5292% %
5293+ S y n c A u t h e n t i c P i x e l C a c h e %
5294% %
5295% %
5296% %
5297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5298%
5299% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5300% or disk cache. The method returns MagickTrue if the pixel region is synced,
5301% otherwise MagickFalse.
5302%
5303% The format of the SyncAuthenticPixelsCache() method is:
5304%
5305% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5306% ExceptionInfo *exception)
5307%
5308% A description of each parameter follows:
5309%
5310% o image: the image.
5311%
5312% o exception: return any errors or warnings in this structure.
5313%
5314*/
5315static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5316 ExceptionInfo *exception)
5317{
5318 CacheInfo
5319 *cache_info;
5320
cristy5c9e6f22010-09-17 17:31:01 +00005321 const int
5322 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005323
cristy4c08aed2011-07-01 19:47:50 +00005324 MagickBooleanType
5325 status;
5326
cristye7cc7cf2010-09-21 13:26:47 +00005327 assert(image != (Image *) NULL);
5328 assert(image->signature == MagickSignature);
5329 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005330 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005331 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005332 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005333 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5334 exception);
5335 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005336}
5337
5338/*
5339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5340% %
5341% %
5342% %
5343% S y n c A u t h e n t i c P i x e l s %
5344% %
5345% %
5346% %
5347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5348%
5349% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5350% The method returns MagickTrue if the pixel region is flushed, otherwise
5351% MagickFalse.
5352%
5353% The format of the SyncAuthenticPixels() method is:
5354%
5355% MagickBooleanType SyncAuthenticPixels(Image *image,
5356% ExceptionInfo *exception)
5357%
5358% A description of each parameter follows:
5359%
5360% o image: the image.
5361%
5362% o exception: return any errors or warnings in this structure.
5363%
5364*/
5365MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5366 ExceptionInfo *exception)
5367{
5368 CacheInfo
5369 *cache_info;
5370
cristy2036f5c2010-09-19 21:18:17 +00005371 const int
5372 id = GetOpenMPThreadId();
5373
cristy4c08aed2011-07-01 19:47:50 +00005374 MagickBooleanType
5375 status;
5376
cristy3ed852e2009-09-05 21:47:34 +00005377 assert(image != (Image *) NULL);
5378 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005379 assert(image->cache != (Cache) NULL);
5380 cache_info=(CacheInfo *) image->cache;
5381 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005382 if (cache_info->methods.sync_authentic_pixels_handler !=
5383 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005384 {
5385 status=cache_info->methods.sync_authentic_pixels_handler(image,
5386 exception);
5387 return(status);
5388 }
cristy2036f5c2010-09-19 21:18:17 +00005389 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005390 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5391 exception);
5392 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005393}
5394
5395/*
5396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5397% %
5398% %
5399% %
cristyd1dd6e42011-09-04 01:46:08 +00005400+ 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 +00005401% %
5402% %
5403% %
5404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5405%
5406% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5407% The method returns MagickTrue if the pixel region is flushed, otherwise
5408% MagickFalse.
5409%
5410% The format of the SyncImagePixelCache() method is:
5411%
5412% MagickBooleanType SyncImagePixelCache(Image *image,
5413% ExceptionInfo *exception)
5414%
5415% A description of each parameter follows:
5416%
5417% o image: the image.
5418%
5419% o exception: return any errors or warnings in this structure.
5420%
5421*/
cristyd1dd6e42011-09-04 01:46:08 +00005422MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005423 ExceptionInfo *exception)
5424{
5425 CacheInfo
5426 *cache_info;
5427
5428 assert(image != (Image *) NULL);
5429 assert(exception != (ExceptionInfo *) NULL);
5430 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5431 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5432}
5433
5434/*
5435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5436% %
5437% %
5438% %
cristy4c08aed2011-07-01 19:47:50 +00005439+ 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 +00005440% %
5441% %
5442% %
5443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5444%
cristy4c08aed2011-07-01 19:47:50 +00005445% WritePixelCacheMetacontent() writes the meta-content to the specified region
5446% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005447%
cristy4c08aed2011-07-01 19:47:50 +00005448% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005449%
cristy4c08aed2011-07-01 19:47:50 +00005450% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005451% NexusInfo *nexus_info,ExceptionInfo *exception)
5452%
5453% A description of each parameter follows:
5454%
5455% o cache_info: the pixel cache.
5456%
cristy4c08aed2011-07-01 19:47:50 +00005457% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005458%
5459% o exception: return any errors or warnings in this structure.
5460%
5461*/
cristy4c08aed2011-07-01 19:47:50 +00005462static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005463 NexusInfo *nexus_info,ExceptionInfo *exception)
5464{
5465 MagickOffsetType
5466 count,
5467 offset;
5468
5469 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005470 extent,
5471 length;
cristy3ed852e2009-09-05 21:47:34 +00005472
cristy4c08aed2011-07-01 19:47:50 +00005473 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005474 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005475
cristybb503372010-05-27 20:51:26 +00005476 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005477 y;
5478
cristybb503372010-05-27 20:51:26 +00005479 size_t
cristy3ed852e2009-09-05 21:47:34 +00005480 rows;
5481
cristy4c08aed2011-07-01 19:47:50 +00005482 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005483 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005484 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005485 return(MagickTrue);
5486 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5487 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005488 length=(MagickSizeType) nexus_info->region.width*
5489 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005490 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005491 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005492 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005493 switch (cache_info->type)
5494 {
5495 case MemoryCache:
5496 case MapCache:
5497 {
cristy4c08aed2011-07-01 19:47:50 +00005498 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005499 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005500
5501 /*
cristy4c08aed2011-07-01 19:47:50 +00005502 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005503 */
cristydd341db2010-03-04 19:06:38 +00005504 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005505 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005506 {
cristy48078b12010-09-23 17:11:01 +00005507 length=extent;
cristydd341db2010-03-04 19:06:38 +00005508 rows=1UL;
5509 }
cristy4c08aed2011-07-01 19:47:50 +00005510 q=(unsigned char *) cache_info->metacontent+offset*
5511 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005512 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005513 {
cristy8f036fe2010-09-18 02:02:00 +00005514 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005515 p+=nexus_info->region.width*cache_info->metacontent_extent;
5516 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005517 }
5518 break;
5519 }
5520 case DiskCache:
5521 {
5522 /*
cristy4c08aed2011-07-01 19:47:50 +00005523 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005524 */
5525 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5526 {
5527 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5528 cache_info->cache_filename);
5529 return(MagickFalse);
5530 }
cristydd341db2010-03-04 19:06:38 +00005531 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005532 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005533 {
cristy48078b12010-09-23 17:11:01 +00005534 length=extent;
cristydd341db2010-03-04 19:06:38 +00005535 rows=1UL;
5536 }
cristy48078b12010-09-23 17:11:01 +00005537 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005538 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005539 {
cristy48078b12010-09-23 17:11:01 +00005540 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005541 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005542 cache_info->metacontent_extent,length,(const unsigned char *) p);
5543 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005544 break;
cristy4c08aed2011-07-01 19:47:50 +00005545 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005546 offset+=cache_info->columns;
5547 }
cristybb503372010-05-27 20:51:26 +00005548 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005549 {
5550 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5551 cache_info->cache_filename);
5552 return(MagickFalse);
5553 }
5554 break;
5555 }
5556 default:
5557 break;
5558 }
5559 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005560 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005561 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005562 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005563 nexus_info->region.width,(double) nexus_info->region.height,(double)
5564 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005565 return(MagickTrue);
5566}
5567
5568/*
5569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5570% %
5571% %
5572% %
5573+ W r i t e C a c h e P i x e l s %
5574% %
5575% %
5576% %
5577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5578%
5579% WritePixelCachePixels() writes image pixels to the specified region of the
5580% pixel cache.
5581%
5582% The format of the WritePixelCachePixels() method is:
5583%
5584% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5585% NexusInfo *nexus_info,ExceptionInfo *exception)
5586%
5587% A description of each parameter follows:
5588%
5589% o cache_info: the pixel cache.
5590%
5591% o nexus_info: the cache nexus to write the pixels.
5592%
5593% o exception: return any errors or warnings in this structure.
5594%
5595*/
5596static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5597 NexusInfo *nexus_info,ExceptionInfo *exception)
5598{
5599 MagickOffsetType
5600 count,
5601 offset;
5602
5603 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005604 extent,
5605 length;
cristy3ed852e2009-09-05 21:47:34 +00005606
cristy4c08aed2011-07-01 19:47:50 +00005607 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005608 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005609
cristybb503372010-05-27 20:51:26 +00005610 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005611 y;
5612
cristybb503372010-05-27 20:51:26 +00005613 size_t
cristy3ed852e2009-09-05 21:47:34 +00005614 rows;
5615
cristy4c08aed2011-07-01 19:47:50 +00005616 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005617 return(MagickTrue);
5618 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5619 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005620 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005621 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005622 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005623 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005624 p=nexus_info->pixels;
5625 switch (cache_info->type)
5626 {
5627 case MemoryCache:
5628 case MapCache:
5629 {
cristy4c08aed2011-07-01 19:47:50 +00005630 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005631 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005632
5633 /*
5634 Write pixels to memory.
5635 */
cristydd341db2010-03-04 19:06:38 +00005636 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005637 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005638 {
cristy48078b12010-09-23 17:11:01 +00005639 length=extent;
cristydd341db2010-03-04 19:06:38 +00005640 rows=1UL;
5641 }
cristyed231572011-07-14 02:18:59 +00005642 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005643 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005644 {
cristy8f036fe2010-09-18 02:02:00 +00005645 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005646 p+=nexus_info->region.width*cache_info->number_channels;
5647 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005648 }
5649 break;
5650 }
5651 case DiskCache:
5652 {
5653 /*
5654 Write pixels to disk.
5655 */
5656 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5657 {
5658 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5659 cache_info->cache_filename);
5660 return(MagickFalse);
5661 }
cristydd341db2010-03-04 19:06:38 +00005662 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005663 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005664 {
cristy48078b12010-09-23 17:11:01 +00005665 length=extent;
cristydd341db2010-03-04 19:06:38 +00005666 rows=1UL;
5667 }
cristybb503372010-05-27 20:51:26 +00005668 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005669 {
5670 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005671 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005672 p);
5673 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005674 break;
cristyed231572011-07-14 02:18:59 +00005675 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005676 offset+=cache_info->columns;
5677 }
cristybb503372010-05-27 20:51:26 +00005678 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005679 {
5680 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5681 cache_info->cache_filename);
5682 return(MagickFalse);
5683 }
5684 break;
5685 }
5686 default:
5687 break;
5688 }
5689 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005690 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005691 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005692 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005693 nexus_info->region.width,(double) nexus_info->region.height,(double)
5694 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005695 return(MagickTrue);
5696}