blob: 660b71e69cada8a0f14c4555fa0f5b82d76d195d [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
cristye2a912b2011-12-05 20:02:07 +00002159 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002160 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
cristye2a912b2011-12-05 20:02:07 +00002234 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002235 pixel[channel]=q[i];
2236 }
cristy3ed852e2009-09-05 21:47:34 +00002237 return(MagickTrue);
2238}
2239
2240/*
2241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242% %
2243% %
2244% %
cristy3ed852e2009-09-05 21:47:34 +00002245% G e t O n e V i r t u a l P i x e l %
2246% %
2247% %
2248% %
2249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250%
2251% GetOneVirtualPixel() returns a single virtual pixel at the specified
2252% (x,y) location. The image background color is returned if an error occurs.
2253% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2254%
2255% The format of the GetOneVirtualPixel() method is:
2256%
cristybb503372010-05-27 20:51:26 +00002257% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002258% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002259%
2260% A description of each parameter follows:
2261%
2262% o image: the image.
2263%
2264% o x,y: These values define the location of the pixel to return.
2265%
2266% o pixel: return a pixel at the specified (x,y) location.
2267%
2268% o exception: return any errors or warnings in this structure.
2269%
2270*/
2271MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002272 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002273{
cristy3ed852e2009-09-05 21:47:34 +00002274 CacheInfo
2275 *cache_info;
2276
cristy0158a4b2010-09-20 13:59:45 +00002277 const int
2278 id = GetOpenMPThreadId();
2279
cristy4c08aed2011-07-01 19:47:50 +00002280 const Quantum
2281 *p;
cristy2036f5c2010-09-19 21:18:17 +00002282
cristy2ed42f62011-10-02 19:49:57 +00002283 register ssize_t
2284 i;
2285
cristy3ed852e2009-09-05 21:47:34 +00002286 assert(image != (const Image *) NULL);
2287 assert(image->signature == MagickSignature);
2288 assert(image->cache != (Cache) NULL);
2289 cache_info=(CacheInfo *) image->cache;
2290 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002291 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002292 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2293 (GetOneVirtualPixelFromHandler) NULL)
2294 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2295 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002296 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002297 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002298 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002299 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002300 {
2301 pixel[RedPixelChannel]=image->background_color.red;
2302 pixel[GreenPixelChannel]=image->background_color.green;
2303 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002304 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002305 pixel[AlphaPixelChannel]=image->background_color.alpha;
2306 return(MagickFalse);
2307 }
2308 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2309 {
2310 PixelChannel
2311 channel;
2312
cristye2a912b2011-12-05 20:02:07 +00002313 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002314 pixel[channel]=p[i];
2315 }
cristy2036f5c2010-09-19 21:18:17 +00002316 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002317}
2318
2319/*
2320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321% %
2322% %
2323% %
2324+ 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 %
2325% %
2326% %
2327% %
2328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2329%
2330% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2331% specified (x,y) location. The image background color is returned if an
2332% error occurs.
2333%
2334% The format of the GetOneVirtualPixelFromCache() method is:
2335%
2336% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002337% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002338% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002339%
2340% A description of each parameter follows:
2341%
2342% o image: the image.
2343%
2344% o virtual_pixel_method: the virtual pixel method.
2345%
2346% o x,y: These values define the location of the pixel to return.
2347%
2348% o pixel: return a pixel at the specified (x,y) location.
2349%
2350% o exception: return any errors or warnings in this structure.
2351%
2352*/
2353static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002354 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002355 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002356{
cristy0158a4b2010-09-20 13:59:45 +00002357 CacheInfo
2358 *cache_info;
2359
2360 const int
2361 id = GetOpenMPThreadId();
2362
cristy4c08aed2011-07-01 19:47:50 +00002363 const Quantum
2364 *p;
cristy3ed852e2009-09-05 21:47:34 +00002365
cristy2ed42f62011-10-02 19:49:57 +00002366 register ssize_t
2367 i;
2368
cristye7cc7cf2010-09-21 13:26:47 +00002369 assert(image != (const Image *) NULL);
2370 assert(image->signature == MagickSignature);
2371 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002372 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002373 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002374 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002375 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002376 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002377 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002378 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002379 {
2380 pixel[RedPixelChannel]=image->background_color.red;
2381 pixel[GreenPixelChannel]=image->background_color.green;
2382 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002383 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002384 pixel[AlphaPixelChannel]=image->background_color.alpha;
2385 return(MagickFalse);
2386 }
2387 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2388 {
2389 PixelChannel
2390 channel;
2391
cristye2a912b2011-12-05 20:02:07 +00002392 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002393 pixel[channel]=p[i];
2394 }
cristy3ed852e2009-09-05 21:47:34 +00002395 return(MagickTrue);
2396}
2397
2398/*
2399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2400% %
2401% %
2402% %
cristy3aa93752011-12-18 15:54:24 +00002403% G e t O n e V i r t u a l P i x e l I n f o %
2404% %
2405% %
2406% %
2407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2408%
2409% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2410% location. The image background color is returned if an error occurs. If
2411% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2412%
2413% The format of the GetOneVirtualPixelInfo() method is:
2414%
2415% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2416% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2417% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2418%
2419% A description of each parameter follows:
2420%
2421% o image: the image.
2422%
2423% o virtual_pixel_method: the virtual pixel method.
2424%
2425% o x,y: these values define the location of the pixel to return.
2426%
2427% o pixel: return a pixel at the specified (x,y) location.
2428%
2429% o exception: return any errors or warnings in this structure.
2430%
2431*/
2432MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2433 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2434 PixelInfo *pixel,ExceptionInfo *exception)
2435{
2436 CacheInfo
2437 *cache_info;
2438
2439 const int
2440 id = GetOpenMPThreadId();
2441
2442 register const Quantum
2443 *p;
2444
2445 assert(image != (const Image *) NULL);
2446 assert(image->signature == MagickSignature);
2447 assert(image->cache != (Cache) NULL);
2448 cache_info=(CacheInfo *) image->cache;
2449 assert(cache_info->signature == MagickSignature);
2450 assert(id < (int) cache_info->number_threads);
2451 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2452 cache_info->nexus_info[id],exception);
2453 GetPixelInfo(image,pixel);
2454 if (p == (const Quantum *) NULL)
2455 return(MagickFalse);
2456 GetPixelInfoPixel(image,p,pixel);
2457 return(MagickTrue);
2458}
2459
2460/*
2461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462% %
2463% %
2464% %
cristy3ed852e2009-09-05 21:47:34 +00002465+ G e t P i x e l C a c h e C o l o r s p a c e %
2466% %
2467% %
2468% %
2469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470%
2471% GetPixelCacheColorspace() returns the class type of the pixel cache.
2472%
2473% The format of the GetPixelCacheColorspace() method is:
2474%
2475% Colorspace GetPixelCacheColorspace(Cache cache)
2476%
2477% A description of each parameter follows:
2478%
2479% o cache: the pixel cache.
2480%
2481*/
cristya6577ff2011-09-02 19:54:26 +00002482MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002483{
2484 CacheInfo
2485 *cache_info;
2486
2487 assert(cache != (Cache) NULL);
2488 cache_info=(CacheInfo *) cache;
2489 assert(cache_info->signature == MagickSignature);
2490 if (cache_info->debug != MagickFalse)
2491 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2492 cache_info->filename);
2493 return(cache_info->colorspace);
2494}
2495
2496/*
2497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2498% %
2499% %
2500% %
2501+ G e t P i x e l C a c h e M e t h o d s %
2502% %
2503% %
2504% %
2505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2506%
2507% GetPixelCacheMethods() initializes the CacheMethods structure.
2508%
2509% The format of the GetPixelCacheMethods() method is:
2510%
2511% void GetPixelCacheMethods(CacheMethods *cache_methods)
2512%
2513% A description of each parameter follows:
2514%
2515% o cache_methods: Specifies a pointer to a CacheMethods structure.
2516%
2517*/
cristya6577ff2011-09-02 19:54:26 +00002518MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002519{
2520 assert(cache_methods != (CacheMethods *) NULL);
2521 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2522 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2523 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002524 cache_methods->get_virtual_metacontent_from_handler=
2525 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002526 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2527 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002528 cache_methods->get_authentic_metacontent_from_handler=
2529 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002530 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2531 cache_methods->get_one_authentic_pixel_from_handler=
2532 GetOneAuthenticPixelFromCache;
2533 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2534 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2535 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2536}
2537
2538/*
2539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2540% %
2541% %
2542% %
2543+ G e t P i x e l C a c h e N e x u s E x t e n t %
2544% %
2545% %
2546% %
2547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548%
cristy4c08aed2011-07-01 19:47:50 +00002549% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2550% corresponding with the last call to SetPixelCacheNexusPixels() or
2551% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002552%
2553% The format of the GetPixelCacheNexusExtent() method is:
2554%
2555% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2556% NexusInfo *nexus_info)
2557%
2558% A description of each parameter follows:
2559%
2560% o nexus_info: the nexus info.
2561%
2562*/
cristya6577ff2011-09-02 19:54:26 +00002563MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002564 NexusInfo *nexus_info)
2565{
2566 CacheInfo
2567 *cache_info;
2568
2569 MagickSizeType
2570 extent;
2571
cristy9f027d12011-09-21 01:17:17 +00002572 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002573 cache_info=(CacheInfo *) cache;
2574 assert(cache_info->signature == MagickSignature);
2575 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2576 if (extent == 0)
2577 return((MagickSizeType) cache_info->columns*cache_info->rows);
2578 return(extent);
2579}
2580
2581/*
2582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583% %
2584% %
2585% %
cristy4c08aed2011-07-01 19:47:50 +00002586+ 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 +00002587% %
2588% %
2589% %
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591%
cristy4c08aed2011-07-01 19:47:50 +00002592% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2593% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002594%
cristy4c08aed2011-07-01 19:47:50 +00002595% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002596%
cristy4c08aed2011-07-01 19:47:50 +00002597% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002598% NexusInfo *nexus_info)
2599%
2600% A description of each parameter follows:
2601%
2602% o cache: the pixel cache.
2603%
cristy4c08aed2011-07-01 19:47:50 +00002604% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002605%
2606*/
cristya6577ff2011-09-02 19:54:26 +00002607MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002608 NexusInfo *nexus_info)
2609{
2610 CacheInfo
2611 *cache_info;
2612
cristy9f027d12011-09-21 01:17:17 +00002613 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002614 cache_info=(CacheInfo *) cache;
2615 assert(cache_info->signature == MagickSignature);
2616 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002617 return((void *) NULL);
2618 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002619}
2620
2621/*
2622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2623% %
2624% %
2625% %
2626+ G e t P i x e l C a c h e N e x u s P i x e l s %
2627% %
2628% %
2629% %
2630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2631%
2632% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2633% cache nexus.
2634%
2635% The format of the GetPixelCacheNexusPixels() method is:
2636%
cristy4c08aed2011-07-01 19:47:50 +00002637% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002638% NexusInfo *nexus_info)
2639%
2640% A description of each parameter follows:
2641%
2642% o cache: the pixel cache.
2643%
2644% o nexus_info: the cache nexus to return the pixels.
2645%
2646*/
cristya6577ff2011-09-02 19:54:26 +00002647MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002648 NexusInfo *nexus_info)
2649{
2650 CacheInfo
2651 *cache_info;
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);
cristy3ed852e2009-09-05 21:47:34 +00002656 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002657 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002658 return(nexus_info->pixels);
2659}
2660
2661/*
2662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2663% %
2664% %
2665% %
cristy056ba772010-01-02 23:33:54 +00002666+ G e t P i x e l C a c h e P i x e l s %
2667% %
2668% %
2669% %
2670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671%
2672% GetPixelCachePixels() returns the pixels associated with the specified image.
2673%
2674% The format of the GetPixelCachePixels() method is:
2675%
cristyf84a1932010-01-03 18:00:18 +00002676% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2677% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002678%
2679% A description of each parameter follows:
2680%
2681% o image: the image.
2682%
2683% o length: the pixel cache length.
2684%
cristyf84a1932010-01-03 18:00:18 +00002685% o exception: return any errors or warnings in this structure.
2686%
cristy056ba772010-01-02 23:33:54 +00002687*/
cristyd1dd6e42011-09-04 01:46:08 +00002688MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002689 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002690{
2691 CacheInfo
2692 *cache_info;
2693
2694 assert(image != (const Image *) NULL);
2695 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002696 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002697 assert(length != (MagickSizeType *) NULL);
2698 assert(exception != (ExceptionInfo *) NULL);
2699 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002700 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002701 assert(cache_info->signature == MagickSignature);
2702 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002703 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002704 return((void *) NULL);
2705 *length=cache_info->length;
2706 return((void *) cache_info->pixels);
2707}
2708
2709/*
2710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711% %
2712% %
2713% %
cristyb32b90a2009-09-07 21:45:48 +00002714+ 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 +00002715% %
2716% %
2717% %
2718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719%
2720% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2721%
2722% The format of the GetPixelCacheStorageClass() method is:
2723%
2724% ClassType GetPixelCacheStorageClass(Cache cache)
2725%
2726% A description of each parameter follows:
2727%
2728% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2729%
2730% o cache: the pixel cache.
2731%
2732*/
cristya6577ff2011-09-02 19:54:26 +00002733MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002734{
2735 CacheInfo
2736 *cache_info;
2737
2738 assert(cache != (Cache) NULL);
2739 cache_info=(CacheInfo *) cache;
2740 assert(cache_info->signature == MagickSignature);
2741 if (cache_info->debug != MagickFalse)
2742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2743 cache_info->filename);
2744 return(cache_info->storage_class);
2745}
2746
2747/*
2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749% %
2750% %
2751% %
cristyb32b90a2009-09-07 21:45:48 +00002752+ G e t P i x e l C a c h e T i l e S i z e %
2753% %
2754% %
2755% %
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757%
2758% GetPixelCacheTileSize() returns the pixel cache tile size.
2759%
2760% The format of the GetPixelCacheTileSize() method is:
2761%
cristybb503372010-05-27 20:51:26 +00002762% void GetPixelCacheTileSize(const Image *image,size_t *width,
2763% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002764%
2765% A description of each parameter follows:
2766%
2767% o image: the image.
2768%
2769% o width: the optimize cache tile width in pixels.
2770%
2771% o height: the optimize cache tile height in pixels.
2772%
2773*/
cristya6577ff2011-09-02 19:54:26 +00002774MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002775 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002776{
cristy4c08aed2011-07-01 19:47:50 +00002777 CacheInfo
2778 *cache_info;
2779
cristyb32b90a2009-09-07 21:45:48 +00002780 assert(image != (Image *) NULL);
2781 assert(image->signature == MagickSignature);
2782 if (image->debug != MagickFalse)
2783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002784 cache_info=(CacheInfo *) image->cache;
2785 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002786 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002787 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002788 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002789 *height=(*width);
2790}
2791
2792/*
2793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794% %
2795% %
2796% %
2797+ G e t P i x e l C a c h e T y p e %
2798% %
2799% %
2800% %
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802%
2803% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2804%
2805% The format of the GetPixelCacheType() method is:
2806%
2807% CacheType GetPixelCacheType(const Image *image)
2808%
2809% A description of each parameter follows:
2810%
2811% o image: the image.
2812%
2813*/
cristya6577ff2011-09-02 19:54:26 +00002814MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002815{
2816 CacheInfo
2817 *cache_info;
2818
2819 assert(image != (Image *) NULL);
2820 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002821 assert(image->cache != (Cache) NULL);
2822 cache_info=(CacheInfo *) image->cache;
2823 assert(cache_info->signature == MagickSignature);
2824 return(cache_info->type);
2825}
2826
2827/*
2828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829% %
2830% %
2831% %
cristy3ed852e2009-09-05 21:47:34 +00002832+ 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 %
2833% %
2834% %
2835% %
2836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837%
2838% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2839% pixel cache. A virtual pixel is any pixel access that is outside the
2840% boundaries of the image cache.
2841%
2842% The format of the GetPixelCacheVirtualMethod() method is:
2843%
2844% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2845%
2846% A description of each parameter follows:
2847%
2848% o image: the image.
2849%
2850*/
cristyd1dd6e42011-09-04 01:46:08 +00002851MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002852{
2853 CacheInfo
2854 *cache_info;
2855
2856 assert(image != (Image *) NULL);
2857 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002858 assert(image->cache != (Cache) NULL);
2859 cache_info=(CacheInfo *) image->cache;
2860 assert(cache_info->signature == MagickSignature);
2861 return(cache_info->virtual_pixel_method);
2862}
2863
2864/*
2865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866% %
2867% %
2868% %
cristy4c08aed2011-07-01 19:47:50 +00002869+ 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 +00002870% %
2871% %
2872% %
2873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874%
cristy4c08aed2011-07-01 19:47:50 +00002875% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2876% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002877%
cristy4c08aed2011-07-01 19:47:50 +00002878% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002879%
cristy4c08aed2011-07-01 19:47:50 +00002880% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002881%
2882% A description of each parameter follows:
2883%
2884% o image: the image.
2885%
2886*/
cristy4c08aed2011-07-01 19:47:50 +00002887static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002888{
2889 CacheInfo
2890 *cache_info;
2891
cristy5c9e6f22010-09-17 17:31:01 +00002892 const int
2893 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002894
cristy4c08aed2011-07-01 19:47:50 +00002895 const void
2896 *metacontent;
2897
cristye7cc7cf2010-09-21 13:26:47 +00002898 assert(image != (const Image *) NULL);
2899 assert(image->signature == MagickSignature);
2900 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002901 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002902 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002903 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002904 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2905 cache_info->nexus_info[id]);
2906 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002907}
2908
2909/*
2910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911% %
2912% %
2913% %
cristy4c08aed2011-07-01 19:47:50 +00002914+ 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 +00002915% %
2916% %
2917% %
2918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919%
cristy4c08aed2011-07-01 19:47:50 +00002920% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2921% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002922%
cristy4c08aed2011-07-01 19:47:50 +00002923% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002924%
cristy4c08aed2011-07-01 19:47:50 +00002925% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002926% NexusInfo *nexus_info)
2927%
2928% A description of each parameter follows:
2929%
2930% o cache: the pixel cache.
2931%
cristy4c08aed2011-07-01 19:47:50 +00002932% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002933%
2934*/
cristya6577ff2011-09-02 19:54:26 +00002935MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002936 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002937{
2938 CacheInfo
2939 *cache_info;
2940
cristye7cc7cf2010-09-21 13:26:47 +00002941 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002942 cache_info=(CacheInfo *) cache;
2943 assert(cache_info->signature == MagickSignature);
2944 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002945 return((void *) NULL);
2946 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002947}
2948
2949/*
2950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2951% %
2952% %
2953% %
cristy4c08aed2011-07-01 19:47:50 +00002954% 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 +00002955% %
2956% %
2957% %
2958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2959%
cristy4c08aed2011-07-01 19:47:50 +00002960% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2961% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2962% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002963%
cristy4c08aed2011-07-01 19:47:50 +00002964% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002965%
cristy4c08aed2011-07-01 19:47:50 +00002966% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002967%
2968% A description of each parameter follows:
2969%
2970% o image: the image.
2971%
2972*/
cristy4c08aed2011-07-01 19:47:50 +00002973MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002974{
2975 CacheInfo
2976 *cache_info;
2977
cristy2036f5c2010-09-19 21:18:17 +00002978 const int
2979 id = GetOpenMPThreadId();
2980
cristy4c08aed2011-07-01 19:47:50 +00002981 const void
2982 *metacontent;
2983
cristy3ed852e2009-09-05 21:47:34 +00002984 assert(image != (const Image *) NULL);
2985 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002986 assert(image->cache != (Cache) NULL);
2987 cache_info=(CacheInfo *) image->cache;
2988 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002989 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2990 (GetVirtualMetacontentFromHandler) NULL)
2991 {
2992 metacontent=cache_info->methods.
2993 get_virtual_metacontent_from_handler(image);
2994 return(metacontent);
2995 }
cristy2036f5c2010-09-19 21:18:17 +00002996 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002997 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2998 cache_info->nexus_info[id]);
2999 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003000}
3001
3002/*
3003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004% %
3005% %
3006% %
3007+ 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 %
3008% %
3009% %
3010% %
3011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3012%
3013% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3014% pixel cache as defined by the geometry parameters. A pointer to the pixels
3015% is returned if the pixels are transferred, otherwise a NULL is returned.
3016%
3017% The format of the GetVirtualPixelsFromNexus() method is:
3018%
cristy4c08aed2011-07-01 19:47:50 +00003019% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003020% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003021% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3022% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003023%
3024% A description of each parameter follows:
3025%
3026% o image: the image.
3027%
3028% o virtual_pixel_method: the virtual pixel method.
3029%
3030% o x,y,columns,rows: These values define the perimeter of a region of
3031% pixels.
3032%
3033% o nexus_info: the cache nexus to acquire.
3034%
3035% o exception: return any errors or warnings in this structure.
3036%
3037*/
3038
cristybb503372010-05-27 20:51:26 +00003039static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003040 DitherMatrix[64] =
3041 {
3042 0, 48, 12, 60, 3, 51, 15, 63,
3043 32, 16, 44, 28, 35, 19, 47, 31,
3044 8, 56, 4, 52, 11, 59, 7, 55,
3045 40, 24, 36, 20, 43, 27, 39, 23,
3046 2, 50, 14, 62, 1, 49, 13, 61,
3047 34, 18, 46, 30, 33, 17, 45, 29,
3048 10, 58, 6, 54, 9, 57, 5, 53,
3049 42, 26, 38, 22, 41, 25, 37, 21
3050 };
3051
cristybb503372010-05-27 20:51:26 +00003052static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003053{
cristybb503372010-05-27 20:51:26 +00003054 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003055 index;
3056
3057 index=x+DitherMatrix[x & 0x07]-32L;
3058 if (index < 0L)
3059 return(0L);
cristybb503372010-05-27 20:51:26 +00003060 if (index >= (ssize_t) columns)
3061 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003062 return(index);
3063}
3064
cristybb503372010-05-27 20:51:26 +00003065static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003066{
cristybb503372010-05-27 20:51:26 +00003067 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003068 index;
3069
3070 index=y+DitherMatrix[y & 0x07]-32L;
3071 if (index < 0L)
3072 return(0L);
cristybb503372010-05-27 20:51:26 +00003073 if (index >= (ssize_t) rows)
3074 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003075 return(index);
3076}
3077
cristybb503372010-05-27 20:51:26 +00003078static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003079{
3080 if (x < 0L)
3081 return(0L);
cristybb503372010-05-27 20:51:26 +00003082 if (x >= (ssize_t) columns)
3083 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003084 return(x);
3085}
3086
cristybb503372010-05-27 20:51:26 +00003087static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003088{
3089 if (y < 0L)
3090 return(0L);
cristybb503372010-05-27 20:51:26 +00003091 if (y >= (ssize_t) rows)
3092 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003093 return(y);
3094}
3095
cristybb503372010-05-27 20:51:26 +00003096static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003097{
cristybb503372010-05-27 20:51:26 +00003098 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003099}
3100
cristybb503372010-05-27 20:51:26 +00003101static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003102{
cristybb503372010-05-27 20:51:26 +00003103 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003104}
3105
cristybb503372010-05-27 20:51:26 +00003106static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3107 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003108{
3109 MagickModulo
3110 modulo;
3111
cristy6162bb42011-07-18 11:34:09 +00003112 /*
3113 Compute the remainder of dividing offset by extent. It returns not only
3114 the quotient (tile the offset falls in) but also the positive remainer
3115 within that tile such that 0 <= remainder < extent. This method is
3116 essentially a ldiv() using a floored modulo division rather than the
3117 normal default truncated modulo division.
3118 */
cristybb503372010-05-27 20:51:26 +00003119 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003120 if (offset < 0L)
3121 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003122 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003123 return(modulo);
3124}
3125
cristya6577ff2011-09-02 19:54:26 +00003126MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003127 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3128 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003129 ExceptionInfo *exception)
3130{
3131 CacheInfo
3132 *cache_info;
3133
3134 MagickOffsetType
3135 offset;
3136
3137 MagickSizeType
3138 length,
3139 number_pixels;
3140
3141 NexusInfo
3142 **virtual_nexus;
3143
cristy4c08aed2011-07-01 19:47:50 +00003144 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003145 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003146 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003147
3148 RectangleInfo
3149 region;
3150
cristy4c08aed2011-07-01 19:47:50 +00003151 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003152 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003153
cristy4c08aed2011-07-01 19:47:50 +00003154 register const void
3155 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003156
cristy4c08aed2011-07-01 19:47:50 +00003157 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003158 *restrict q;
3159
cristybb503372010-05-27 20:51:26 +00003160 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003161 i,
3162 u;
cristy3ed852e2009-09-05 21:47:34 +00003163
cristy4c08aed2011-07-01 19:47:50 +00003164 register unsigned char
3165 *restrict s;
3166
cristy105ba3c2011-07-18 02:28:38 +00003167 ssize_t
3168 v;
3169
cristy4c08aed2011-07-01 19:47:50 +00003170 void
cristy105ba3c2011-07-18 02:28:38 +00003171 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003172
cristy3ed852e2009-09-05 21:47:34 +00003173 /*
3174 Acquire pixels.
3175 */
cristye7cc7cf2010-09-21 13:26:47 +00003176 assert(image != (const Image *) NULL);
3177 assert(image->signature == MagickSignature);
3178 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003179 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003180 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003181 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003182 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003183 region.x=x;
3184 region.y=y;
3185 region.width=columns;
3186 region.height=rows;
3187 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003188 if (pixels == (Quantum *) NULL)
3189 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003190 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003191 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3192 nexus_info->region.x;
3193 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3194 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003195 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3196 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003197 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3198 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003199 {
3200 MagickBooleanType
3201 status;
3202
3203 /*
3204 Pixel request is inside cache extents.
3205 */
cristy4c08aed2011-07-01 19:47:50 +00003206 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003207 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003208 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3209 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003210 return((const Quantum *) NULL);
3211 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003212 {
cristy4c08aed2011-07-01 19:47:50 +00003213 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003214 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003215 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003216 }
cristyacd2ed22011-08-30 01:44:23 +00003217 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003218 }
3219 /*
3220 Pixel request is outside cache extents.
3221 */
cristy4c08aed2011-07-01 19:47:50 +00003222 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003223 virtual_nexus=AcquirePixelCacheNexus(1);
3224 if (virtual_nexus == (NexusInfo **) NULL)
3225 {
cristy4c08aed2011-07-01 19:47:50 +00003226 if (virtual_nexus != (NexusInfo **) NULL)
3227 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003228 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3229 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003230 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003231 }
cristy105ba3c2011-07-18 02:28:38 +00003232 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3233 sizeof(*virtual_pixel));
3234 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003235 switch (virtual_pixel_method)
3236 {
cristy4c08aed2011-07-01 19:47:50 +00003237 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003238 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003239 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003240 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003241 case MaskVirtualPixelMethod:
3242 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003243 case EdgeVirtualPixelMethod:
3244 case CheckerTileVirtualPixelMethod:
3245 case HorizontalTileVirtualPixelMethod:
3246 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003247 {
cristy4c08aed2011-07-01 19:47:50 +00003248 if (cache_info->metacontent_extent != 0)
3249 {
cristy6162bb42011-07-18 11:34:09 +00003250 /*
3251 Acquire a metacontent buffer.
3252 */
cristya64b85d2011-09-14 01:02:31 +00003253 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003254 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003255 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003256 {
cristy4c08aed2011-07-01 19:47:50 +00003257 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3258 (void) ThrowMagickException(exception,GetMagickModule(),
3259 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3260 return((const Quantum *) NULL);
3261 }
cristy105ba3c2011-07-18 02:28:38 +00003262 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003263 cache_info->metacontent_extent);
3264 }
3265 switch (virtual_pixel_method)
3266 {
3267 case BlackVirtualPixelMethod:
3268 {
cristy30301712011-07-18 15:06:51 +00003269 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3270 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003271 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3272 break;
3273 }
3274 case GrayVirtualPixelMethod:
3275 {
cristy30301712011-07-18 15:06:51 +00003276 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003277 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3278 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003279 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3280 break;
3281 }
3282 case TransparentVirtualPixelMethod:
3283 {
cristy30301712011-07-18 15:06:51 +00003284 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3285 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003286 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3287 break;
3288 }
3289 case MaskVirtualPixelMethod:
3290 case WhiteVirtualPixelMethod:
3291 {
cristy30301712011-07-18 15:06:51 +00003292 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3293 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003294 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3295 break;
3296 }
3297 default:
3298 {
3299 SetPixelRed(image,image->background_color.red,virtual_pixel);
3300 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3301 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003302 if (image->colorspace == CMYKColorspace)
3303 SetPixelBlack(image,image->background_color.black,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003304 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3305 break;
3306 }
3307 }
cristy3ed852e2009-09-05 21:47:34 +00003308 break;
3309 }
3310 default:
cristy3ed852e2009-09-05 21:47:34 +00003311 break;
cristy3ed852e2009-09-05 21:47:34 +00003312 }
cristybb503372010-05-27 20:51:26 +00003313 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003314 {
cristybb503372010-05-27 20:51:26 +00003315 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003316 {
3317 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003318 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003319 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3320 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003321 {
3322 MagickModulo
3323 x_modulo,
3324 y_modulo;
3325
3326 /*
3327 Transfer a single pixel.
3328 */
3329 length=(MagickSizeType) 1;
3330 switch (virtual_pixel_method)
3331 {
cristy3ed852e2009-09-05 21:47:34 +00003332 default:
3333 {
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003335 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003336 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003338 break;
3339 }
3340 case RandomVirtualPixelMethod:
3341 {
3342 if (cache_info->random_info == (RandomInfo *) NULL)
3343 cache_info->random_info=AcquireRandomInfo();
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003345 RandomX(cache_info->random_info,cache_info->columns),
3346 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003347 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003348 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003349 break;
3350 }
3351 case DitherVirtualPixelMethod:
3352 {
3353 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003354 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003355 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003356 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003357 break;
3358 }
3359 case TileVirtualPixelMethod:
3360 {
3361 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3362 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003364 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003365 exception);
cristy4c08aed2011-07-01 19:47:50 +00003366 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
3368 }
3369 case MirrorVirtualPixelMethod:
3370 {
3371 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3372 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003373 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003374 x_modulo.remainder-1L;
3375 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3376 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003377 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003378 y_modulo.remainder-1L;
3379 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003380 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003381 exception);
cristy4c08aed2011-07-01 19:47:50 +00003382 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003383 break;
3384 }
3385 case HorizontalTileEdgeVirtualPixelMethod:
3386 {
3387 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3388 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003389 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003390 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003391 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003392 break;
3393 }
3394 case VerticalTileEdgeVirtualPixelMethod:
3395 {
3396 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3397 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003398 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003399 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003400 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3401 break;
3402 }
3403 case BackgroundVirtualPixelMethod:
3404 case BlackVirtualPixelMethod:
3405 case GrayVirtualPixelMethod:
3406 case TransparentVirtualPixelMethod:
3407 case MaskVirtualPixelMethod:
3408 case WhiteVirtualPixelMethod:
3409 {
3410 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003411 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003412 break;
3413 }
3414 case EdgeVirtualPixelMethod:
3415 case CheckerTileVirtualPixelMethod:
3416 {
3417 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3418 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3419 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3420 {
3421 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003422 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003423 break;
3424 }
3425 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3426 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3427 exception);
3428 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3429 break;
3430 }
3431 case HorizontalTileVirtualPixelMethod:
3432 {
3433 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3434 {
3435 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003436 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003437 break;
3438 }
3439 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3440 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3441 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3442 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3443 exception);
3444 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3445 break;
3446 }
3447 case VerticalTileVirtualPixelMethod:
3448 {
3449 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3450 {
3451 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003452 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003453 break;
3454 }
3455 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3456 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3457 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3458 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3459 exception);
3460 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003461 break;
3462 }
3463 }
cristy4c08aed2011-07-01 19:47:50 +00003464 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003465 break;
cristyed231572011-07-14 02:18:59 +00003466 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003467 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003468 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003469 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003470 {
3471 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3472 s+=cache_info->metacontent_extent;
3473 }
cristy3ed852e2009-09-05 21:47:34 +00003474 continue;
3475 }
3476 /*
3477 Transfer a run of pixels.
3478 */
cristy4c08aed2011-07-01 19:47:50 +00003479 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3480 length,1UL,*virtual_nexus,exception);
3481 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003482 break;
cristy4c08aed2011-07-01 19:47:50 +00003483 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003484 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3485 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003486 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003487 {
cristy4c08aed2011-07-01 19:47:50 +00003488 (void) memcpy(s,r,(size_t) length);
3489 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003490 }
3491 }
3492 }
cristy4c08aed2011-07-01 19:47:50 +00003493 /*
3494 Free resources.
3495 */
cristy105ba3c2011-07-18 02:28:38 +00003496 if (virtual_metacontent != (void *) NULL)
3497 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003498 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3499 return(pixels);
3500}
3501
3502/*
3503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3504% %
3505% %
3506% %
3507+ G e t V i r t u a l P i x e l C a c h e %
3508% %
3509% %
3510% %
3511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3512%
3513% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3514% cache as defined by the geometry parameters. A pointer to the pixels
3515% is returned if the pixels are transferred, otherwise a NULL is returned.
3516%
3517% The format of the GetVirtualPixelCache() method is:
3518%
cristy4c08aed2011-07-01 19:47:50 +00003519% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003520% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3521% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003522% ExceptionInfo *exception)
3523%
3524% A description of each parameter follows:
3525%
3526% o image: the image.
3527%
3528% o virtual_pixel_method: the virtual pixel method.
3529%
3530% o x,y,columns,rows: These values define the perimeter of a region of
3531% pixels.
3532%
3533% o exception: return any errors or warnings in this structure.
3534%
3535*/
cristy4c08aed2011-07-01 19:47:50 +00003536static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003537 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3538 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003539{
3540 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003541 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003542
cristy5c9e6f22010-09-17 17:31:01 +00003543 const int
3544 id = GetOpenMPThreadId();
3545
cristy4c08aed2011-07-01 19:47:50 +00003546 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003547 *p;
cristy4c08aed2011-07-01 19:47:50 +00003548
cristye7cc7cf2010-09-21 13:26:47 +00003549 assert(image != (const Image *) NULL);
3550 assert(image->signature == MagickSignature);
3551 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003552 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003553 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003554 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003555 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003556 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003557 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003558}
3559
3560/*
3561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562% %
3563% %
3564% %
3565% G e t V i r t u a l P i x e l Q u e u e %
3566% %
3567% %
3568% %
3569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3570%
cristy4c08aed2011-07-01 19:47:50 +00003571% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3572% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003573%
3574% The format of the GetVirtualPixelQueue() method is:
3575%
cristy4c08aed2011-07-01 19:47:50 +00003576% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003577%
3578% A description of each parameter follows:
3579%
3580% o image: the image.
3581%
3582*/
cristy4c08aed2011-07-01 19:47:50 +00003583MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003584{
3585 CacheInfo
3586 *cache_info;
3587
cristy2036f5c2010-09-19 21:18:17 +00003588 const int
3589 id = GetOpenMPThreadId();
3590
cristy3ed852e2009-09-05 21:47:34 +00003591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003593 assert(image->cache != (Cache) NULL);
3594 cache_info=(CacheInfo *) image->cache;
3595 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003596 if (cache_info->methods.get_virtual_pixels_handler !=
3597 (GetVirtualPixelsHandler) NULL)
3598 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003599 assert(id < (int) cache_info->number_threads);
3600 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003601}
3602
3603/*
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605% %
3606% %
3607% %
3608% G e t V i r t u a l P i x e l s %
3609% %
3610% %
3611% %
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613%
3614% GetVirtualPixels() returns an immutable pixel region. If the
3615% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003616% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003617% copy of the pixels or it may point to the original pixels in memory.
3618% Performance is maximized if the selected region is part of one row, or one
3619% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003620% (without a copy) if the image is in memory, or in a memory-mapped file. The
3621% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003622%
3623% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003624% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3625% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3626% access the meta-content (of type void) corresponding to the the
3627% region.
cristy3ed852e2009-09-05 21:47:34 +00003628%
3629% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3630%
3631% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3632% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3633% GetCacheViewAuthenticPixels() instead.
3634%
3635% The format of the GetVirtualPixels() method is:
3636%
cristy4c08aed2011-07-01 19:47:50 +00003637% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003638% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003639% ExceptionInfo *exception)
3640%
3641% A description of each parameter follows:
3642%
3643% o image: the image.
3644%
3645% o x,y,columns,rows: These values define the perimeter of a region of
3646% pixels.
3647%
3648% o exception: return any errors or warnings in this structure.
3649%
3650*/
cristy4c08aed2011-07-01 19:47:50 +00003651MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003652 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3653 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003654{
3655 CacheInfo
3656 *cache_info;
3657
cristy2036f5c2010-09-19 21:18:17 +00003658 const int
3659 id = GetOpenMPThreadId();
3660
cristy4c08aed2011-07-01 19:47:50 +00003661 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003662 *p;
cristy4c08aed2011-07-01 19:47:50 +00003663
cristy3ed852e2009-09-05 21:47:34 +00003664 assert(image != (const Image *) NULL);
3665 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003666 assert(image->cache != (Cache) NULL);
3667 cache_info=(CacheInfo *) image->cache;
3668 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003669 if (cache_info->methods.get_virtual_pixel_handler !=
3670 (GetVirtualPixelHandler) NULL)
3671 return(cache_info->methods.get_virtual_pixel_handler(image,
3672 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003673 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003674 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003675 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003676 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003677}
3678
3679/*
3680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3681% %
3682% %
3683% %
3684+ 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 %
3685% %
3686% %
3687% %
3688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3689%
cristy4c08aed2011-07-01 19:47:50 +00003690% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3691% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003692%
3693% The format of the GetVirtualPixelsCache() method is:
3694%
cristy4c08aed2011-07-01 19:47:50 +00003695% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003696%
3697% A description of each parameter follows:
3698%
3699% o image: the image.
3700%
3701*/
cristy4c08aed2011-07-01 19:47:50 +00003702static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003703{
3704 CacheInfo
3705 *cache_info;
3706
cristy5c9e6f22010-09-17 17:31:01 +00003707 const int
3708 id = GetOpenMPThreadId();
3709
cristye7cc7cf2010-09-21 13:26:47 +00003710 assert(image != (const Image *) NULL);
3711 assert(image->signature == MagickSignature);
3712 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003713 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003714 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003715 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003716 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003717}
3718
3719/*
3720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3721% %
3722% %
3723% %
3724+ G e t V i r t u a l P i x e l s N e x u s %
3725% %
3726% %
3727% %
3728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3729%
3730% GetVirtualPixelsNexus() returns the pixels associated with the specified
3731% cache nexus.
3732%
3733% The format of the GetVirtualPixelsNexus() method is:
3734%
cristy4c08aed2011-07-01 19:47:50 +00003735% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003736% NexusInfo *nexus_info)
3737%
3738% A description of each parameter follows:
3739%
3740% o cache: the pixel cache.
3741%
3742% o nexus_info: the cache nexus to return the colormap pixels.
3743%
3744*/
cristya6577ff2011-09-02 19:54:26 +00003745MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003746 NexusInfo *nexus_info)
3747{
3748 CacheInfo
3749 *cache_info;
3750
cristye7cc7cf2010-09-21 13:26:47 +00003751 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003752 cache_info=(CacheInfo *) cache;
3753 assert(cache_info->signature == MagickSignature);
3754 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003755 return((Quantum *) NULL);
3756 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003757}
3758
3759/*
3760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3761% %
3762% %
3763% %
3764+ M a s k P i x e l C a c h e N e x u s %
3765% %
3766% %
3767% %
3768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3769%
3770% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3771% The method returns MagickTrue if the pixel region is masked, otherwise
3772% MagickFalse.
3773%
3774% The format of the MaskPixelCacheNexus() method is:
3775%
3776% MagickBooleanType MaskPixelCacheNexus(Image *image,
3777% NexusInfo *nexus_info,ExceptionInfo *exception)
3778%
3779% A description of each parameter follows:
3780%
3781% o image: the image.
3782%
3783% o nexus_info: the cache nexus to clip.
3784%
3785% o exception: return any errors or warnings in this structure.
3786%
3787*/
3788
cristy3aa93752011-12-18 15:54:24 +00003789static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3790 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003791{
3792 MagickRealType
3793 gamma;
3794
cristyaa83c2c2011-09-21 13:36:25 +00003795 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003796 {
3797 *composite=(*q);
3798 return;
3799 }
3800 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3801 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003802 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3803 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3804 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003805 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003806 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003807}
3808
3809static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3810 ExceptionInfo *exception)
3811{
3812 CacheInfo
3813 *cache_info;
3814
cristy4c08aed2011-07-01 19:47:50 +00003815 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003816 alpha,
3817 beta;
3818
3819 MagickSizeType
3820 number_pixels;
3821
3822 NexusInfo
3823 **clip_nexus,
3824 **image_nexus;
3825
cristy4c08aed2011-07-01 19:47:50 +00003826 register const Quantum
3827 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003828 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003829
cristy4c08aed2011-07-01 19:47:50 +00003830 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003831 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003832
cristye076a6e2010-08-15 19:59:43 +00003833 register ssize_t
3834 i;
3835
cristy3ed852e2009-09-05 21:47:34 +00003836 /*
3837 Apply clip mask.
3838 */
3839 if (image->debug != MagickFalse)
3840 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3841 if (image->mask == (Image *) NULL)
3842 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003843 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003844 if (cache_info == (Cache) NULL)
3845 return(MagickFalse);
3846 image_nexus=AcquirePixelCacheNexus(1);
3847 clip_nexus=AcquirePixelCacheNexus(1);
3848 if ((image_nexus == (NexusInfo **) NULL) ||
3849 (clip_nexus == (NexusInfo **) NULL))
3850 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003851 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3852 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3853 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003854 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003855 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3856 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003857 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003858 GetPixelInfo(image,&alpha);
3859 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003860 number_pixels=(MagickSizeType) nexus_info->region.width*
3861 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003862 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003863 {
cristy4c08aed2011-07-01 19:47:50 +00003864 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003865 break;
cristy803640d2011-11-17 02:11:32 +00003866 GetPixelInfoPixel(image,p,&alpha);
3867 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003868 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003869 &alpha,alpha.alpha,&beta);
3870 SetPixelRed(image,ClampToQuantum(beta.red),q);
3871 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3872 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3873 if (cache_info->colorspace == CMYKColorspace)
3874 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3875 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003876 p++;
3877 q++;
3878 r++;
3879 }
3880 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3881 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003882 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003883 return(MagickFalse);
3884 return(MagickTrue);
3885}
3886
3887/*
3888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3889% %
3890% %
3891% %
3892+ O p e n P i x e l C a c h e %
3893% %
3894% %
3895% %
3896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3897%
3898% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3899% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003900% metacontent, and memory mapping the cache if it is disk based. The cache
3901% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003902%
3903% The format of the OpenPixelCache() method is:
3904%
3905% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3906% ExceptionInfo *exception)
3907%
3908% A description of each parameter follows:
3909%
3910% o image: the image.
3911%
3912% o mode: ReadMode, WriteMode, or IOMode.
3913%
3914% o exception: return any errors or warnings in this structure.
3915%
3916*/
3917
cristyd43a46b2010-01-21 02:13:41 +00003918static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003919{
3920 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003921 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003922 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003923 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003924 {
3925 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003926 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003927 cache_info->length);
3928 }
3929}
3930
3931static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3932{
3933 CacheInfo
3934 *cache_info;
3935
3936 MagickOffsetType
3937 count,
3938 extent,
3939 offset;
3940
3941 cache_info=(CacheInfo *) image->cache;
3942 if (image->debug != MagickFalse)
3943 {
3944 char
3945 format[MaxTextExtent],
3946 message[MaxTextExtent];
3947
cristyb9080c92009-12-01 20:13:26 +00003948 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003949 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003950 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003951 cache_info->cache_filename,cache_info->file,format);
3952 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3953 }
3954 if (length != (MagickSizeType) ((MagickOffsetType) length))
3955 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003956 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003957 if (extent < 0)
3958 return(MagickFalse);
3959 if ((MagickSizeType) extent >= length)
3960 return(MagickTrue);
3961 offset=(MagickOffsetType) length-1;
3962 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3963 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3964}
3965
3966static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3967 ExceptionInfo *exception)
3968{
cristy3ed852e2009-09-05 21:47:34 +00003969 CacheInfo
3970 *cache_info,
3971 source_info;
3972
cristyf3a6a9d2010-11-07 21:02:56 +00003973 char
3974 format[MaxTextExtent],
3975 message[MaxTextExtent];
3976
cristy4c08aed2011-07-01 19:47:50 +00003977 MagickBooleanType
3978 status;
3979
cristy3ed852e2009-09-05 21:47:34 +00003980 MagickSizeType
3981 length,
3982 number_pixels;
3983
cristy3ed852e2009-09-05 21:47:34 +00003984 size_t
cristye076a6e2010-08-15 19:59:43 +00003985 columns,
cristy3ed852e2009-09-05 21:47:34 +00003986 packet_size;
3987
cristye7cc7cf2010-09-21 13:26:47 +00003988 assert(image != (const Image *) NULL);
3989 assert(image->signature == MagickSignature);
3990 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003991 if (image->debug != MagickFalse)
3992 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3993 if ((image->columns == 0) || (image->rows == 0))
3994 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3995 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003996 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003997 source_info=(*cache_info);
3998 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003999 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004000 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004001 cache_info->storage_class=image->storage_class;
4002 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004003 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004004 cache_info->rows=image->rows;
4005 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004006 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004007 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004008 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004009 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004010 if (image->ping != MagickFalse)
4011 {
cristy73724512010-04-12 14:43:14 +00004012 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004013 cache_info->pixels=(Quantum *) NULL;
4014 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004015 cache_info->length=0;
4016 return(MagickTrue);
4017 }
cristy3ed852e2009-09-05 21:47:34 +00004018 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004019 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004020 if (image->metacontent_extent != 0)
4021 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004022 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004023 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004024 if (cache_info->columns != columns)
4025 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4026 image->filename);
4027 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004028 if ((cache_info->type != UndefinedCache) &&
4029 (cache_info->columns <= source_info.columns) &&
4030 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004031 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004032 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4033 {
4034 /*
4035 Inline pixel cache clone optimization.
4036 */
4037 if ((cache_info->columns == source_info.columns) &&
4038 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004039 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004040 (cache_info->metacontent_extent == source_info.metacontent_extent))
4041 return(MagickTrue);
4042 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4043 }
cristy3ed852e2009-09-05 21:47:34 +00004044 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004045 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004046 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004047 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4048 {
4049 status=AcquireMagickResource(MemoryResource,cache_info->length);
4050 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4051 (cache_info->type == MemoryCache))
4052 {
cristyd43a46b2010-01-21 02:13:41 +00004053 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004054 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004055 cache_info->pixels=source_info.pixels;
4056 else
4057 {
4058 /*
4059 Create memory pixel cache.
4060 */
cristy4c08aed2011-07-01 19:47:50 +00004061 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004062 if (image->debug != MagickFalse)
4063 {
cristy97e7a572009-12-05 15:07:53 +00004064 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004065 format);
cristyb51dff52011-05-19 16:55:47 +00004066 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004067 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4068 cache_info->filename,cache_info->mapped != MagickFalse ?
4069 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004070 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004071 format);
cristy3ed852e2009-09-05 21:47:34 +00004072 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4073 message);
4074 }
cristy3ed852e2009-09-05 21:47:34 +00004075 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004076 cache_info->metacontent=(void *) NULL;
4077 if (cache_info->metacontent_extent != 0)
4078 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004079 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004080 if (source_info.storage_class != UndefinedClass)
4081 {
cristy4c08aed2011-07-01 19:47:50 +00004082 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004083 exception);
4084 RelinquishPixelCachePixels(&source_info);
4085 }
cristy4c08aed2011-07-01 19:47:50 +00004086 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004087 }
4088 }
4089 RelinquishMagickResource(MemoryResource,cache_info->length);
4090 }
4091 /*
4092 Create pixel cache on disk.
4093 */
4094 status=AcquireMagickResource(DiskResource,cache_info->length);
4095 if (status == MagickFalse)
4096 {
4097 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4098 "CacheResourcesExhausted","`%s'",image->filename);
4099 return(MagickFalse);
4100 }
4101 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4102 {
4103 RelinquishMagickResource(DiskResource,cache_info->length);
4104 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4105 image->filename);
4106 return(MagickFalse);
4107 }
4108 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4109 cache_info->length);
4110 if (status == MagickFalse)
4111 {
4112 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4113 image->filename);
4114 return(MagickFalse);
4115 }
cristyed231572011-07-14 02:18:59 +00004116 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004117 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004118 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004119 cache_info->type=DiskCache;
4120 else
4121 {
4122 status=AcquireMagickResource(MapResource,cache_info->length);
4123 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4124 (cache_info->type != MemoryCache))
4125 cache_info->type=DiskCache;
4126 else
4127 {
cristy4c08aed2011-07-01 19:47:50 +00004128 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004129 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004130 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004131 {
cristy3ed852e2009-09-05 21:47:34 +00004132 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004133 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004134 }
4135 else
4136 {
4137 /*
4138 Create file-backed memory-mapped pixel cache.
4139 */
cristy4c08aed2011-07-01 19:47:50 +00004140 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004141 (void) ClosePixelCacheOnDisk(cache_info);
4142 cache_info->type=MapCache;
4143 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004144 cache_info->metacontent=(void *) NULL;
4145 if (cache_info->metacontent_extent != 0)
4146 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004147 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004148 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004149 {
4150 status=ClonePixelCachePixels(cache_info,&source_info,
4151 exception);
4152 RelinquishPixelCachePixels(&source_info);
4153 }
4154 if (image->debug != MagickFalse)
4155 {
cristy97e7a572009-12-05 15:07:53 +00004156 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004157 format);
cristyb51dff52011-05-19 16:55:47 +00004158 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004159 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004160 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004161 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004162 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004163 format);
cristy3ed852e2009-09-05 21:47:34 +00004164 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4165 message);
4166 }
cristy4c08aed2011-07-01 19:47:50 +00004167 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004168 }
4169 }
4170 RelinquishMagickResource(MapResource,cache_info->length);
4171 }
cristy4c08aed2011-07-01 19:47:50 +00004172 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004173 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4174 {
4175 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4176 RelinquishPixelCachePixels(&source_info);
4177 }
4178 if (image->debug != MagickFalse)
4179 {
cristyb9080c92009-12-01 20:13:26 +00004180 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004181 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004182 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004183 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004184 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004185 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004186 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4187 }
cristy4c08aed2011-07-01 19:47:50 +00004188 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004189}
4190
4191/*
4192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4193% %
4194% %
4195% %
4196+ P e r s i s t P i x e l C a c h e %
4197% %
4198% %
4199% %
4200%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4201%
4202% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4203% persistent pixel cache is one that resides on disk and is not destroyed
4204% when the program exits.
4205%
4206% The format of the PersistPixelCache() method is:
4207%
4208% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4209% const MagickBooleanType attach,MagickOffsetType *offset,
4210% ExceptionInfo *exception)
4211%
4212% A description of each parameter follows:
4213%
4214% o image: the image.
4215%
4216% o filename: the persistent pixel cache filename.
4217%
cristyf3a6a9d2010-11-07 21:02:56 +00004218% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004219%
cristy3ed852e2009-09-05 21:47:34 +00004220% o initialize: A value other than zero initializes the persistent pixel
4221% cache.
4222%
4223% o offset: the offset in the persistent cache to store pixels.
4224%
4225% o exception: return any errors or warnings in this structure.
4226%
4227*/
4228MagickExport MagickBooleanType PersistPixelCache(Image *image,
4229 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4230 ExceptionInfo *exception)
4231{
4232 CacheInfo
4233 *cache_info,
4234 *clone_info;
4235
4236 Image
4237 clone_image;
4238
cristy3ed852e2009-09-05 21:47:34 +00004239 MagickBooleanType
4240 status;
4241
cristye076a6e2010-08-15 19:59:43 +00004242 ssize_t
4243 page_size;
4244
cristy3ed852e2009-09-05 21:47:34 +00004245 assert(image != (Image *) NULL);
4246 assert(image->signature == MagickSignature);
4247 if (image->debug != MagickFalse)
4248 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4249 assert(image->cache != (void *) NULL);
4250 assert(filename != (const char *) NULL);
4251 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004252 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004253 cache_info=(CacheInfo *) image->cache;
4254 assert(cache_info->signature == MagickSignature);
4255 if (attach != MagickFalse)
4256 {
4257 /*
cristy01b7eb02009-09-10 23:10:14 +00004258 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004259 */
4260 if (image->debug != MagickFalse)
4261 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004262 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004263 (void) CopyMagickString(cache_info->cache_filename,filename,
4264 MaxTextExtent);
4265 cache_info->type=DiskCache;
4266 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004267 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004268 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004269 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004270 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004271 }
cristy01b7eb02009-09-10 23:10:14 +00004272 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4273 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004274 {
cristyf84a1932010-01-03 18:00:18 +00004275 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004276 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004277 (cache_info->reference_count == 1))
4278 {
4279 int
4280 status;
4281
4282 /*
cristy01b7eb02009-09-10 23:10:14 +00004283 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004284 */
cristy320684d2011-09-23 14:55:47 +00004285 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004286 if (status == 0)
4287 {
4288 (void) CopyMagickString(cache_info->cache_filename,filename,
4289 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004290 *offset+=cache_info->length+page_size-(cache_info->length %
4291 page_size);
cristyf84a1932010-01-03 18:00:18 +00004292 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004293 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004294 if (image->debug != MagickFalse)
4295 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4296 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004297 return(MagickTrue);
4298 }
4299 }
cristyf84a1932010-01-03 18:00:18 +00004300 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004301 }
4302 /*
cristy01b7eb02009-09-10 23:10:14 +00004303 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004304 */
4305 clone_image=(*image);
4306 clone_info=(CacheInfo *) clone_image.cache;
4307 image->cache=ClonePixelCache(cache_info);
4308 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4309 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4310 cache_info->type=DiskCache;
4311 cache_info->offset=(*offset);
4312 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004313 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004314 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004315 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004316 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004317 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4318 return(status);
4319}
4320
4321/*
4322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4323% %
4324% %
4325% %
4326+ Q u e u e A u t h e n t i c N e x u s %
4327% %
4328% %
4329% %
4330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4331%
4332% QueueAuthenticNexus() allocates an region to store image pixels as defined
4333% by the region rectangle and returns a pointer to the region. This region is
4334% subsequently transferred from the pixel cache with
4335% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4336% pixels are transferred, otherwise a NULL is returned.
4337%
4338% The format of the QueueAuthenticNexus() method is:
4339%
cristy4c08aed2011-07-01 19:47:50 +00004340% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004341% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004342% const MagickBooleanType clone,NexusInfo *nexus_info,
4343% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004344%
4345% A description of each parameter follows:
4346%
4347% o image: the image.
4348%
4349% o x,y,columns,rows: These values define the perimeter of a region of
4350% pixels.
4351%
4352% o nexus_info: the cache nexus to set.
4353%
cristy65dbf172011-10-06 17:32:04 +00004354% o clone: clone the pixel cache.
4355%
cristy3ed852e2009-09-05 21:47:34 +00004356% o exception: return any errors or warnings in this structure.
4357%
4358*/
cristya6577ff2011-09-02 19:54:26 +00004359MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004360 const ssize_t y,const size_t columns,const size_t rows,
4361 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004362{
4363 CacheInfo
4364 *cache_info;
4365
4366 MagickOffsetType
4367 offset;
4368
4369 MagickSizeType
4370 number_pixels;
4371
4372 RectangleInfo
4373 region;
4374
4375 /*
4376 Validate pixel cache geometry.
4377 */
cristye7cc7cf2010-09-21 13:26:47 +00004378 assert(image != (const Image *) NULL);
4379 assert(image->signature == MagickSignature);
4380 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004381 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004382 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004383 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004384 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004385 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4386 {
4387 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4388 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004389 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004390 }
cristybb503372010-05-27 20:51:26 +00004391 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4392 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004393 {
4394 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4395 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004396 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004397 }
4398 offset=(MagickOffsetType) y*cache_info->columns+x;
4399 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004400 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004401 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4402 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4403 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004404 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004405 /*
4406 Return pixel cache.
4407 */
4408 region.x=x;
4409 region.y=y;
4410 region.width=columns;
4411 region.height=rows;
4412 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4413}
4414
4415/*
4416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4417% %
4418% %
4419% %
4420+ 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 %
4421% %
4422% %
4423% %
4424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4425%
4426% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4427% defined by the region rectangle and returns a pointer to the region. This
4428% region is subsequently transferred from the pixel cache with
4429% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4430% pixels are transferred, otherwise a NULL is returned.
4431%
4432% The format of the QueueAuthenticPixelsCache() method is:
4433%
cristy4c08aed2011-07-01 19:47:50 +00004434% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004435% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004436% ExceptionInfo *exception)
4437%
4438% A description of each parameter follows:
4439%
4440% o image: the image.
4441%
4442% o x,y,columns,rows: These values define the perimeter of a region of
4443% pixels.
4444%
4445% o exception: return any errors or warnings in this structure.
4446%
4447*/
cristy4c08aed2011-07-01 19:47:50 +00004448static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004449 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004450 ExceptionInfo *exception)
4451{
4452 CacheInfo
4453 *cache_info;
4454
cristy5c9e6f22010-09-17 17:31:01 +00004455 const int
4456 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004457
cristy4c08aed2011-07-01 19:47:50 +00004458 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004459 *q;
cristy4c08aed2011-07-01 19:47:50 +00004460
cristye7cc7cf2010-09-21 13:26:47 +00004461 assert(image != (const Image *) NULL);
4462 assert(image->signature == MagickSignature);
4463 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004464 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004465 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004466 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004467 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4468 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004469 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004470}
4471
4472/*
4473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474% %
4475% %
4476% %
4477% Q u e u e A u t h e n t i c P i x e l s %
4478% %
4479% %
4480% %
4481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482%
4483% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004484% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004485% region is returned, otherwise NULL is returned. The returned pointer may
4486% point to a temporary working buffer for the pixels or it may point to the
4487% final location of the pixels in memory.
4488%
4489% Write-only access means that any existing pixel values corresponding to
4490% the region are ignored. This is useful if the initial image is being
4491% created from scratch, or if the existing pixel values are to be
4492% completely replaced without need to refer to their pre-existing values.
4493% The application is free to read and write the pixel buffer returned by
4494% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4495% initialize the pixel array values. Initializing pixel array values is the
4496% application's responsibility.
4497%
4498% Performance is maximized if the selected region is part of one row, or
4499% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004500% pixels in-place (without a copy) if the image is in memory, or in a
4501% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004502% by the user.
4503%
4504% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004505% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4506% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4507% obtain the meta-content (of type void) corresponding to the region.
4508% Once the Quantum (and/or Quantum) array has been updated, the
4509% changes must be saved back to the underlying image using
4510% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004511%
4512% The format of the QueueAuthenticPixels() method is:
4513%
cristy4c08aed2011-07-01 19:47:50 +00004514% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004515% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004516% ExceptionInfo *exception)
4517%
4518% A description of each parameter follows:
4519%
4520% o image: the image.
4521%
4522% o x,y,columns,rows: These values define the perimeter of a region of
4523% pixels.
4524%
4525% o exception: return any errors or warnings in this structure.
4526%
4527*/
cristy4c08aed2011-07-01 19:47:50 +00004528MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004529 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004530 ExceptionInfo *exception)
4531{
4532 CacheInfo
4533 *cache_info;
4534
cristy2036f5c2010-09-19 21:18:17 +00004535 const int
4536 id = GetOpenMPThreadId();
4537
cristy4c08aed2011-07-01 19:47:50 +00004538 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004539 *q;
cristy4c08aed2011-07-01 19:47:50 +00004540
cristy3ed852e2009-09-05 21:47:34 +00004541 assert(image != (Image *) NULL);
4542 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004543 assert(image->cache != (Cache) NULL);
4544 cache_info=(CacheInfo *) image->cache;
4545 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004546 if (cache_info->methods.queue_authentic_pixels_handler !=
4547 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004548 {
cristyacd2ed22011-08-30 01:44:23 +00004549 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004550 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004551 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004552 }
cristy2036f5c2010-09-19 21:18:17 +00004553 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004554 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4555 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004556 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004557}
4558
4559/*
4560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561% %
4562% %
4563% %
cristy4c08aed2011-07-01 19:47:50 +00004564+ 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 +00004565% %
4566% %
4567% %
4568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4569%
cristy4c08aed2011-07-01 19:47:50 +00004570% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004571% the pixel cache.
4572%
cristy4c08aed2011-07-01 19:47:50 +00004573% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004574%
cristy4c08aed2011-07-01 19:47:50 +00004575% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004576% NexusInfo *nexus_info,ExceptionInfo *exception)
4577%
4578% A description of each parameter follows:
4579%
4580% o cache_info: the pixel cache.
4581%
cristy4c08aed2011-07-01 19:47:50 +00004582% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004583%
4584% o exception: return any errors or warnings in this structure.
4585%
4586*/
cristy4c08aed2011-07-01 19:47:50 +00004587static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004588 NexusInfo *nexus_info,ExceptionInfo *exception)
4589{
4590 MagickOffsetType
4591 count,
4592 offset;
4593
4594 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004595 extent,
4596 length;
cristy3ed852e2009-09-05 21:47:34 +00004597
cristybb503372010-05-27 20:51:26 +00004598 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004599 y;
4600
cristy4c08aed2011-07-01 19:47:50 +00004601 register unsigned char
4602 *restrict q;
4603
cristybb503372010-05-27 20:51:26 +00004604 size_t
cristy3ed852e2009-09-05 21:47:34 +00004605 rows;
4606
cristy4c08aed2011-07-01 19:47:50 +00004607 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004608 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004609 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004610 return(MagickTrue);
4611 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4612 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004613 length=(MagickSizeType) nexus_info->region.width*
4614 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004615 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004616 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004617 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004618 switch (cache_info->type)
4619 {
4620 case MemoryCache:
4621 case MapCache:
4622 {
cristy4c08aed2011-07-01 19:47:50 +00004623 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004624 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004625
4626 /*
cristy4c08aed2011-07-01 19:47:50 +00004627 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004628 */
cristydd341db2010-03-04 19:06:38 +00004629 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004630 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004631 {
cristy48078b12010-09-23 17:11:01 +00004632 length=extent;
cristydd341db2010-03-04 19:06:38 +00004633 rows=1UL;
4634 }
cristy4c08aed2011-07-01 19:47:50 +00004635 p=(unsigned char *) cache_info->metacontent+offset*
4636 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004637 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004638 {
cristy8f036fe2010-09-18 02:02:00 +00004639 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004640 p+=cache_info->metacontent_extent*cache_info->columns;
4641 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004642 }
4643 break;
4644 }
4645 case DiskCache:
4646 {
4647 /*
cristy4c08aed2011-07-01 19:47:50 +00004648 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004649 */
4650 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4651 {
4652 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4653 cache_info->cache_filename);
4654 return(MagickFalse);
4655 }
cristydd341db2010-03-04 19:06:38 +00004656 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004657 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004658 {
cristy48078b12010-09-23 17:11:01 +00004659 length=extent;
cristydd341db2010-03-04 19:06:38 +00004660 rows=1UL;
4661 }
cristy48078b12010-09-23 17:11:01 +00004662 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004663 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004664 {
cristy48078b12010-09-23 17:11:01 +00004665 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004666 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004667 cache_info->metacontent_extent,length,(unsigned char *) q);
4668 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004669 break;
4670 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004671 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004672 }
cristybb503372010-05-27 20:51:26 +00004673 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004674 {
4675 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4676 cache_info->cache_filename);
4677 return(MagickFalse);
4678 }
4679 break;
4680 }
4681 default:
4682 break;
4683 }
4684 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004685 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004686 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004687 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004688 nexus_info->region.width,(double) nexus_info->region.height,(double)
4689 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004690 return(MagickTrue);
4691}
4692
4693/*
4694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4695% %
4696% %
4697% %
4698+ R e a d P i x e l C a c h e P i x e l s %
4699% %
4700% %
4701% %
4702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703%
4704% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4705% cache.
4706%
4707% The format of the ReadPixelCachePixels() method is:
4708%
4709% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4710% NexusInfo *nexus_info,ExceptionInfo *exception)
4711%
4712% A description of each parameter follows:
4713%
4714% o cache_info: the pixel cache.
4715%
4716% o nexus_info: the cache nexus to read the pixels.
4717%
4718% o exception: return any errors or warnings in this structure.
4719%
4720*/
4721static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4722 NexusInfo *nexus_info,ExceptionInfo *exception)
4723{
4724 MagickOffsetType
4725 count,
4726 offset;
4727
4728 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004729 extent,
4730 length;
cristy3ed852e2009-09-05 21:47:34 +00004731
cristy4c08aed2011-07-01 19:47:50 +00004732 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004733 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004734
cristye076a6e2010-08-15 19:59:43 +00004735 register ssize_t
4736 y;
4737
cristybb503372010-05-27 20:51:26 +00004738 size_t
cristy3ed852e2009-09-05 21:47:34 +00004739 rows;
4740
cristy4c08aed2011-07-01 19:47:50 +00004741 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004742 return(MagickTrue);
4743 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4744 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004745 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004746 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004747 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004748 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004749 q=nexus_info->pixels;
4750 switch (cache_info->type)
4751 {
4752 case MemoryCache:
4753 case MapCache:
4754 {
cristy4c08aed2011-07-01 19:47:50 +00004755 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004756 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004757
4758 /*
4759 Read pixels from memory.
4760 */
cristydd341db2010-03-04 19:06:38 +00004761 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004762 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004763 {
cristy48078b12010-09-23 17:11:01 +00004764 length=extent;
cristydd341db2010-03-04 19:06:38 +00004765 rows=1UL;
4766 }
cristyed231572011-07-14 02:18:59 +00004767 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004768 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004769 {
cristy8f036fe2010-09-18 02:02:00 +00004770 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004771 p+=cache_info->number_channels*cache_info->columns;
4772 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004773 }
4774 break;
4775 }
4776 case DiskCache:
4777 {
4778 /*
4779 Read pixels from disk.
4780 */
4781 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4782 {
4783 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4784 cache_info->cache_filename);
4785 return(MagickFalse);
4786 }
cristydd341db2010-03-04 19:06:38 +00004787 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004788 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004789 {
cristy48078b12010-09-23 17:11:01 +00004790 length=extent;
cristydd341db2010-03-04 19:06:38 +00004791 rows=1UL;
4792 }
cristybb503372010-05-27 20:51:26 +00004793 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004794 {
4795 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004796 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004797 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004798 break;
4799 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004800 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004801 }
cristybb503372010-05-27 20:51:26 +00004802 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004803 {
4804 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4805 cache_info->cache_filename);
4806 return(MagickFalse);
4807 }
4808 break;
4809 }
4810 default:
4811 break;
4812 }
4813 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004814 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004815 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004816 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004817 nexus_info->region.width,(double) nexus_info->region.height,(double)
4818 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004819 return(MagickTrue);
4820}
4821
4822/*
4823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4824% %
4825% %
4826% %
4827+ R e f e r e n c e P i x e l C a c h e %
4828% %
4829% %
4830% %
4831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4832%
4833% ReferencePixelCache() increments the reference count associated with the
4834% pixel cache returning a pointer to the cache.
4835%
4836% The format of the ReferencePixelCache method is:
4837%
4838% Cache ReferencePixelCache(Cache cache_info)
4839%
4840% A description of each parameter follows:
4841%
4842% o cache_info: the pixel cache.
4843%
4844*/
cristya6577ff2011-09-02 19:54:26 +00004845MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004846{
4847 CacheInfo
4848 *cache_info;
4849
4850 assert(cache != (Cache *) NULL);
4851 cache_info=(CacheInfo *) cache;
4852 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004853 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004854 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004855 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004856 return(cache_info);
4857}
4858
4859/*
4860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4861% %
4862% %
4863% %
4864+ S e t P i x e l C a c h e M e t h o d s %
4865% %
4866% %
4867% %
4868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4869%
4870% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4871%
4872% The format of the SetPixelCacheMethods() method is:
4873%
4874% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4875%
4876% A description of each parameter follows:
4877%
4878% o cache: the pixel cache.
4879%
4880% o cache_methods: Specifies a pointer to a CacheMethods structure.
4881%
4882*/
cristya6577ff2011-09-02 19:54:26 +00004883MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004884{
4885 CacheInfo
4886 *cache_info;
4887
4888 GetOneAuthenticPixelFromHandler
4889 get_one_authentic_pixel_from_handler;
4890
4891 GetOneVirtualPixelFromHandler
4892 get_one_virtual_pixel_from_handler;
4893
4894 /*
4895 Set cache pixel methods.
4896 */
4897 assert(cache != (Cache) NULL);
4898 assert(cache_methods != (CacheMethods *) NULL);
4899 cache_info=(CacheInfo *) cache;
4900 assert(cache_info->signature == MagickSignature);
4901 if (cache_info->debug != MagickFalse)
4902 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4903 cache_info->filename);
4904 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4905 cache_info->methods.get_virtual_pixel_handler=
4906 cache_methods->get_virtual_pixel_handler;
4907 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4908 cache_info->methods.destroy_pixel_handler=
4909 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004910 if (cache_methods->get_virtual_metacontent_from_handler !=
4911 (GetVirtualMetacontentFromHandler) NULL)
4912 cache_info->methods.get_virtual_metacontent_from_handler=
4913 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004914 if (cache_methods->get_authentic_pixels_handler !=
4915 (GetAuthenticPixelsHandler) NULL)
4916 cache_info->methods.get_authentic_pixels_handler=
4917 cache_methods->get_authentic_pixels_handler;
4918 if (cache_methods->queue_authentic_pixels_handler !=
4919 (QueueAuthenticPixelsHandler) NULL)
4920 cache_info->methods.queue_authentic_pixels_handler=
4921 cache_methods->queue_authentic_pixels_handler;
4922 if (cache_methods->sync_authentic_pixels_handler !=
4923 (SyncAuthenticPixelsHandler) NULL)
4924 cache_info->methods.sync_authentic_pixels_handler=
4925 cache_methods->sync_authentic_pixels_handler;
4926 if (cache_methods->get_authentic_pixels_from_handler !=
4927 (GetAuthenticPixelsFromHandler) NULL)
4928 cache_info->methods.get_authentic_pixels_from_handler=
4929 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004930 if (cache_methods->get_authentic_metacontent_from_handler !=
4931 (GetAuthenticMetacontentFromHandler) NULL)
4932 cache_info->methods.get_authentic_metacontent_from_handler=
4933 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004934 get_one_virtual_pixel_from_handler=
4935 cache_info->methods.get_one_virtual_pixel_from_handler;
4936 if (get_one_virtual_pixel_from_handler !=
4937 (GetOneVirtualPixelFromHandler) NULL)
4938 cache_info->methods.get_one_virtual_pixel_from_handler=
4939 cache_methods->get_one_virtual_pixel_from_handler;
4940 get_one_authentic_pixel_from_handler=
4941 cache_methods->get_one_authentic_pixel_from_handler;
4942 if (get_one_authentic_pixel_from_handler !=
4943 (GetOneAuthenticPixelFromHandler) NULL)
4944 cache_info->methods.get_one_authentic_pixel_from_handler=
4945 cache_methods->get_one_authentic_pixel_from_handler;
4946}
4947
4948/*
4949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4950% %
4951% %
4952% %
4953+ S e t P i x e l C a c h e N e x u s P i x e l s %
4954% %
4955% %
4956% %
4957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4958%
4959% SetPixelCacheNexusPixels() defines the region of the cache for the
4960% specified cache nexus.
4961%
4962% The format of the SetPixelCacheNexusPixels() method is:
4963%
cristy4c08aed2011-07-01 19:47:50 +00004964% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004965% const RectangleInfo *region,NexusInfo *nexus_info,
4966% ExceptionInfo *exception)
4967%
4968% A description of each parameter follows:
4969%
4970% o image: the image.
4971%
4972% o region: A pointer to the RectangleInfo structure that defines the
4973% region of this particular cache nexus.
4974%
4975% o nexus_info: the cache nexus to set.
4976%
4977% o exception: return any errors or warnings in this structure.
4978%
4979*/
cristyabd6e372010-09-15 19:11:26 +00004980
4981static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4982 NexusInfo *nexus_info,ExceptionInfo *exception)
4983{
4984 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4985 return(MagickFalse);
4986 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00004987 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004988 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004989 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004990 {
4991 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004992 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004993 nexus_info->length);
4994 }
cristy4c08aed2011-07-01 19:47:50 +00004995 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004996 {
4997 (void) ThrowMagickException(exception,GetMagickModule(),
4998 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4999 cache_info->filename);
5000 return(MagickFalse);
5001 }
5002 return(MagickTrue);
5003}
5004
cristy4c08aed2011-07-01 19:47:50 +00005005static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005006 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5007{
5008 CacheInfo
5009 *cache_info;
5010
5011 MagickBooleanType
5012 status;
5013
cristy3ed852e2009-09-05 21:47:34 +00005014 MagickSizeType
5015 length,
5016 number_pixels;
5017
cristy3ed852e2009-09-05 21:47:34 +00005018 cache_info=(CacheInfo *) image->cache;
5019 assert(cache_info->signature == MagickSignature);
5020 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005021 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005022 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005023 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5024 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005025 {
cristybb503372010-05-27 20:51:26 +00005026 ssize_t
cristybad067a2010-02-15 17:20:55 +00005027 x,
5028 y;
cristy3ed852e2009-09-05 21:47:34 +00005029
cristyeaedf062010-05-29 22:36:02 +00005030 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5031 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005032 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5033 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005034 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005035 ((nexus_info->region.width == cache_info->columns) ||
5036 ((nexus_info->region.width % cache_info->columns) == 0)))))
5037 {
5038 MagickOffsetType
5039 offset;
5040
5041 /*
5042 Pixels are accessed directly from memory.
5043 */
5044 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5045 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005046 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005047 offset;
5048 nexus_info->metacontent=(void *) NULL;
5049 if (cache_info->metacontent_extent != 0)
5050 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5051 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005052 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005053 }
5054 }
5055 /*
5056 Pixels are stored in a cache region until they are synced to the cache.
5057 */
5058 number_pixels=(MagickSizeType) nexus_info->region.width*
5059 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005060 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005061 if (cache_info->metacontent_extent != 0)
5062 length+=number_pixels*cache_info->metacontent_extent;
5063 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005064 {
5065 nexus_info->length=length;
5066 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5067 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005068 {
5069 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005070 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005071 }
cristy3ed852e2009-09-05 21:47:34 +00005072 }
5073 else
5074 if (nexus_info->length != length)
5075 {
5076 RelinquishCacheNexusPixels(nexus_info);
5077 nexus_info->length=length;
5078 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5079 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005080 {
5081 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005082 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005083 }
cristy3ed852e2009-09-05 21:47:34 +00005084 }
5085 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005086 nexus_info->metacontent=(void *) NULL;
5087 if (cache_info->metacontent_extent != 0)
5088 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005089 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005090 return(nexus_info->pixels);
5091}
5092
5093/*
5094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5095% %
5096% %
5097% %
5098% 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 %
5099% %
5100% %
5101% %
5102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103%
5104% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5105% pixel cache and returns the previous setting. A virtual pixel is any pixel
5106% access that is outside the boundaries of the image cache.
5107%
5108% The format of the SetPixelCacheVirtualMethod() method is:
5109%
5110% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5111% const VirtualPixelMethod virtual_pixel_method)
5112%
5113% A description of each parameter follows:
5114%
5115% o image: the image.
5116%
5117% o virtual_pixel_method: choose the type of virtual pixel.
5118%
5119*/
cristyd1dd6e42011-09-04 01:46:08 +00005120MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005121 const VirtualPixelMethod virtual_pixel_method)
5122{
5123 CacheInfo
5124 *cache_info;
5125
5126 VirtualPixelMethod
5127 method;
5128
5129 assert(image != (Image *) NULL);
5130 assert(image->signature == MagickSignature);
5131 if (image->debug != MagickFalse)
5132 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5133 assert(image->cache != (Cache) NULL);
5134 cache_info=(CacheInfo *) image->cache;
5135 assert(cache_info->signature == MagickSignature);
5136 method=cache_info->virtual_pixel_method;
5137 cache_info->virtual_pixel_method=virtual_pixel_method;
5138 return(method);
5139}
5140
5141/*
5142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5143% %
5144% %
5145% %
5146+ 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 %
5147% %
5148% %
5149% %
5150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151%
5152% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5153% in-memory or disk cache. The method returns MagickTrue if the pixel region
5154% is synced, otherwise MagickFalse.
5155%
5156% The format of the SyncAuthenticPixelCacheNexus() method is:
5157%
5158% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5159% NexusInfo *nexus_info,ExceptionInfo *exception)
5160%
5161% A description of each parameter follows:
5162%
5163% o image: the image.
5164%
5165% o nexus_info: the cache nexus to sync.
5166%
5167% o exception: return any errors or warnings in this structure.
5168%
5169*/
cristya6577ff2011-09-02 19:54:26 +00005170MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005171 NexusInfo *nexus_info,ExceptionInfo *exception)
5172{
5173 CacheInfo
5174 *cache_info;
5175
5176 MagickBooleanType
5177 status;
5178
5179 /*
5180 Transfer pixels to the cache.
5181 */
5182 assert(image != (Image *) NULL);
5183 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005184 if (image->cache == (Cache) NULL)
5185 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5186 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005187 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005188 if (cache_info->type == UndefinedCache)
5189 return(MagickFalse);
5190 if ((image->clip_mask != (Image *) NULL) &&
5191 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5192 return(MagickFalse);
5193 if ((image->mask != (Image *) NULL) &&
5194 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5195 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005196 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005197 return(MagickTrue);
5198 assert(cache_info->signature == MagickSignature);
5199 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005200 if ((cache_info->metacontent_extent != 0) &&
5201 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005202 return(MagickFalse);
5203 return(status);
5204}
5205
5206/*
5207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5208% %
5209% %
5210% %
5211+ S y n c A u t h e n t i c P i x e l C a c h e %
5212% %
5213% %
5214% %
5215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5216%
5217% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5218% or disk cache. The method returns MagickTrue if the pixel region is synced,
5219% otherwise MagickFalse.
5220%
5221% The format of the SyncAuthenticPixelsCache() method is:
5222%
5223% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5224% ExceptionInfo *exception)
5225%
5226% A description of each parameter follows:
5227%
5228% o image: the image.
5229%
5230% o exception: return any errors or warnings in this structure.
5231%
5232*/
5233static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5234 ExceptionInfo *exception)
5235{
5236 CacheInfo
5237 *cache_info;
5238
cristy5c9e6f22010-09-17 17:31:01 +00005239 const int
5240 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005241
cristy4c08aed2011-07-01 19:47:50 +00005242 MagickBooleanType
5243 status;
5244
cristye7cc7cf2010-09-21 13:26:47 +00005245 assert(image != (Image *) NULL);
5246 assert(image->signature == MagickSignature);
5247 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005248 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005249 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005250 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005251 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5252 exception);
5253 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005254}
5255
5256/*
5257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258% %
5259% %
5260% %
5261% S y n c A u t h e n t i c P i x e l s %
5262% %
5263% %
5264% %
5265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266%
5267% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5268% The method returns MagickTrue if the pixel region is flushed, otherwise
5269% MagickFalse.
5270%
5271% The format of the SyncAuthenticPixels() method is:
5272%
5273% MagickBooleanType SyncAuthenticPixels(Image *image,
5274% ExceptionInfo *exception)
5275%
5276% A description of each parameter follows:
5277%
5278% o image: the image.
5279%
5280% o exception: return any errors or warnings in this structure.
5281%
5282*/
5283MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5284 ExceptionInfo *exception)
5285{
5286 CacheInfo
5287 *cache_info;
5288
cristy2036f5c2010-09-19 21:18:17 +00005289 const int
5290 id = GetOpenMPThreadId();
5291
cristy4c08aed2011-07-01 19:47:50 +00005292 MagickBooleanType
5293 status;
5294
cristy3ed852e2009-09-05 21:47:34 +00005295 assert(image != (Image *) NULL);
5296 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005297 assert(image->cache != (Cache) NULL);
5298 cache_info=(CacheInfo *) image->cache;
5299 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005300 if (cache_info->methods.sync_authentic_pixels_handler !=
5301 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005302 {
5303 status=cache_info->methods.sync_authentic_pixels_handler(image,
5304 exception);
5305 return(status);
5306 }
cristy2036f5c2010-09-19 21:18:17 +00005307 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005308 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5309 exception);
5310 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005311}
5312
5313/*
5314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315% %
5316% %
5317% %
cristyd1dd6e42011-09-04 01:46:08 +00005318+ 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 +00005319% %
5320% %
5321% %
5322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5323%
5324% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5325% The method returns MagickTrue if the pixel region is flushed, otherwise
5326% MagickFalse.
5327%
5328% The format of the SyncImagePixelCache() method is:
5329%
5330% MagickBooleanType SyncImagePixelCache(Image *image,
5331% ExceptionInfo *exception)
5332%
5333% A description of each parameter follows:
5334%
5335% o image: the image.
5336%
5337% o exception: return any errors or warnings in this structure.
5338%
5339*/
cristyd1dd6e42011-09-04 01:46:08 +00005340MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005341 ExceptionInfo *exception)
5342{
5343 CacheInfo
5344 *cache_info;
5345
5346 assert(image != (Image *) NULL);
5347 assert(exception != (ExceptionInfo *) NULL);
5348 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5349 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5350}
5351
5352/*
5353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5354% %
5355% %
5356% %
cristy4c08aed2011-07-01 19:47:50 +00005357+ 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 +00005358% %
5359% %
5360% %
5361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5362%
cristy4c08aed2011-07-01 19:47:50 +00005363% WritePixelCacheMetacontent() writes the meta-content to the specified region
5364% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005365%
cristy4c08aed2011-07-01 19:47:50 +00005366% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005367%
cristy4c08aed2011-07-01 19:47:50 +00005368% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005369% NexusInfo *nexus_info,ExceptionInfo *exception)
5370%
5371% A description of each parameter follows:
5372%
5373% o cache_info: the pixel cache.
5374%
cristy4c08aed2011-07-01 19:47:50 +00005375% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005376%
5377% o exception: return any errors or warnings in this structure.
5378%
5379*/
cristy4c08aed2011-07-01 19:47:50 +00005380static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005381 NexusInfo *nexus_info,ExceptionInfo *exception)
5382{
5383 MagickOffsetType
5384 count,
5385 offset;
5386
5387 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005388 extent,
5389 length;
cristy3ed852e2009-09-05 21:47:34 +00005390
cristy4c08aed2011-07-01 19:47:50 +00005391 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005392 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005393
cristybb503372010-05-27 20:51:26 +00005394 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005395 y;
5396
cristybb503372010-05-27 20:51:26 +00005397 size_t
cristy3ed852e2009-09-05 21:47:34 +00005398 rows;
5399
cristy4c08aed2011-07-01 19:47:50 +00005400 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005401 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005402 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005403 return(MagickTrue);
5404 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5405 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005406 length=(MagickSizeType) nexus_info->region.width*
5407 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005408 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005409 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005410 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005411 switch (cache_info->type)
5412 {
5413 case MemoryCache:
5414 case MapCache:
5415 {
cristy4c08aed2011-07-01 19:47:50 +00005416 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005417 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005418
5419 /*
cristy4c08aed2011-07-01 19:47:50 +00005420 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005421 */
cristydd341db2010-03-04 19:06:38 +00005422 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005423 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005424 {
cristy48078b12010-09-23 17:11:01 +00005425 length=extent;
cristydd341db2010-03-04 19:06:38 +00005426 rows=1UL;
5427 }
cristy4c08aed2011-07-01 19:47:50 +00005428 q=(unsigned char *) cache_info->metacontent+offset*
5429 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005430 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005431 {
cristy8f036fe2010-09-18 02:02:00 +00005432 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005433 p+=nexus_info->region.width*cache_info->metacontent_extent;
5434 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005435 }
5436 break;
5437 }
5438 case DiskCache:
5439 {
5440 /*
cristy4c08aed2011-07-01 19:47:50 +00005441 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005442 */
5443 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5444 {
5445 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5446 cache_info->cache_filename);
5447 return(MagickFalse);
5448 }
cristydd341db2010-03-04 19:06:38 +00005449 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005450 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005451 {
cristy48078b12010-09-23 17:11:01 +00005452 length=extent;
cristydd341db2010-03-04 19:06:38 +00005453 rows=1UL;
5454 }
cristy48078b12010-09-23 17:11:01 +00005455 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005456 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005457 {
cristy48078b12010-09-23 17:11:01 +00005458 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005459 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005460 cache_info->metacontent_extent,length,(const unsigned char *) p);
5461 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005462 break;
cristy4c08aed2011-07-01 19:47:50 +00005463 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005464 offset+=cache_info->columns;
5465 }
cristybb503372010-05-27 20:51:26 +00005466 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005467 {
5468 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5469 cache_info->cache_filename);
5470 return(MagickFalse);
5471 }
5472 break;
5473 }
5474 default:
5475 break;
5476 }
5477 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005478 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005479 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005480 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005481 nexus_info->region.width,(double) nexus_info->region.height,(double)
5482 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005483 return(MagickTrue);
5484}
5485
5486/*
5487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5488% %
5489% %
5490% %
5491+ W r i t e C a c h e P i x e l s %
5492% %
5493% %
5494% %
5495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5496%
5497% WritePixelCachePixels() writes image pixels to the specified region of the
5498% pixel cache.
5499%
5500% The format of the WritePixelCachePixels() method is:
5501%
5502% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5503% NexusInfo *nexus_info,ExceptionInfo *exception)
5504%
5505% A description of each parameter follows:
5506%
5507% o cache_info: the pixel cache.
5508%
5509% o nexus_info: the cache nexus to write the pixels.
5510%
5511% o exception: return any errors or warnings in this structure.
5512%
5513*/
5514static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5515 NexusInfo *nexus_info,ExceptionInfo *exception)
5516{
5517 MagickOffsetType
5518 count,
5519 offset;
5520
5521 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005522 extent,
5523 length;
cristy3ed852e2009-09-05 21:47:34 +00005524
cristy4c08aed2011-07-01 19:47:50 +00005525 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005526 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005527
cristybb503372010-05-27 20:51:26 +00005528 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005529 y;
5530
cristybb503372010-05-27 20:51:26 +00005531 size_t
cristy3ed852e2009-09-05 21:47:34 +00005532 rows;
5533
cristy4c08aed2011-07-01 19:47:50 +00005534 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005535 return(MagickTrue);
5536 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5537 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005538 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005539 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005540 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005541 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005542 p=nexus_info->pixels;
5543 switch (cache_info->type)
5544 {
5545 case MemoryCache:
5546 case MapCache:
5547 {
cristy4c08aed2011-07-01 19:47:50 +00005548 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005549 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005550
5551 /*
5552 Write pixels to memory.
5553 */
cristydd341db2010-03-04 19:06:38 +00005554 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005555 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005556 {
cristy48078b12010-09-23 17:11:01 +00005557 length=extent;
cristydd341db2010-03-04 19:06:38 +00005558 rows=1UL;
5559 }
cristyed231572011-07-14 02:18:59 +00005560 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005561 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005562 {
cristy8f036fe2010-09-18 02:02:00 +00005563 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005564 p+=nexus_info->region.width*cache_info->number_channels;
5565 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005566 }
5567 break;
5568 }
5569 case DiskCache:
5570 {
5571 /*
5572 Write pixels to disk.
5573 */
5574 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5575 {
5576 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5577 cache_info->cache_filename);
5578 return(MagickFalse);
5579 }
cristydd341db2010-03-04 19:06:38 +00005580 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005581 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005582 {
cristy48078b12010-09-23 17:11:01 +00005583 length=extent;
cristydd341db2010-03-04 19:06:38 +00005584 rows=1UL;
5585 }
cristybb503372010-05-27 20:51:26 +00005586 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005587 {
5588 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005589 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005590 p);
5591 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005592 break;
cristyed231572011-07-14 02:18:59 +00005593 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005594 offset+=cache_info->columns;
5595 }
cristybb503372010-05-27 20:51:26 +00005596 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005597 {
5598 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5599 cache_info->cache_filename);
5600 return(MagickFalse);
5601 }
5602 break;
5603 }
5604 default:
5605 break;
5606 }
5607 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005608 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005609 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005610 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005611 nexus_info->region.width,(double) nexus_info->region.height,(double)
5612 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005613 return(MagickTrue);
5614}