blob: 0b8e0b6125979393ecaf6471aea764151ada1003 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78
79/*
cristy3ed852e2009-09-05 21:47:34 +000080 Typedef declarations.
81*/
82typedef struct _MagickModulo
83{
cristybb503372010-05-27 20:51:26 +000084 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000085 quotient,
86 remainder;
87} MagickModulo;
88
89struct _NexusInfo
90{
91 MagickBooleanType
92 mapped;
93
94 RectangleInfo
95 region;
96
97 MagickSizeType
98 length;
99
cristy4c08aed2011-07-01 19:47:50 +0000100 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000101 *cache,
102 *pixels;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 void
105 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000106
cristybb503372010-05-27 20:51:26 +0000107 size_t
cristy3ed852e2009-09-05 21:47:34 +0000108 signature;
109};
110
111/*
112 Forward declarations.
113*/
114#if defined(__cplusplus) || defined(c_plusplus)
115extern "C" {
116#endif
117
cristy4c08aed2011-07-01 19:47:50 +0000118static const Quantum
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
cristy4c08aed2011-07-01 19:47:50 +0000123static const void
124 *GetVirtualMetacontentFromCache(const Image *);
125
cristy3ed852e2009-09-05 21:47:34 +0000126static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000128 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
137
cristy4c08aed2011-07-01 19:47:50 +0000138static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000144 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146#if defined(__cplusplus) || defined(c_plusplus)
147}
148#endif
149
150/*
151 Global declarations.
152*/
153static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
155
156static SemaphoreInfo
157 *cache_semaphore = (SemaphoreInfo *) NULL;
158
159static SplayTreeInfo
160 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167+ A c q u i r e P i x e l C a c h e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquirePixelCache() acquires a pixel cache.
174%
175% The format of the AcquirePixelCache() method is:
176%
cristybb503372010-05-27 20:51:26 +0000177% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178%
179% A description of each parameter follows:
180%
181% o number_threads: the number of nexus threads.
182%
183*/
cristya6577ff2011-09-02 19:54:26 +0000184MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000185{
186 CacheInfo
187 *cache_info;
188
cristya64b85d2011-09-14 01:02:31 +0000189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000194 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristya6577ff2011-09-02 19:54:26 +0000250MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristya64b85d2011-09-14 01:02:31 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
cristyd1dd6e42011-09-04 01:46:08 +0000301MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
cristy5ff4eaf2011-09-03 01:38:02 +0000339MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
cristy5ff4eaf2011-09-03 01:38:02 +0000363MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000387% mask. It returns MagickTrue if the pixel region is clipped, otherwise
388% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
cristy4c08aed2011-07-01 19:47:50 +0000417 register const Quantum
418 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristy4c08aed2011-07-01 19:47:50 +0000421 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristye076a6e2010-08-15 19:59:43 +0000424 register ssize_t
425 i;
426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
428 Apply clip mask.
429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000434 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000445 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000451 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy4c08aed2011-07-01 19:47:50 +0000453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000454 break;
cristy4c08aed2011-07-01 19:47:50 +0000455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000456 {
cristy4c08aed2011-07-01 19:47:50 +0000457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000463 }
cristyed231572011-07-14 02:18:59 +0000464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000467 }
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000470 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000471 return(MagickFalse);
472 return(MagickTrue);
473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
480+ C l o n e P i x e l C a c h e %
481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
486% ClonePixelCache() clones a pixel cache.
487%
488% The format of the ClonePixelCache() method is:
489%
490% Cache ClonePixelCache(const Cache cache)
491%
492% A description of each parameter follows:
493%
494% o cache: the pixel cache.
495%
496*/
cristya6577ff2011-09-02 19:54:26 +0000497MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000498{
499 CacheInfo
500 *clone_info;
501
502 const CacheInfo
503 *cache_info;
504
cristy9f027d12011-09-21 01:17:17 +0000505 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
516}
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520% %
521% %
522% %
cristy60c44a82009-10-07 00:58:49 +0000523+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000524% %
525% %
526% %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528% ClonePixelCachePixels() clones the source pixel cache to the destination
529% cache.
530%
531% The format of the ClonePixelCachePixels() method is:
532%
533% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534% CacheInfo *source_info,ExceptionInfo *exception)
535%
536% A description of each parameter follows:
537%
538% o cache_info: the pixel cache.
539%
540% o source_info: the source pixel cache.
541%
542% o exception: return any errors or warnings in this structure.
543%
544*/
545
546static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
547{
548 int
549 status;
550
cristy5ee247a2010-02-12 15:42:34 +0000551 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000552 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000553 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000554 {
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
558 }
cristyf84a1932010-01-03 18:00:18 +0000559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000560 return(status == -1 ? MagickFalse : MagickTrue);
561}
562
563static void LimitPixelCacheDescriptors(void)
564{
565 register CacheInfo
566 *p,
567 *q;
568
569 /*
570 Limit # of open file descriptors.
571 */
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
573 return;
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (cache_resources == (SplayTreeInfo *) NULL)
576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return;
579 }
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
583 {
584 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000585 break;
cristy3ed852e2009-09-05 21:47:34 +0000586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 }
588 for (q=p; p != (CacheInfo *) NULL; )
589 {
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000592 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
594 }
595 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000596 {
597 /*
598 Close least recently used cache.
599 */
600 (void) close(q->file);
601 q->file=(-1);
602 }
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604}
605
606static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
608{
609 if (x > y)
610 return(x);
611 return(y);
612}
613
614static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x < y)
618 return(x);
619 return(y);
620}
621
622static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
623 const MapMode mode)
624{
625 int
626 file;
627
628 /*
629 Open pixel cache on disk.
630 */
cristyf84a1932010-01-03 18:00:18 +0000631 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000632 if (cache_info->file != -1)
633 {
cristyf84a1932010-01-03 18:00:18 +0000634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 return(MagickTrue); /* cache already open */
636 }
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
640 else
641 switch (mode)
642 {
643 case ReadMode:
644 {
cristy18c6c272011-09-23 14:40:37 +0000645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 case WriteMode:
649 {
cristy18c6c272011-09-23 14:40:37 +0000650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000652 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case IOMode:
657 default:
658 {
cristy18c6c272011-09-23 14:40:37 +0000659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000660 O_EXCL,S_MODE);
661 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
664 }
665 }
666 if (file == -1)
667 {
cristyf84a1932010-01-03 18:00:18 +0000668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000669 return(MagickFalse);
670 }
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
673 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000674 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000675 return(MagickTrue);
676}
677
678static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
679 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000680 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000681{
682 register MagickOffsetType
683 i;
684
685 ssize_t
686 count;
687
cristy08a88202010-03-04 19:18:05 +0000688 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000689#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000690 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000691 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristyf84a1932010-01-03 18:00:18 +0000693 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 return((MagickOffsetType) -1);
695 }
696#endif
697 count=0;
698 for (i=0; i < (MagickOffsetType) length; i+=count)
699 {
700#if !defined(MAGICKCORE_HAVE_PREAD)
701 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX));
703#else
704 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000705 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000706#endif
707 if (count > 0)
708 continue;
709 count=0;
710 if (errno != EINTR)
711 {
712 i=(-1);
713 break;
714 }
715 }
716#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000717 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000718#endif
719 return(i);
720}
721
722static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
723 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000724 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000725{
726 register MagickOffsetType
727 i;
728
729 ssize_t
730 count;
731
cristy08a88202010-03-04 19:18:05 +0000732 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000733#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000734 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000735 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000736 {
cristyf84a1932010-01-03 18:00:18 +0000737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 return((MagickOffsetType) -1);
739 }
740#endif
741 count=0;
742 for (i=0; i < (MagickOffsetType) length; i+=count)
743 {
744#if !defined(MAGICKCORE_HAVE_PWRITE)
745 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX));
747#else
748 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000749 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000750#endif
751 if (count > 0)
752 continue;
753 count=0;
754 if (errno != EINTR)
755 {
756 i=(-1);
757 break;
758 }
759 }
760#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000761 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000762#endif
763 return(i);
764}
765
cristy4c08aed2011-07-01 19:47:50 +0000766static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000767 CacheInfo *cache_info,ExceptionInfo *exception)
768{
769 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000770 count;
cristy3ed852e2009-09-05 21:47:34 +0000771
cristy4c08aed2011-07-01 19:47:50 +0000772 register MagickOffsetType
773 i;
cristye076a6e2010-08-15 19:59:43 +0000774
cristybb503372010-05-27 20:51:26 +0000775 size_t
cristy4c08aed2011-07-01 19:47:50 +0000776 length;
cristy3ed852e2009-09-05 21:47:34 +0000777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
780
781 /*
782 Clone pixel cache (both caches on disk).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000786 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000787 sizeof(*blob));
788 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000789 {
cristy4c08aed2011-07-01 19:47:50 +0000790 (void) ThrowMagickException(exception,GetMagickModule(),
791 ResourceLimitError,"MemoryAllocationFailed","`%s'",
792 cache_info->filename);
793 return(MagickFalse);
794 }
cristy3dedf062011-07-02 14:07:40 +0000795 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000796 {
797 blob=(unsigned char *) RelinquishMagickMemory(blob);
798 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
799 cache_info->cache_filename);
800 return(MagickFalse);
801 }
cristy3dedf062011-07-02 14:07:40 +0000802 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000803 {
804 (void) ClosePixelCacheOnDisk(cache_info);
805 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000806 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
807 clone_info->cache_filename);
808 return(MagickFalse);
809 }
cristy4c08aed2011-07-01 19:47:50 +0000810 count=0;
811 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
814 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
815 blob);
816 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000817 {
cristy4c08aed2011-07-01 19:47:50 +0000818 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
819 cache_info->cache_filename);
820 break;
cristy3ed852e2009-09-05 21:47:34 +0000821 }
cristy4c08aed2011-07-01 19:47:50 +0000822 length=(size_t) count;
823 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
824 if ((MagickSizeType) count != length)
825 {
826 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
827 clone_info->cache_filename);
828 break;
829 }
830 }
831 (void) ClosePixelCacheOnDisk(clone_info);
832 (void) ClosePixelCacheOnDisk(cache_info);
833 blob=(unsigned char *) RelinquishMagickMemory(blob);
834 if (i < (MagickOffsetType) cache_info->length)
835 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000836 return(MagickTrue);
837}
838
cristy4c08aed2011-07-01 19:47:50 +0000839static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000840 CacheInfo *cache_info,ExceptionInfo *exception)
841{
842 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000843 count;
cristy3ed852e2009-09-05 21:47:34 +0000844
cristy4c08aed2011-07-01 19:47:50 +0000845 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000846 {
cristy3ed852e2009-09-05 21:47:34 +0000847 /*
cristy4c08aed2011-07-01 19:47:50 +0000848 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000849 */
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->debug != MagickFalse)
851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
852 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
853 cache_info->length);
854 return(MagickTrue);
855 }
856 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
857 {
858 /*
859 Clone pixel cache (one cache on disk, one in memory).
860 */
861 if (cache_info->debug != MagickFalse)
862 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
863 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy4c08aed2011-07-01 19:47:50 +0000865 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000866 cache_info->cache_filename);
867 return(MagickFalse);
868 }
cristy4c08aed2011-07-01 19:47:50 +0000869 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
870 cache_info->length,(unsigned char *) clone_info->pixels);
871 (void) ClosePixelCacheOnDisk(cache_info);
872 if ((MagickSizeType) count != cache_info->length)
873 {
874 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
875 cache_info->cache_filename);
876 return(MagickFalse);
877 }
878 return(MagickTrue);
879 }
880 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
881 {
882 /*
883 Clone pixel cache (one cache on disk, one in memory).
884 */
885 if (clone_info->debug != MagickFalse)
886 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
887 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
888 {
889 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
890 clone_info->cache_filename);
891 return(MagickFalse);
892 }
893 count=WritePixelCacheRegion(clone_info,clone_info->offset,
894 clone_info->length,(unsigned char *) cache_info->pixels);
895 (void) ClosePixelCacheOnDisk(clone_info);
896 if ((MagickSizeType) count != clone_info->length)
897 {
898 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
899 clone_info->cache_filename);
900 return(MagickFalse);
901 }
902 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000903 }
904 /*
cristy4c08aed2011-07-01 19:47:50 +0000905 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000906 */
cristy4c08aed2011-07-01 19:47:50 +0000907 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000908}
909
cristy4c08aed2011-07-01 19:47:50 +0000910static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000911 CacheInfo *cache_info,ExceptionInfo *exception)
912{
cristy4c08aed2011-07-01 19:47:50 +0000913 MagickBooleanType
914 status;
cristy3ed852e2009-09-05 21:47:34 +0000915
cristy4c08aed2011-07-01 19:47:50 +0000916 MagickOffsetType
917 cache_offset,
918 clone_offset,
919 count;
920
921 register ssize_t
922 x;
923
924 size_t
cristy3ed852e2009-09-05 21:47:34 +0000925 length;
926
cristy4c08aed2011-07-01 19:47:50 +0000927 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000928 y;
929
cristy4c08aed2011-07-01 19:47:50 +0000930 unsigned char
931 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000932
cristy4c08aed2011-07-01 19:47:50 +0000933 /*
934 Clone pixel cache (unoptimized).
935 */
cristy3ed852e2009-09-05 21:47:34 +0000936 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000937 {
cristy4c08aed2011-07-01 19:47:50 +0000938 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
939 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
940 else
941 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
942 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
943 else
944 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
946 else
947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
948 }
cristyed231572011-07-14 02:18:59 +0000949 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
950 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000951 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000952 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000953 if (blob == (unsigned char *) NULL)
954 {
955 (void) ThrowMagickException(exception,GetMagickModule(),
956 ResourceLimitError,"MemoryAllocationFailed","`%s'",
957 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000958 return(MagickFalse);
959 }
cristy4c08aed2011-07-01 19:47:50 +0000960 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
961 cache_offset=0;
962 clone_offset=0;
963 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000964 {
cristy4c08aed2011-07-01 19:47:50 +0000965 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
cristy4c08aed2011-07-01 19:47:50 +0000967 blob=(unsigned char *) RelinquishMagickMemory(blob);
968 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
cristy4c08aed2011-07-01 19:47:50 +0000972 cache_offset=cache_info->offset;
973 }
974 if (clone_info->type == DiskCache)
975 {
cristy3dedf062011-07-02 14:07:40 +0000976 if ((cache_info->type == DiskCache) &&
977 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
978 {
979 (void) ClosePixelCacheOnDisk(clone_info);
980 *clone_info->cache_filename='\0';
981 }
982 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000983 {
cristy4c08aed2011-07-01 19:47:50 +0000984 if (cache_info->type == DiskCache)
985 (void) ClosePixelCacheOnDisk(cache_info);
986 blob=(unsigned char *) RelinquishMagickMemory(blob);
987 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
988 clone_info->cache_filename);
989 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000990 }
cristy4c08aed2011-07-01 19:47:50 +0000991 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000992 }
993 /*
cristy4c08aed2011-07-01 19:47:50 +0000994 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000995 */
cristy4c08aed2011-07-01 19:47:50 +0000996 status=MagickTrue;
997 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
cristy4c08aed2011-07-01 19:47:50 +0000999 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001000 {
cristy3ed852e2009-09-05 21:47:34 +00001001 /*
cristy4c08aed2011-07-01 19:47:50 +00001002 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001003 */
cristyed231572011-07-14 02:18:59 +00001004 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001005 if (cache_info->type != DiskCache)
1006 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1007 length);
cristy3ed852e2009-09-05 21:47:34 +00001008 else
1009 {
cristy4c08aed2011-07-01 19:47:50 +00001010 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1011 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001012 {
cristy4c08aed2011-07-01 19:47:50 +00001013 status=MagickFalse;
1014 break;
cristy3ed852e2009-09-05 21:47:34 +00001015 }
1016 }
cristy4c08aed2011-07-01 19:47:50 +00001017 cache_offset+=length;
1018 if ((y < (ssize_t) clone_info->rows) &&
1019 (x < (ssize_t) clone_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00001020 {
cristy4c08aed2011-07-01 19:47:50 +00001021 /*
1022 Write a set of pixel channels.
1023 */
cristyed231572011-07-14 02:18:59 +00001024 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001025 if (clone_info->type != DiskCache)
1026 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1027 blob,length);
1028 else
1029 {
cristy208b1002011-08-07 18:51:50 +00001030 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001031 if ((MagickSizeType) count != length)
1032 {
1033 status=MagickFalse;
1034 break;
1035 }
1036 }
1037 clone_offset+=length;
cristy3ed852e2009-09-05 21:47:34 +00001038 }
1039 }
cristyed231572011-07-14 02:18:59 +00001040 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001041 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1042 for ( ; x < (ssize_t) clone_info->columns; x++)
1043 {
1044 /*
1045 Set remaining columns with transparent pixel channels.
1046 */
1047 if (clone_info->type != DiskCache)
1048 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1049 length);
1050 else
1051 {
1052 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1053 if ((MagickSizeType) count != length)
1054 {
1055 status=MagickFalse;
1056 break;
1057 }
1058 }
1059 clone_offset+=length;
1060 }
1061 }
cristyed231572011-07-14 02:18:59 +00001062 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001063 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1064 for ( ; y < (ssize_t) clone_info->rows; y++)
1065 {
1066 /*
1067 Set remaining rows with transparent pixels.
1068 */
1069 for (x=0; x < (ssize_t) clone_info->columns; x++)
1070 {
1071 if (clone_info->type != DiskCache)
1072 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1073 length);
1074 else
1075 {
1076 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1077 if ((MagickSizeType) count != length)
1078 {
1079 status=MagickFalse;
1080 break;
1081 }
1082 }
1083 clone_offset+=length;
1084 }
1085 }
1086 if ((cache_info->metacontent_extent != 0) &&
1087 (clone_info->metacontent_extent != 0))
1088 {
1089 /*
1090 Clone metacontent.
1091 */
1092 for (y=0; y < (ssize_t) cache_info->rows; y++)
1093 {
1094 for (x=0; x < (ssize_t) cache_info->columns; x++)
1095 {
1096 /*
1097 Read a set of metacontent.
1098 */
1099 length=cache_info->metacontent_extent;
1100 if (cache_info->type != DiskCache)
1101 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1102 cache_offset,length);
1103 else
1104 {
1105 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1106 if ((MagickSizeType) count != length)
1107 {
1108 status=MagickFalse;
1109 break;
1110 }
1111 }
1112 cache_offset+=length;
1113 if ((y < (ssize_t) clone_info->rows) &&
1114 (x < (ssize_t) clone_info->columns))
1115 {
1116 /*
1117 Write a set of metacontent.
1118 */
1119 length=clone_info->metacontent_extent;
1120 if (clone_info->type != DiskCache)
1121 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1122 blob,length);
1123 else
1124 {
1125 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1126 blob);
1127 if ((MagickSizeType) count != length)
1128 {
1129 status=MagickFalse;
1130 break;
1131 }
1132 }
1133 clone_offset+=length;
1134 }
1135 }
1136 length=clone_info->metacontent_extent;
1137 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1138 for ( ; x < (ssize_t) clone_info->columns; x++)
1139 {
1140 /*
1141 Set remaining columns with metacontent.
1142 */
1143 if (clone_info->type != DiskCache)
1144 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1145 blob,length);
1146 else
1147 {
cristy208b1002011-08-07 18:51:50 +00001148 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001149 if ((MagickSizeType) count != length)
1150 {
1151 status=MagickFalse;
1152 break;
1153 }
1154 }
1155 clone_offset+=length;
1156 }
1157 }
1158 length=clone_info->metacontent_extent;
1159 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1160 for ( ; y < (ssize_t) clone_info->rows; y++)
1161 {
1162 /*
1163 Set remaining rows with metacontent.
1164 */
1165 for (x=0; x < (ssize_t) clone_info->columns; x++)
1166 {
1167 if (clone_info->type != DiskCache)
1168 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1169 blob,length);
1170 else
1171 {
1172 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1173 if ((MagickSizeType) count != length)
1174 {
1175 status=MagickFalse;
1176 break;
1177 }
1178 }
1179 clone_offset+=length;
1180 }
1181 }
1182 }
1183 if (clone_info->type == DiskCache)
1184 (void) ClosePixelCacheOnDisk(clone_info);
1185 if (cache_info->type == DiskCache)
1186 (void) ClosePixelCacheOnDisk(cache_info);
1187 blob=(unsigned char *) RelinquishMagickMemory(blob);
1188 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001189}
1190
1191static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1192 CacheInfo *cache_info,ExceptionInfo *exception)
1193{
cristy5a7fbfb2010-11-06 16:10:59 +00001194 if (cache_info->type == PingCache)
1195 return(MagickTrue);
cristy4c08aed2011-07-01 19:47:50 +00001196 if ((cache_info->columns == clone_info->columns) &&
1197 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001198 (cache_info->number_channels == clone_info->number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00001199 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1200 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1201 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001202}
1203
1204/*
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206% %
1207% %
1208% %
1209+ C l o n e P i x e l C a c h e M e t h o d s %
1210% %
1211% %
1212% %
1213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214%
1215% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1216% another.
1217%
1218% The format of the ClonePixelCacheMethods() method is:
1219%
1220% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1221%
1222% A description of each parameter follows:
1223%
1224% o clone: Specifies a pointer to a Cache structure.
1225%
1226% o cache: the pixel cache.
1227%
1228*/
cristya6577ff2011-09-02 19:54:26 +00001229MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001230{
1231 CacheInfo
1232 *cache_info,
1233 *source_info;
1234
1235 assert(clone != (Cache) NULL);
1236 source_info=(CacheInfo *) clone;
1237 assert(source_info->signature == MagickSignature);
1238 if (source_info->debug != MagickFalse)
1239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1240 source_info->filename);
1241 assert(cache != (Cache) NULL);
1242 cache_info=(CacheInfo *) cache;
1243 assert(cache_info->signature == MagickSignature);
1244 source_info->methods=cache_info->methods;
1245}
1246
1247/*
1248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249% %
1250% %
1251% %
1252+ D e s t r o y I m a g e P i x e l C a c h e %
1253% %
1254% %
1255% %
1256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257%
1258% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1259%
1260% The format of the DestroyImagePixelCache() method is:
1261%
1262% void DestroyImagePixelCache(Image *image)
1263%
1264% A description of each parameter follows:
1265%
1266% o image: the image.
1267%
1268*/
1269static void DestroyImagePixelCache(Image *image)
1270{
1271 assert(image != (Image *) NULL);
1272 assert(image->signature == MagickSignature);
1273 if (image->debug != MagickFalse)
1274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1275 if (image->cache == (void *) NULL)
1276 return;
1277 image->cache=DestroyPixelCache(image->cache);
1278}
1279
1280/*
1281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282% %
1283% %
1284% %
1285+ D e s t r o y I m a g e P i x e l s %
1286% %
1287% %
1288% %
1289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290%
1291% DestroyImagePixels() deallocates memory associated with the pixel cache.
1292%
1293% The format of the DestroyImagePixels() method is:
1294%
1295% void DestroyImagePixels(Image *image)
1296%
1297% A description of each parameter follows:
1298%
1299% o image: the image.
1300%
1301*/
1302MagickExport void DestroyImagePixels(Image *image)
1303{
1304 CacheInfo
1305 *cache_info;
1306
1307 assert(image != (const Image *) NULL);
1308 assert(image->signature == MagickSignature);
1309 if (image->debug != MagickFalse)
1310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1311 assert(image->cache != (Cache) NULL);
1312 cache_info=(CacheInfo *) image->cache;
1313 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001314 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1315 {
1316 cache_info->methods.destroy_pixel_handler(image);
1317 return;
1318 }
cristy2036f5c2010-09-19 21:18:17 +00001319 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001320}
1321
1322/*
1323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324% %
1325% %
1326% %
1327+ D e s t r o y P i x e l C a c h e %
1328% %
1329% %
1330% %
1331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332%
1333% DestroyPixelCache() deallocates memory associated with the pixel cache.
1334%
1335% The format of the DestroyPixelCache() method is:
1336%
1337% Cache DestroyPixelCache(Cache cache)
1338%
1339% A description of each parameter follows:
1340%
1341% o cache: the pixel cache.
1342%
1343*/
1344
1345static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1346{
1347 switch (cache_info->type)
1348 {
1349 case MemoryCache:
1350 {
1351 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001352 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001353 cache_info->pixels);
1354 else
cristy4c08aed2011-07-01 19:47:50 +00001355 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001356 (size_t) cache_info->length);
1357 RelinquishMagickResource(MemoryResource,cache_info->length);
1358 break;
1359 }
1360 case MapCache:
1361 {
cristy4c08aed2011-07-01 19:47:50 +00001362 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001363 cache_info->length);
1364 RelinquishMagickResource(MapResource,cache_info->length);
1365 }
1366 case DiskCache:
1367 {
1368 if (cache_info->file != -1)
1369 (void) ClosePixelCacheOnDisk(cache_info);
1370 RelinquishMagickResource(DiskResource,cache_info->length);
1371 break;
1372 }
1373 default:
1374 break;
1375 }
1376 cache_info->type=UndefinedCache;
1377 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001378 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001379}
1380
cristya6577ff2011-09-02 19:54:26 +00001381MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001382{
1383 CacheInfo
1384 *cache_info;
1385
cristy3ed852e2009-09-05 21:47:34 +00001386 assert(cache != (Cache) NULL);
1387 cache_info=(CacheInfo *) cache;
1388 assert(cache_info->signature == MagickSignature);
1389 if (cache_info->debug != MagickFalse)
1390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1391 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001392 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001393 cache_info->reference_count--;
1394 if (cache_info->reference_count != 0)
1395 {
cristyf84a1932010-01-03 18:00:18 +00001396 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001397 return((Cache) NULL);
1398 }
cristyf84a1932010-01-03 18:00:18 +00001399 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001400 if (cache_resources != (SplayTreeInfo *) NULL)
1401 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001402 if (cache_info->debug != MagickFalse)
1403 {
1404 char
1405 message[MaxTextExtent];
1406
cristyb51dff52011-05-19 16:55:47 +00001407 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001408 cache_info->filename);
1409 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1410 }
cristyc2e1bdd2009-09-10 23:43:34 +00001411 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1412 (cache_info->type != DiskCache)))
1413 RelinquishPixelCachePixels(cache_info);
1414 else
1415 {
1416 RelinquishPixelCachePixels(cache_info);
1417 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1418 }
cristy3ed852e2009-09-05 21:47:34 +00001419 *cache_info->cache_filename='\0';
1420 if (cache_info->nexus_info != (NexusInfo **) NULL)
1421 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1422 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001423 if (cache_info->random_info != (RandomInfo *) NULL)
1424 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001425 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1426 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1427 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1428 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001429 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001430 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001431 cache=(Cache) NULL;
1432 return(cache);
1433}
1434
1435/*
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437% %
1438% %
1439% %
1440+ D e s t r o y P i x e l C a c h e N e x u s %
1441% %
1442% %
1443% %
1444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445%
1446% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1447%
1448% The format of the DestroyPixelCacheNexus() method is:
1449%
1450% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001451% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001452%
1453% A description of each parameter follows:
1454%
1455% o nexus_info: the nexus to destroy.
1456%
1457% o number_threads: the number of nexus threads.
1458%
1459*/
1460
1461static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1462{
1463 if (nexus_info->mapped == MagickFalse)
1464 (void) RelinquishMagickMemory(nexus_info->cache);
1465 else
1466 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001467 nexus_info->cache=(Quantum *) NULL;
1468 nexus_info->pixels=(Quantum *) NULL;
1469 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001470 nexus_info->length=0;
1471 nexus_info->mapped=MagickFalse;
1472}
1473
cristya6577ff2011-09-02 19:54:26 +00001474MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001475 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001476{
cristybb503372010-05-27 20:51:26 +00001477 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001478 i;
1479
1480 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001481 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001482 {
cristy4c08aed2011-07-01 19:47:50 +00001483 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001484 RelinquishCacheNexusPixels(nexus_info[i]);
1485 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001486 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001487 }
cristyb41ee102010-10-04 16:46:15 +00001488 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001489 return(nexus_info);
1490}
1491
1492/*
1493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494% %
1495% %
1496% %
cristy4c08aed2011-07-01 19:47:50 +00001497% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001498% %
1499% %
1500% %
1501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502%
cristy4c08aed2011-07-01 19:47:50 +00001503% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1504% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1505% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001506%
cristy4c08aed2011-07-01 19:47:50 +00001507% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001508%
cristy4c08aed2011-07-01 19:47:50 +00001509% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001510%
1511% A description of each parameter follows:
1512%
1513% o image: the image.
1514%
1515*/
cristy4c08aed2011-07-01 19:47:50 +00001516MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001517{
1518 CacheInfo
1519 *cache_info;
1520
cristy5c9e6f22010-09-17 17:31:01 +00001521 const int
1522 id = GetOpenMPThreadId();
1523
cristy4c08aed2011-07-01 19:47:50 +00001524 void
1525 *metacontent;
1526
cristye7cc7cf2010-09-21 13:26:47 +00001527 assert(image != (const Image *) NULL);
1528 assert(image->signature == MagickSignature);
1529 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001530 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001531 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001532 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1533 (GetAuthenticMetacontentFromHandler) NULL)
1534 {
1535 metacontent=cache_info->methods.
1536 get_authentic_metacontent_from_handler(image);
1537 return(metacontent);
1538 }
cristy6ebe97c2010-07-03 01:17:28 +00001539 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001540 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1541 cache_info->nexus_info[id]);
1542 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001543}
1544
1545/*
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547% %
1548% %
1549% %
cristy4c08aed2011-07-01 19:47:50 +00001550+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001551% %
1552% %
1553% %
1554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555%
cristy4c08aed2011-07-01 19:47:50 +00001556% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1557% with the last call to QueueAuthenticPixelsCache() or
1558% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001559%
cristy4c08aed2011-07-01 19:47:50 +00001560% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001561%
cristy4c08aed2011-07-01 19:47:50 +00001562% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001563%
1564% A description of each parameter follows:
1565%
1566% o image: the image.
1567%
1568*/
cristy4c08aed2011-07-01 19:47:50 +00001569static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001570{
1571 CacheInfo
1572 *cache_info;
1573
cristy2036f5c2010-09-19 21:18:17 +00001574 const int
1575 id = GetOpenMPThreadId();
1576
cristy4c08aed2011-07-01 19:47:50 +00001577 void
1578 *metacontent;
1579
cristy3ed852e2009-09-05 21:47:34 +00001580 assert(image != (const Image *) NULL);
1581 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001582 assert(image->cache != (Cache) NULL);
1583 cache_info=(CacheInfo *) image->cache;
1584 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001585 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001586 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1587 cache_info->nexus_info[id]);
1588 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001589}
1590
1591/*
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593% %
1594% %
1595% %
1596+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1597% %
1598% %
1599% %
1600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601%
1602% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1603% disk pixel cache as defined by the geometry parameters. A pointer to the
1604% pixels is returned if the pixels are transferred, otherwise a NULL is
1605% returned.
1606%
1607% The format of the GetAuthenticPixelCacheNexus() method is:
1608%
cristy4c08aed2011-07-01 19:47:50 +00001609% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001610% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001611% NexusInfo *nexus_info,ExceptionInfo *exception)
1612%
1613% A description of each parameter follows:
1614%
1615% o image: the image.
1616%
1617% o x,y,columns,rows: These values define the perimeter of a region of
1618% pixels.
1619%
1620% o nexus_info: the cache nexus to return.
1621%
1622% o exception: return any errors or warnings in this structure.
1623%
1624*/
1625
cristy4c08aed2011-07-01 19:47:50 +00001626static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001627 NexusInfo *nexus_info)
1628{
cristy4c08aed2011-07-01 19:47:50 +00001629 MagickBooleanType
1630 status;
1631
cristy3ed852e2009-09-05 21:47:34 +00001632 MagickOffsetType
1633 offset;
1634
cristy73724512010-04-12 14:43:14 +00001635 if (cache_info->type == PingCache)
1636 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001637 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1638 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001639 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001640 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001641 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001642}
1643
cristya6577ff2011-09-02 19:54:26 +00001644MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001645 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001646 NexusInfo *nexus_info,ExceptionInfo *exception)
1647{
1648 CacheInfo
1649 *cache_info;
1650
cristy4c08aed2011-07-01 19:47:50 +00001651 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001652 *q;
cristy3ed852e2009-09-05 21:47:34 +00001653
1654 /*
1655 Transfer pixels from the cache.
1656 */
1657 assert(image != (Image *) NULL);
1658 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001659 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001660 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001661 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001662 cache_info=(CacheInfo *) image->cache;
1663 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001664 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001665 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001666 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001667 return((Quantum *) NULL);
1668 if (cache_info->metacontent_extent != 0)
1669 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1670 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001671 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001672}
1673
1674/*
1675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676% %
1677% %
1678% %
1679+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1680% %
1681% %
1682% %
1683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684%
1685% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1686% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1687%
1688% The format of the GetAuthenticPixelsFromCache() method is:
1689%
cristy4c08aed2011-07-01 19:47:50 +00001690% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001691%
1692% A description of each parameter follows:
1693%
1694% o image: the image.
1695%
1696*/
cristy4c08aed2011-07-01 19:47:50 +00001697static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001698{
1699 CacheInfo
1700 *cache_info;
1701
cristy5c9e6f22010-09-17 17:31:01 +00001702 const int
1703 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001704
cristye7cc7cf2010-09-21 13:26:47 +00001705 assert(image != (const Image *) NULL);
1706 assert(image->signature == MagickSignature);
1707 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001708 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001709 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001710 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001711 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001712}
1713
1714/*
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716% %
1717% %
1718% %
1719% G e t A u t h e n t i c P i x e l Q u e u e %
1720% %
1721% %
1722% %
1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724%
cristy4c08aed2011-07-01 19:47:50 +00001725% GetAuthenticPixelQueue() returns the authentic pixels associated
1726% corresponding with the last call to QueueAuthenticPixels() or
1727% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001728%
1729% The format of the GetAuthenticPixelQueue() method is:
1730%
cristy4c08aed2011-07-01 19:47:50 +00001731% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001732%
1733% A description of each parameter follows:
1734%
1735% o image: the image.
1736%
1737*/
cristy4c08aed2011-07-01 19:47:50 +00001738MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001739{
1740 CacheInfo
1741 *cache_info;
1742
cristy2036f5c2010-09-19 21:18:17 +00001743 const int
1744 id = GetOpenMPThreadId();
1745
cristy3ed852e2009-09-05 21:47:34 +00001746 assert(image != (const Image *) NULL);
1747 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001748 assert(image->cache != (Cache) NULL);
1749 cache_info=(CacheInfo *) image->cache;
1750 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001751 if (cache_info->methods.get_authentic_pixels_from_handler !=
1752 (GetAuthenticPixelsFromHandler) NULL)
1753 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001754 assert(id < (int) cache_info->number_threads);
1755 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001756}
1757
1758/*
1759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760% %
1761% %
1762% %
1763% G e t A u t h e n t i c P i x e l s %
1764% %
1765% %
cristy4c08aed2011-07-01 19:47:50 +00001766% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001767%
1768% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001769% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001770% representing the region is returned, otherwise NULL is returned.
1771%
1772% The returned pointer may point to a temporary working copy of the pixels
1773% or it may point to the original pixels in memory. Performance is maximized
1774% if the selected region is part of one row, or one or more full rows, since
1775% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001776% if the image is in memory, or in a memory-mapped file. The returned pointer
1777% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001778%
1779% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001780% Quantum. If the image has corresponding metacontent,call
1781% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1782% meta-content corresponding to the region. Once the Quantum array has
1783% been updated, the changes must be saved back to the underlying image using
1784% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001785%
1786% The format of the GetAuthenticPixels() method is:
1787%
cristy4c08aed2011-07-01 19:47:50 +00001788% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001789% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001790% ExceptionInfo *exception)
1791%
1792% A description of each parameter follows:
1793%
1794% o image: the image.
1795%
1796% o x,y,columns,rows: These values define the perimeter of a region of
1797% pixels.
1798%
1799% o exception: return any errors or warnings in this structure.
1800%
1801*/
cristy4c08aed2011-07-01 19:47:50 +00001802MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001803 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001804 ExceptionInfo *exception)
1805{
1806 CacheInfo
1807 *cache_info;
1808
cristy2036f5c2010-09-19 21:18:17 +00001809 const int
1810 id = GetOpenMPThreadId();
1811
cristy4c08aed2011-07-01 19:47:50 +00001812 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001813 *q;
cristy4c08aed2011-07-01 19:47:50 +00001814
cristy3ed852e2009-09-05 21:47:34 +00001815 assert(image != (Image *) NULL);
1816 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001817 assert(image->cache != (Cache) NULL);
1818 cache_info=(CacheInfo *) image->cache;
1819 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001820 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001821 (GetAuthenticPixelsHandler) NULL)
1822 {
cristyacd2ed22011-08-30 01:44:23 +00001823 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1824 exception);
1825 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001826 }
cristy2036f5c2010-09-19 21:18:17 +00001827 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001828 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001829 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001830 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001831}
1832
1833/*
1834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835% %
1836% %
1837% %
1838+ G e t A u t h e n t i c P i x e l s C a c h e %
1839% %
1840% %
1841% %
1842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1843%
1844% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1845% as defined by the geometry parameters. A pointer to the pixels is returned
1846% if the pixels are transferred, otherwise a NULL is returned.
1847%
1848% The format of the GetAuthenticPixelsCache() method is:
1849%
cristy4c08aed2011-07-01 19:47:50 +00001850% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001851% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001852% ExceptionInfo *exception)
1853%
1854% A description of each parameter follows:
1855%
1856% o image: the image.
1857%
1858% o x,y,columns,rows: These values define the perimeter of a region of
1859% pixels.
1860%
1861% o exception: return any errors or warnings in this structure.
1862%
1863*/
cristy4c08aed2011-07-01 19:47:50 +00001864static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001865 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001866 ExceptionInfo *exception)
1867{
1868 CacheInfo
1869 *cache_info;
1870
cristy5c9e6f22010-09-17 17:31:01 +00001871 const int
1872 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001873
cristy4c08aed2011-07-01 19:47:50 +00001874 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001875 *q;
cristy4c08aed2011-07-01 19:47:50 +00001876
cristye7cc7cf2010-09-21 13:26:47 +00001877 assert(image != (const Image *) NULL);
1878 assert(image->signature == MagickSignature);
1879 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001880 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001881 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001882 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001883 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001884 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001885 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001886 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001887 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001888}
1889
1890/*
1891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892% %
1893% %
1894% %
1895+ G e t I m a g e E x t e n t %
1896% %
1897% %
1898% %
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900%
cristy4c08aed2011-07-01 19:47:50 +00001901% GetImageExtent() returns the extent of the pixels associated corresponding
1902% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001903%
1904% The format of the GetImageExtent() method is:
1905%
1906% MagickSizeType GetImageExtent(const Image *image)
1907%
1908% A description of each parameter follows:
1909%
1910% o image: the image.
1911%
1912*/
1913MagickExport MagickSizeType GetImageExtent(const Image *image)
1914{
1915 CacheInfo
1916 *cache_info;
1917
cristy5c9e6f22010-09-17 17:31:01 +00001918 const int
1919 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001920
cristy3ed852e2009-09-05 21:47:34 +00001921 assert(image != (Image *) NULL);
1922 assert(image->signature == MagickSignature);
1923 if (image->debug != MagickFalse)
1924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1925 assert(image->cache != (Cache) NULL);
1926 cache_info=(CacheInfo *) image->cache;
1927 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001928 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001929 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001930}
1931
1932/*
1933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1934% %
1935% %
1936% %
1937+ G e t I m a g e P i x e l C a c h e %
1938% %
1939% %
1940% %
1941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942%
1943% GetImagePixelCache() ensures that there is only a single reference to the
1944% pixel cache to be modified, updating the provided cache pointer to point to
1945% a clone of the original pixel cache if necessary.
1946%
1947% The format of the GetImagePixelCache method is:
1948%
1949% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1950% ExceptionInfo *exception)
1951%
1952% A description of each parameter follows:
1953%
1954% o image: the image.
1955%
1956% o clone: any value other than MagickFalse clones the cache pixels.
1957%
1958% o exception: return any errors or warnings in this structure.
1959%
1960*/
cristyaf894d72011-08-06 23:03:10 +00001961
cristy3ed852e2009-09-05 21:47:34 +00001962static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1963{
1964 CacheInfo
1965 *cache_info;
1966
1967 /*
1968 Does the image match the pixel cache morphology?
1969 */
1970 cache_info=(CacheInfo *) image->cache;
1971 if ((image->storage_class != cache_info->storage_class) ||
1972 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001973 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00001974 (image->columns != cache_info->columns) ||
1975 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001976 (image->number_channels != cache_info->number_channels) ||
cristy4c08aed2011-07-01 19:47:50 +00001977 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001978 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1979 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1980 return(MagickFalse);
1981 return(MagickTrue);
1982}
1983
cristycd01fae2011-08-06 23:52:42 +00001984static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1985 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001986{
1987 CacheInfo
1988 *cache_info;
1989
cristy3ed852e2009-09-05 21:47:34 +00001990 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001991 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001992 status;
1993
cristy50a10922010-02-15 18:35:25 +00001994 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001995 cpu_throttle = 0,
1996 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001997 time_limit = 0;
1998
cristy1ea34962010-07-01 19:49:21 +00001999 static time_t
cristy208b1002011-08-07 18:51:50 +00002000 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002001
cristyc4f9f132010-03-04 18:50:01 +00002002 status=MagickTrue;
2003 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002004 if (cpu_throttle == 0)
2005 {
2006 char
2007 *limit;
2008
2009 /*
2010 Set CPU throttle in milleseconds.
2011 */
2012 cpu_throttle=MagickResourceInfinity;
2013 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2014 if (limit == (char *) NULL)
2015 limit=GetPolicyValue("throttle");
2016 if (limit != (char *) NULL)
2017 {
2018 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2019 limit=DestroyString(limit);
2020 }
2021 }
2022 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2023 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002024 if (time_limit == 0)
2025 {
cristy6ebe97c2010-07-03 01:17:28 +00002026 /*
2027 Set the exire time in seconds.
2028 */
cristy1ea34962010-07-01 19:49:21 +00002029 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002030 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002031 }
2032 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002033 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002034 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002035 assert(image->cache != (Cache) NULL);
2036 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002037 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002038 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002039 {
cristyceb55ee2010-11-06 16:05:49 +00002040 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002041 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002042 {
cristyceb55ee2010-11-06 16:05:49 +00002043 Image
2044 clone_image;
2045
2046 CacheInfo
2047 *clone_info;
2048
2049 /*
2050 Clone pixel cache.
2051 */
2052 clone_image=(*image);
2053 clone_image.semaphore=AllocateSemaphoreInfo();
2054 clone_image.reference_count=1;
2055 clone_image.cache=ClonePixelCache(cache_info);
2056 clone_info=(CacheInfo *) clone_image.cache;
2057 status=OpenPixelCache(&clone_image,IOMode,exception);
2058 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002059 {
cristy5a7fbfb2010-11-06 16:10:59 +00002060 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002061 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002062 if (status != MagickFalse)
2063 {
cristy979bf772011-08-08 00:04:15 +00002064 if (cache_info->mode == ReadMode)
2065 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002066 destroy=MagickTrue;
2067 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002068 }
2069 }
cristyceb55ee2010-11-06 16:05:49 +00002070 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002071 }
cristyceb55ee2010-11-06 16:05:49 +00002072 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002073 }
cristy4320e0e2009-09-10 15:00:08 +00002074 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002075 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002076 if (status != MagickFalse)
2077 {
2078 /*
2079 Ensure the image matches the pixel cache morphology.
2080 */
2081 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002082 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002083 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2084 status=OpenPixelCache(image,IOMode,exception);
2085 }
cristyf84a1932010-01-03 18:00:18 +00002086 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002087 if (status == MagickFalse)
2088 return((Cache) NULL);
2089 return(image->cache);
2090}
2091
2092/*
2093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094% %
2095% %
2096% %
2097% G e t O n e A u t h e n t i c P i x e l %
2098% %
2099% %
2100% %
2101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102%
2103% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2104% location. The image background color is returned if an error occurs.
2105%
2106% The format of the GetOneAuthenticPixel() method is:
2107%
cristybb503372010-05-27 20:51:26 +00002108% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002109% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002110%
2111% A description of each parameter follows:
2112%
2113% o image: the image.
2114%
2115% o x,y: These values define the location of the pixel to return.
2116%
2117% o pixel: return a pixel at the specified (x,y) location.
2118%
2119% o exception: return any errors or warnings in this structure.
2120%
2121*/
cristyacbbb7c2010-06-30 18:56:48 +00002122MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002123 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002124{
2125 CacheInfo
2126 *cache_info;
2127
cristy4c08aed2011-07-01 19:47:50 +00002128 register Quantum
2129 *q;
cristy2036f5c2010-09-19 21:18:17 +00002130
cristy2ed42f62011-10-02 19:49:57 +00002131 register ssize_t
2132 i;
2133
cristy3ed852e2009-09-05 21:47:34 +00002134 assert(image != (Image *) NULL);
2135 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002136 assert(image->cache != (Cache) NULL);
2137 cache_info=(CacheInfo *) image->cache;
2138 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002139 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002140 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2141 (GetOneAuthenticPixelFromHandler) NULL)
2142 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2143 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002144 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2145 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002146 {
2147 pixel[RedPixelChannel]=image->background_color.red;
2148 pixel[GreenPixelChannel]=image->background_color.green;
2149 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002150 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002151 pixel[AlphaPixelChannel]=image->background_color.alpha;
2152 return(MagickFalse);
2153 }
2154 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2155 {
2156 PixelChannel
2157 channel;
2158
2159 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2160 pixel[channel]=q[i];
2161 }
cristy2036f5c2010-09-19 21:18:17 +00002162 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002163}
2164
2165/*
2166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167% %
2168% %
2169% %
2170+ G e t O n e A u t h e n t i c P i x e l F r o m C a c h e %
2171% %
2172% %
2173% %
2174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2175%
2176% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2177% location. The image background color is returned if an error occurs.
2178%
2179% The format of the GetOneAuthenticPixelFromCache() method is:
2180%
2181% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002182% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002183% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002184%
2185% A description of each parameter follows:
2186%
2187% o image: the image.
2188%
2189% o x,y: These values define the location of the pixel to return.
2190%
2191% o pixel: return a pixel at the specified (x,y) location.
2192%
2193% o exception: return any errors or warnings in this structure.
2194%
2195*/
2196static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002197 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002198{
cristy098f78c2010-09-23 17:28:44 +00002199 CacheInfo
2200 *cache_info;
2201
2202 const int
2203 id = GetOpenMPThreadId();
2204
cristy4c08aed2011-07-01 19:47:50 +00002205 register Quantum
2206 *q;
cristy3ed852e2009-09-05 21:47:34 +00002207
cristy2ed42f62011-10-02 19:49:57 +00002208 register ssize_t
2209 i;
2210
cristy0158a4b2010-09-20 13:59:45 +00002211 assert(image != (const Image *) NULL);
2212 assert(image->signature == MagickSignature);
2213 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002214 cache_info=(CacheInfo *) image->cache;
2215 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002216 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002217 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002218 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2219 exception);
2220 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002221 {
2222 pixel[RedPixelChannel]=image->background_color.red;
2223 pixel[GreenPixelChannel]=image->background_color.green;
2224 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002225 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002226 pixel[AlphaPixelChannel]=image->background_color.alpha;
2227 return(MagickFalse);
2228 }
2229 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2230 {
2231 PixelChannel
2232 channel;
2233
2234 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2235 pixel[channel]=q[i];
2236 }
cristy3ed852e2009-09-05 21:47:34 +00002237 return(MagickTrue);
2238}
2239
2240/*
2241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242% %
2243% %
2244% %
2245% G e t O n e V i r t u a l M a g i c k P i x e l %
2246% %
2247% %
2248% %
2249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250%
2251% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2252% location. The image background color is returned if an error occurs. If
2253% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2254%
2255% The format of the GetOneVirtualMagickPixel() method is:
2256%
2257% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristy52010022011-10-21 18:07:37 +00002258% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2259% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002260%
2261% A description of each parameter follows:
2262%
2263% o image: the image.
2264%
cristy52010022011-10-21 18:07:37 +00002265% o virtual_pixel_method: the virtual pixel method.
2266%
cristy3ed852e2009-09-05 21:47:34 +00002267% o x,y: these values define the location of the pixel to return.
2268%
2269% o pixel: return a pixel at the specified (x,y) location.
2270%
2271% o exception: return any errors or warnings in this structure.
2272%
2273*/
2274MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristy52010022011-10-21 18:07:37 +00002275 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2276 PixelInfo *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002277{
2278 CacheInfo
2279 *cache_info;
2280
cristy0158a4b2010-09-20 13:59:45 +00002281 const int
2282 id = GetOpenMPThreadId();
2283
cristy4c08aed2011-07-01 19:47:50 +00002284 register const Quantum
cristyacd2ed22011-08-30 01:44:23 +00002285 *p;
cristy3ed852e2009-09-05 21:47:34 +00002286
2287 assert(image != (const Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 assert(image->cache != (Cache) NULL);
2290 cache_info=(CacheInfo *) image->cache;
2291 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002292 assert(id < (int) cache_info->number_threads);
cristy52010022011-10-21 18:07:37 +00002293 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2294 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002295 GetPixelInfo(image,pixel);
cristyacd2ed22011-08-30 01:44:23 +00002296 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002297 return(MagickFalse);
cristyacd2ed22011-08-30 01:44:23 +00002298 SetPixelInfo(image,p,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002299 return(MagickTrue);
2300}
2301
2302/*
2303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2304% %
2305% %
2306% %
2307% G e t O n e V i r t u a l M e t h o d P i x e l %
2308% %
2309% %
2310% %
2311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312%
2313% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2314% location as defined by specified pixel method. The image background color
2315% is returned if an error occurs. If you plan to modify the pixel, use
2316% GetOneAuthenticPixel() instead.
2317%
2318% The format of the GetOneVirtualMethodPixel() method is:
2319%
2320% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002321% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002322% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002323%
2324% A description of each parameter follows:
2325%
2326% o image: the image.
2327%
2328% o virtual_pixel_method: the virtual pixel method.
2329%
2330% o x,y: These values define the location of the pixel to return.
2331%
2332% o pixel: return a pixel at the specified (x,y) location.
2333%
2334% o exception: return any errors or warnings in this structure.
2335%
2336*/
2337MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002338 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002339 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002340{
cristy3ed852e2009-09-05 21:47:34 +00002341 CacheInfo
2342 *cache_info;
2343
cristy0158a4b2010-09-20 13:59:45 +00002344 const int
2345 id = GetOpenMPThreadId();
2346
cristy4c08aed2011-07-01 19:47:50 +00002347 const Quantum
2348 *p;
cristy2036f5c2010-09-19 21:18:17 +00002349
cristy2ed42f62011-10-02 19:49:57 +00002350 register ssize_t
2351 i;
2352
cristy3ed852e2009-09-05 21:47:34 +00002353 assert(image != (const Image *) NULL);
2354 assert(image->signature == MagickSignature);
2355 assert(image->cache != (Cache) NULL);
2356 cache_info=(CacheInfo *) image->cache;
2357 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002358 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002359 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2360 (GetOneVirtualPixelFromHandler) NULL)
2361 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2362 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002363 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002365 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002366 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002367 {
2368 pixel[RedPixelChannel]=image->background_color.red;
2369 pixel[GreenPixelChannel]=image->background_color.green;
2370 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002371 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002372 pixel[AlphaPixelChannel]=image->background_color.alpha;
2373 return(MagickFalse);
2374 }
2375 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2376 {
2377 PixelChannel
2378 channel;
2379
2380 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2381 pixel[channel]=p[i];
2382 }
cristy2036f5c2010-09-19 21:18:17 +00002383 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002384}
2385
2386/*
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388% %
2389% %
2390% %
2391% G e t O n e V i r t u a l P i x e l %
2392% %
2393% %
2394% %
2395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2396%
2397% GetOneVirtualPixel() returns a single virtual pixel at the specified
2398% (x,y) location. The image background color is returned if an error occurs.
2399% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2400%
2401% The format of the GetOneVirtualPixel() method is:
2402%
cristybb503372010-05-27 20:51:26 +00002403% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002404% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002405%
2406% A description of each parameter follows:
2407%
2408% o image: the image.
2409%
2410% o x,y: These values define the location of the pixel to return.
2411%
2412% o pixel: return a pixel at the specified (x,y) location.
2413%
2414% o exception: return any errors or warnings in this structure.
2415%
2416*/
2417MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002418 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002419{
cristy3ed852e2009-09-05 21:47:34 +00002420 CacheInfo
2421 *cache_info;
2422
cristy0158a4b2010-09-20 13:59:45 +00002423 const int
2424 id = GetOpenMPThreadId();
2425
cristy4c08aed2011-07-01 19:47:50 +00002426 const Quantum
2427 *p;
cristy2036f5c2010-09-19 21:18:17 +00002428
cristy2ed42f62011-10-02 19:49:57 +00002429 register ssize_t
2430 i;
2431
cristy3ed852e2009-09-05 21:47:34 +00002432 assert(image != (const Image *) NULL);
2433 assert(image->signature == MagickSignature);
2434 assert(image->cache != (Cache) NULL);
2435 cache_info=(CacheInfo *) image->cache;
2436 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002437 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002438 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2439 (GetOneVirtualPixelFromHandler) NULL)
2440 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2441 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002442 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002443 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002444 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002445 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002446 {
2447 pixel[RedPixelChannel]=image->background_color.red;
2448 pixel[GreenPixelChannel]=image->background_color.green;
2449 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002450 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002451 pixel[AlphaPixelChannel]=image->background_color.alpha;
2452 return(MagickFalse);
2453 }
2454 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2455 {
2456 PixelChannel
2457 channel;
2458
2459 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2460 pixel[channel]=p[i];
2461 }
cristy2036f5c2010-09-19 21:18:17 +00002462 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002463}
2464
2465/*
2466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2467% %
2468% %
2469% %
2470+ 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 %
2471% %
2472% %
2473% %
2474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2475%
2476% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2477% specified (x,y) location. The image background color is returned if an
2478% error occurs.
2479%
2480% The format of the GetOneVirtualPixelFromCache() method is:
2481%
2482% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002483% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002484% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002485%
2486% A description of each parameter follows:
2487%
2488% o image: the image.
2489%
2490% o virtual_pixel_method: the virtual pixel method.
2491%
2492% o x,y: These values define the location of the pixel to return.
2493%
2494% o pixel: return a pixel at the specified (x,y) location.
2495%
2496% o exception: return any errors or warnings in this structure.
2497%
2498*/
2499static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002500 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002501 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002502{
cristy0158a4b2010-09-20 13:59:45 +00002503 CacheInfo
2504 *cache_info;
2505
2506 const int
2507 id = GetOpenMPThreadId();
2508
cristy4c08aed2011-07-01 19:47:50 +00002509 const Quantum
2510 *p;
cristy3ed852e2009-09-05 21:47:34 +00002511
cristy2ed42f62011-10-02 19:49:57 +00002512 register ssize_t
2513 i;
2514
cristye7cc7cf2010-09-21 13:26:47 +00002515 assert(image != (const Image *) NULL);
2516 assert(image->signature == MagickSignature);
2517 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002518 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002519 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002520 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002521 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002522 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002523 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002524 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002525 {
2526 pixel[RedPixelChannel]=image->background_color.red;
2527 pixel[GreenPixelChannel]=image->background_color.green;
2528 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002529 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002530 pixel[AlphaPixelChannel]=image->background_color.alpha;
2531 return(MagickFalse);
2532 }
2533 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2534 {
2535 PixelChannel
2536 channel;
2537
2538 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2539 pixel[channel]=p[i];
2540 }
cristy3ed852e2009-09-05 21:47:34 +00002541 return(MagickTrue);
2542}
2543
2544/*
2545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2546% %
2547% %
2548% %
2549+ G e t P i x e l C a c h e C o l o r s p a c e %
2550% %
2551% %
2552% %
2553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2554%
2555% GetPixelCacheColorspace() returns the class type of the pixel cache.
2556%
2557% The format of the GetPixelCacheColorspace() method is:
2558%
2559% Colorspace GetPixelCacheColorspace(Cache cache)
2560%
2561% A description of each parameter follows:
2562%
2563% o cache: the pixel cache.
2564%
2565*/
cristya6577ff2011-09-02 19:54:26 +00002566MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002567{
2568 CacheInfo
2569 *cache_info;
2570
2571 assert(cache != (Cache) NULL);
2572 cache_info=(CacheInfo *) cache;
2573 assert(cache_info->signature == MagickSignature);
2574 if (cache_info->debug != MagickFalse)
2575 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2576 cache_info->filename);
2577 return(cache_info->colorspace);
2578}
2579
2580/*
2581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2582% %
2583% %
2584% %
2585+ G e t P i x e l C a c h e M e t h o d s %
2586% %
2587% %
2588% %
2589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2590%
2591% GetPixelCacheMethods() initializes the CacheMethods structure.
2592%
2593% The format of the GetPixelCacheMethods() method is:
2594%
2595% void GetPixelCacheMethods(CacheMethods *cache_methods)
2596%
2597% A description of each parameter follows:
2598%
2599% o cache_methods: Specifies a pointer to a CacheMethods structure.
2600%
2601*/
cristya6577ff2011-09-02 19:54:26 +00002602MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002603{
2604 assert(cache_methods != (CacheMethods *) NULL);
2605 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2606 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2607 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002608 cache_methods->get_virtual_metacontent_from_handler=
2609 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002610 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2611 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002612 cache_methods->get_authentic_metacontent_from_handler=
2613 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002614 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2615 cache_methods->get_one_authentic_pixel_from_handler=
2616 GetOneAuthenticPixelFromCache;
2617 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2618 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2619 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2620}
2621
2622/*
2623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2624% %
2625% %
2626% %
2627+ G e t P i x e l C a c h e N e x u s E x t e n t %
2628% %
2629% %
2630% %
2631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632%
cristy4c08aed2011-07-01 19:47:50 +00002633% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2634% corresponding with the last call to SetPixelCacheNexusPixels() or
2635% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002636%
2637% The format of the GetPixelCacheNexusExtent() method is:
2638%
2639% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2640% NexusInfo *nexus_info)
2641%
2642% A description of each parameter follows:
2643%
2644% o nexus_info: the nexus info.
2645%
2646*/
cristya6577ff2011-09-02 19:54:26 +00002647MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002648 NexusInfo *nexus_info)
2649{
2650 CacheInfo
2651 *cache_info;
2652
2653 MagickSizeType
2654 extent;
2655
cristy9f027d12011-09-21 01:17:17 +00002656 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002657 cache_info=(CacheInfo *) cache;
2658 assert(cache_info->signature == MagickSignature);
2659 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2660 if (extent == 0)
2661 return((MagickSizeType) cache_info->columns*cache_info->rows);
2662 return(extent);
2663}
2664
2665/*
2666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2667% %
2668% %
2669% %
cristy4c08aed2011-07-01 19:47:50 +00002670+ 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 +00002671% %
2672% %
2673% %
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675%
cristy4c08aed2011-07-01 19:47:50 +00002676% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2677% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002678%
cristy4c08aed2011-07-01 19:47:50 +00002679% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002680%
cristy4c08aed2011-07-01 19:47:50 +00002681% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002682% NexusInfo *nexus_info)
2683%
2684% A description of each parameter follows:
2685%
2686% o cache: the pixel cache.
2687%
cristy4c08aed2011-07-01 19:47:50 +00002688% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002689%
2690*/
cristya6577ff2011-09-02 19:54:26 +00002691MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002692 NexusInfo *nexus_info)
2693{
2694 CacheInfo
2695 *cache_info;
2696
cristy9f027d12011-09-21 01:17:17 +00002697 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002698 cache_info=(CacheInfo *) cache;
2699 assert(cache_info->signature == MagickSignature);
2700 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002701 return((void *) NULL);
2702 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002703}
2704
2705/*
2706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2707% %
2708% %
2709% %
2710+ G e t P i x e l C a c h e N e x u s P i x e l s %
2711% %
2712% %
2713% %
2714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2715%
2716% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2717% cache nexus.
2718%
2719% The format of the GetPixelCacheNexusPixels() method is:
2720%
cristy4c08aed2011-07-01 19:47:50 +00002721% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002722% NexusInfo *nexus_info)
2723%
2724% A description of each parameter follows:
2725%
2726% o cache: the pixel cache.
2727%
2728% o nexus_info: the cache nexus to return the pixels.
2729%
2730*/
cristya6577ff2011-09-02 19:54:26 +00002731MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002732 NexusInfo *nexus_info)
2733{
2734 CacheInfo
2735 *cache_info;
2736
cristy9f027d12011-09-21 01:17:17 +00002737 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002738 cache_info=(CacheInfo *) cache;
2739 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002740 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002741 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002742 return(nexus_info->pixels);
2743}
2744
2745/*
2746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2747% %
2748% %
2749% %
cristy056ba772010-01-02 23:33:54 +00002750+ G e t P i x e l C a c h e P i x e l s %
2751% %
2752% %
2753% %
2754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2755%
2756% GetPixelCachePixels() returns the pixels associated with the specified image.
2757%
2758% The format of the GetPixelCachePixels() method is:
2759%
cristyf84a1932010-01-03 18:00:18 +00002760% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2761% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002762%
2763% A description of each parameter follows:
2764%
2765% o image: the image.
2766%
2767% o length: the pixel cache length.
2768%
cristyf84a1932010-01-03 18:00:18 +00002769% o exception: return any errors or warnings in this structure.
2770%
cristy056ba772010-01-02 23:33:54 +00002771*/
cristyd1dd6e42011-09-04 01:46:08 +00002772MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002773 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002774{
2775 CacheInfo
2776 *cache_info;
2777
2778 assert(image != (const Image *) NULL);
2779 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002780 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002781 assert(length != (MagickSizeType *) NULL);
2782 assert(exception != (ExceptionInfo *) NULL);
2783 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002784 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002785 assert(cache_info->signature == MagickSignature);
2786 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002787 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002788 return((void *) NULL);
2789 *length=cache_info->length;
2790 return((void *) cache_info->pixels);
2791}
2792
2793/*
2794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2795% %
2796% %
2797% %
cristyb32b90a2009-09-07 21:45:48 +00002798+ 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 +00002799% %
2800% %
2801% %
2802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2803%
2804% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2805%
2806% The format of the GetPixelCacheStorageClass() method is:
2807%
2808% ClassType GetPixelCacheStorageClass(Cache cache)
2809%
2810% A description of each parameter follows:
2811%
2812% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2813%
2814% o cache: the pixel cache.
2815%
2816*/
cristya6577ff2011-09-02 19:54:26 +00002817MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002818{
2819 CacheInfo
2820 *cache_info;
2821
2822 assert(cache != (Cache) NULL);
2823 cache_info=(CacheInfo *) cache;
2824 assert(cache_info->signature == MagickSignature);
2825 if (cache_info->debug != MagickFalse)
2826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2827 cache_info->filename);
2828 return(cache_info->storage_class);
2829}
2830
2831/*
2832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2833% %
2834% %
2835% %
cristyb32b90a2009-09-07 21:45:48 +00002836+ G e t P i x e l C a c h e T i l e S i z e %
2837% %
2838% %
2839% %
2840%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2841%
2842% GetPixelCacheTileSize() returns the pixel cache tile size.
2843%
2844% The format of the GetPixelCacheTileSize() method is:
2845%
cristybb503372010-05-27 20:51:26 +00002846% void GetPixelCacheTileSize(const Image *image,size_t *width,
2847% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002848%
2849% A description of each parameter follows:
2850%
2851% o image: the image.
2852%
2853% o width: the optimize cache tile width in pixels.
2854%
2855% o height: the optimize cache tile height in pixels.
2856%
2857*/
cristya6577ff2011-09-02 19:54:26 +00002858MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002859 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002860{
cristy4c08aed2011-07-01 19:47:50 +00002861 CacheInfo
2862 *cache_info;
2863
cristyb32b90a2009-09-07 21:45:48 +00002864 assert(image != (Image *) NULL);
2865 assert(image->signature == MagickSignature);
2866 if (image->debug != MagickFalse)
2867 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002868 cache_info=(CacheInfo *) image->cache;
2869 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002870 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002871 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002872 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002873 *height=(*width);
2874}
2875
2876/*
2877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878% %
2879% %
2880% %
2881+ G e t P i x e l C a c h e T y p e %
2882% %
2883% %
2884% %
2885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886%
2887% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2888%
2889% The format of the GetPixelCacheType() method is:
2890%
2891% CacheType GetPixelCacheType(const Image *image)
2892%
2893% A description of each parameter follows:
2894%
2895% o image: the image.
2896%
2897*/
cristya6577ff2011-09-02 19:54:26 +00002898MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002899{
2900 CacheInfo
2901 *cache_info;
2902
2903 assert(image != (Image *) NULL);
2904 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002905 assert(image->cache != (Cache) NULL);
2906 cache_info=(CacheInfo *) image->cache;
2907 assert(cache_info->signature == MagickSignature);
2908 return(cache_info->type);
2909}
2910
2911/*
2912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913% %
2914% %
2915% %
cristy3ed852e2009-09-05 21:47:34 +00002916+ 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 %
2917% %
2918% %
2919% %
2920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2921%
2922% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2923% pixel cache. A virtual pixel is any pixel access that is outside the
2924% boundaries of the image cache.
2925%
2926% The format of the GetPixelCacheVirtualMethod() method is:
2927%
2928% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2929%
2930% A description of each parameter follows:
2931%
2932% o image: the image.
2933%
2934*/
cristyd1dd6e42011-09-04 01:46:08 +00002935MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002936{
2937 CacheInfo
2938 *cache_info;
2939
2940 assert(image != (Image *) NULL);
2941 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002942 assert(image->cache != (Cache) NULL);
2943 cache_info=(CacheInfo *) image->cache;
2944 assert(cache_info->signature == MagickSignature);
2945 return(cache_info->virtual_pixel_method);
2946}
2947
2948/*
2949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2950% %
2951% %
2952% %
cristy4c08aed2011-07-01 19:47:50 +00002953+ 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 +00002954% %
2955% %
2956% %
2957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2958%
cristy4c08aed2011-07-01 19:47:50 +00002959% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2960% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002961%
cristy4c08aed2011-07-01 19:47:50 +00002962% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002963%
cristy4c08aed2011-07-01 19:47:50 +00002964% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002965%
2966% A description of each parameter follows:
2967%
2968% o image: the image.
2969%
2970*/
cristy4c08aed2011-07-01 19:47:50 +00002971static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002972{
2973 CacheInfo
2974 *cache_info;
2975
cristy5c9e6f22010-09-17 17:31:01 +00002976 const int
2977 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002978
cristy4c08aed2011-07-01 19:47:50 +00002979 const void
2980 *metacontent;
2981
cristye7cc7cf2010-09-21 13:26:47 +00002982 assert(image != (const Image *) NULL);
2983 assert(image->signature == MagickSignature);
2984 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002985 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002986 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002987 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002988 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2989 cache_info->nexus_info[id]);
2990 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002991}
2992
2993/*
2994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2995% %
2996% %
2997% %
cristy4c08aed2011-07-01 19:47:50 +00002998+ 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 +00002999% %
3000% %
3001% %
3002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3003%
cristy4c08aed2011-07-01 19:47:50 +00003004% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
3005% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00003006%
cristy4c08aed2011-07-01 19:47:50 +00003007% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00003008%
cristy4c08aed2011-07-01 19:47:50 +00003009% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003010% NexusInfo *nexus_info)
3011%
3012% A description of each parameter follows:
3013%
3014% o cache: the pixel cache.
3015%
cristy4c08aed2011-07-01 19:47:50 +00003016% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00003017%
3018*/
cristya6577ff2011-09-02 19:54:26 +00003019MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00003020 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00003021{
3022 CacheInfo
3023 *cache_info;
3024
cristye7cc7cf2010-09-21 13:26:47 +00003025 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003026 cache_info=(CacheInfo *) cache;
3027 assert(cache_info->signature == MagickSignature);
3028 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003029 return((void *) NULL);
3030 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003031}
3032
3033/*
3034%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3035% %
3036% %
3037% %
cristy4c08aed2011-07-01 19:47:50 +00003038% 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 +00003039% %
3040% %
3041% %
3042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3043%
cristy4c08aed2011-07-01 19:47:50 +00003044% GetVirtualMetacontent() returns the virtual metacontent corresponding with
3045% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3046% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003047%
cristy4c08aed2011-07-01 19:47:50 +00003048% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003049%
cristy4c08aed2011-07-01 19:47:50 +00003050% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003051%
3052% A description of each parameter follows:
3053%
3054% o image: the image.
3055%
3056*/
cristy4c08aed2011-07-01 19:47:50 +00003057MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003058{
3059 CacheInfo
3060 *cache_info;
3061
cristy2036f5c2010-09-19 21:18:17 +00003062 const int
3063 id = GetOpenMPThreadId();
3064
cristy4c08aed2011-07-01 19:47:50 +00003065 const void
3066 *metacontent;
3067
cristy3ed852e2009-09-05 21:47:34 +00003068 assert(image != (const Image *) NULL);
3069 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003070 assert(image->cache != (Cache) NULL);
3071 cache_info=(CacheInfo *) image->cache;
3072 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003073 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3074 (GetVirtualMetacontentFromHandler) NULL)
3075 {
3076 metacontent=cache_info->methods.
3077 get_virtual_metacontent_from_handler(image);
3078 return(metacontent);
3079 }
cristy2036f5c2010-09-19 21:18:17 +00003080 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003081 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3082 cache_info->nexus_info[id]);
3083 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003084}
3085
3086/*
3087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3088% %
3089% %
3090% %
3091+ 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 %
3092% %
3093% %
3094% %
3095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3096%
3097% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3098% pixel cache as defined by the geometry parameters. A pointer to the pixels
3099% is returned if the pixels are transferred, otherwise a NULL is returned.
3100%
3101% The format of the GetVirtualPixelsFromNexus() method is:
3102%
cristy4c08aed2011-07-01 19:47:50 +00003103% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003104% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003105% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3106% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003107%
3108% A description of each parameter follows:
3109%
3110% o image: the image.
3111%
3112% o virtual_pixel_method: the virtual pixel method.
3113%
3114% o x,y,columns,rows: These values define the perimeter of a region of
3115% pixels.
3116%
3117% o nexus_info: the cache nexus to acquire.
3118%
3119% o exception: return any errors or warnings in this structure.
3120%
3121*/
3122
cristybb503372010-05-27 20:51:26 +00003123static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003124 DitherMatrix[64] =
3125 {
3126 0, 48, 12, 60, 3, 51, 15, 63,
3127 32, 16, 44, 28, 35, 19, 47, 31,
3128 8, 56, 4, 52, 11, 59, 7, 55,
3129 40, 24, 36, 20, 43, 27, 39, 23,
3130 2, 50, 14, 62, 1, 49, 13, 61,
3131 34, 18, 46, 30, 33, 17, 45, 29,
3132 10, 58, 6, 54, 9, 57, 5, 53,
3133 42, 26, 38, 22, 41, 25, 37, 21
3134 };
3135
cristybb503372010-05-27 20:51:26 +00003136static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003137{
cristybb503372010-05-27 20:51:26 +00003138 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003139 index;
3140
3141 index=x+DitherMatrix[x & 0x07]-32L;
3142 if (index < 0L)
3143 return(0L);
cristybb503372010-05-27 20:51:26 +00003144 if (index >= (ssize_t) columns)
3145 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003146 return(index);
3147}
3148
cristybb503372010-05-27 20:51:26 +00003149static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003150{
cristybb503372010-05-27 20:51:26 +00003151 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003152 index;
3153
3154 index=y+DitherMatrix[y & 0x07]-32L;
3155 if (index < 0L)
3156 return(0L);
cristybb503372010-05-27 20:51:26 +00003157 if (index >= (ssize_t) rows)
3158 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003159 return(index);
3160}
3161
cristybb503372010-05-27 20:51:26 +00003162static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003163{
3164 if (x < 0L)
3165 return(0L);
cristybb503372010-05-27 20:51:26 +00003166 if (x >= (ssize_t) columns)
3167 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003168 return(x);
3169}
3170
cristybb503372010-05-27 20:51:26 +00003171static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003172{
3173 if (y < 0L)
3174 return(0L);
cristybb503372010-05-27 20:51:26 +00003175 if (y >= (ssize_t) rows)
3176 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003177 return(y);
3178}
3179
cristybb503372010-05-27 20:51:26 +00003180static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003181{
cristybb503372010-05-27 20:51:26 +00003182 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003183}
3184
cristybb503372010-05-27 20:51:26 +00003185static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003186{
cristybb503372010-05-27 20:51:26 +00003187 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003188}
3189
cristybb503372010-05-27 20:51:26 +00003190static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3191 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003192{
3193 MagickModulo
3194 modulo;
3195
cristy6162bb42011-07-18 11:34:09 +00003196 /*
3197 Compute the remainder of dividing offset by extent. It returns not only
3198 the quotient (tile the offset falls in) but also the positive remainer
3199 within that tile such that 0 <= remainder < extent. This method is
3200 essentially a ldiv() using a floored modulo division rather than the
3201 normal default truncated modulo division.
3202 */
cristybb503372010-05-27 20:51:26 +00003203 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003204 if (offset < 0L)
3205 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003206 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003207 return(modulo);
3208}
3209
cristya6577ff2011-09-02 19:54:26 +00003210MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003211 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3212 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003213 ExceptionInfo *exception)
3214{
3215 CacheInfo
3216 *cache_info;
3217
3218 MagickOffsetType
3219 offset;
3220
3221 MagickSizeType
3222 length,
3223 number_pixels;
3224
3225 NexusInfo
3226 **virtual_nexus;
3227
cristy4c08aed2011-07-01 19:47:50 +00003228 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003229 *pixels,
cristy105ba3c2011-07-18 02:28:38 +00003230 virtual_pixel[MaxPixelChannels];
cristy3ed852e2009-09-05 21:47:34 +00003231
3232 RectangleInfo
3233 region;
3234
cristy4c08aed2011-07-01 19:47:50 +00003235 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003236 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003237
cristy4c08aed2011-07-01 19:47:50 +00003238 register const void
3239 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003240
cristy4c08aed2011-07-01 19:47:50 +00003241 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003242 *restrict q;
3243
cristybb503372010-05-27 20:51:26 +00003244 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003245 i,
3246 u;
cristy3ed852e2009-09-05 21:47:34 +00003247
cristy4c08aed2011-07-01 19:47:50 +00003248 register unsigned char
3249 *restrict s;
3250
cristy105ba3c2011-07-18 02:28:38 +00003251 ssize_t
3252 v;
3253
cristy4c08aed2011-07-01 19:47:50 +00003254 void
cristy105ba3c2011-07-18 02:28:38 +00003255 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003256
cristy3ed852e2009-09-05 21:47:34 +00003257 /*
3258 Acquire pixels.
3259 */
cristye7cc7cf2010-09-21 13:26:47 +00003260 assert(image != (const Image *) NULL);
3261 assert(image->signature == MagickSignature);
3262 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003263 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003264 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003265 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003266 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003267 region.x=x;
3268 region.y=y;
3269 region.width=columns;
3270 region.height=rows;
3271 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003272 if (pixels == (Quantum *) NULL)
3273 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003274 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003275 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3276 nexus_info->region.x;
3277 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3278 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003279 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3280 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003281 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3282 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003283 {
3284 MagickBooleanType
3285 status;
3286
3287 /*
3288 Pixel request is inside cache extents.
3289 */
cristy4c08aed2011-07-01 19:47:50 +00003290 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003291 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003292 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3293 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003294 return((const Quantum *) NULL);
3295 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003296 {
cristy4c08aed2011-07-01 19:47:50 +00003297 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003298 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003299 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003300 }
cristyacd2ed22011-08-30 01:44:23 +00003301 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003302 }
3303 /*
3304 Pixel request is outside cache extents.
3305 */
cristy4c08aed2011-07-01 19:47:50 +00003306 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003307 virtual_nexus=AcquirePixelCacheNexus(1);
3308 if (virtual_nexus == (NexusInfo **) NULL)
3309 {
cristy4c08aed2011-07-01 19:47:50 +00003310 if (virtual_nexus != (NexusInfo **) NULL)
3311 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003312 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3313 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003314 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003315 }
cristy105ba3c2011-07-18 02:28:38 +00003316 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3317 sizeof(*virtual_pixel));
3318 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003319 switch (virtual_pixel_method)
3320 {
cristy4c08aed2011-07-01 19:47:50 +00003321 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003322 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003323 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003324 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003325 case MaskVirtualPixelMethod:
3326 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003327 case EdgeVirtualPixelMethod:
3328 case CheckerTileVirtualPixelMethod:
3329 case HorizontalTileVirtualPixelMethod:
3330 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003331 {
cristy4c08aed2011-07-01 19:47:50 +00003332 if (cache_info->metacontent_extent != 0)
3333 {
cristy6162bb42011-07-18 11:34:09 +00003334 /*
3335 Acquire a metacontent buffer.
3336 */
cristya64b85d2011-09-14 01:02:31 +00003337 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003338 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003339 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003340 {
cristy4c08aed2011-07-01 19:47:50 +00003341 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3342 (void) ThrowMagickException(exception,GetMagickModule(),
3343 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3344 return((const Quantum *) NULL);
3345 }
cristy105ba3c2011-07-18 02:28:38 +00003346 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003347 cache_info->metacontent_extent);
3348 }
3349 switch (virtual_pixel_method)
3350 {
3351 case BlackVirtualPixelMethod:
3352 {
cristy30301712011-07-18 15:06:51 +00003353 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3354 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003355 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3356 break;
3357 }
3358 case GrayVirtualPixelMethod:
3359 {
cristy30301712011-07-18 15:06:51 +00003360 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003361 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3362 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003363 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3364 break;
3365 }
3366 case TransparentVirtualPixelMethod:
3367 {
cristy30301712011-07-18 15:06:51 +00003368 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3369 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003370 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3371 break;
3372 }
3373 case MaskVirtualPixelMethod:
3374 case WhiteVirtualPixelMethod:
3375 {
cristy30301712011-07-18 15:06:51 +00003376 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3377 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003378 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3379 break;
3380 }
3381 default:
3382 {
3383 SetPixelRed(image,image->background_color.red,virtual_pixel);
3384 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3385 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003386 if (image->colorspace == CMYKColorspace)
3387 SetPixelBlack(image,image->background_color.black,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003388 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3389 break;
3390 }
3391 }
cristy3ed852e2009-09-05 21:47:34 +00003392 break;
3393 }
3394 default:
cristy3ed852e2009-09-05 21:47:34 +00003395 break;
cristy3ed852e2009-09-05 21:47:34 +00003396 }
cristybb503372010-05-27 20:51:26 +00003397 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003398 {
cristybb503372010-05-27 20:51:26 +00003399 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003400 {
3401 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003402 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003403 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3404 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003405 {
3406 MagickModulo
3407 x_modulo,
3408 y_modulo;
3409
3410 /*
3411 Transfer a single pixel.
3412 */
3413 length=(MagickSizeType) 1;
3414 switch (virtual_pixel_method)
3415 {
cristy3ed852e2009-09-05 21:47:34 +00003416 default:
3417 {
3418 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003419 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003420 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003421 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003422 break;
3423 }
3424 case RandomVirtualPixelMethod:
3425 {
3426 if (cache_info->random_info == (RandomInfo *) NULL)
3427 cache_info->random_info=AcquireRandomInfo();
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003429 RandomX(cache_info->random_info,cache_info->columns),
3430 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003431 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003432 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003433 break;
3434 }
3435 case DitherVirtualPixelMethod:
3436 {
3437 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003438 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003439 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003440 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003441 break;
3442 }
3443 case TileVirtualPixelMethod:
3444 {
3445 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3446 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3447 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003448 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003449 exception);
cristy4c08aed2011-07-01 19:47:50 +00003450 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003451 break;
3452 }
3453 case MirrorVirtualPixelMethod:
3454 {
3455 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3456 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003457 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003458 x_modulo.remainder-1L;
3459 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3460 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003461 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003462 y_modulo.remainder-1L;
3463 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003464 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003465 exception);
cristy4c08aed2011-07-01 19:47:50 +00003466 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003467 break;
3468 }
3469 case HorizontalTileEdgeVirtualPixelMethod:
3470 {
3471 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3472 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003473 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003474 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003475 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003476 break;
3477 }
3478 case VerticalTileEdgeVirtualPixelMethod:
3479 {
3480 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3481 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003482 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003483 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003484 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3485 break;
3486 }
3487 case BackgroundVirtualPixelMethod:
3488 case BlackVirtualPixelMethod:
3489 case GrayVirtualPixelMethod:
3490 case TransparentVirtualPixelMethod:
3491 case MaskVirtualPixelMethod:
3492 case WhiteVirtualPixelMethod:
3493 {
3494 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003495 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003496 break;
3497 }
3498 case EdgeVirtualPixelMethod:
3499 case CheckerTileVirtualPixelMethod:
3500 {
3501 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3502 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3503 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3504 {
3505 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003506 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003507 break;
3508 }
3509 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3510 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3511 exception);
3512 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3513 break;
3514 }
3515 case HorizontalTileVirtualPixelMethod:
3516 {
3517 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3518 {
3519 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003520 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003521 break;
3522 }
3523 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3524 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3525 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3526 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3527 exception);
3528 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3529 break;
3530 }
3531 case VerticalTileVirtualPixelMethod:
3532 {
3533 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3534 {
3535 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003536 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003537 break;
3538 }
3539 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3540 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3541 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3542 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3543 exception);
3544 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003545 break;
3546 }
3547 }
cristy4c08aed2011-07-01 19:47:50 +00003548 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003549 break;
cristyed231572011-07-14 02:18:59 +00003550 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003551 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003552 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003553 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003554 {
3555 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3556 s+=cache_info->metacontent_extent;
3557 }
cristy3ed852e2009-09-05 21:47:34 +00003558 continue;
3559 }
3560 /*
3561 Transfer a run of pixels.
3562 */
cristy4c08aed2011-07-01 19:47:50 +00003563 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3564 length,1UL,*virtual_nexus,exception);
3565 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003566 break;
cristy4c08aed2011-07-01 19:47:50 +00003567 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003568 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3569 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003570 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003571 {
cristy4c08aed2011-07-01 19:47:50 +00003572 (void) memcpy(s,r,(size_t) length);
3573 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003574 }
3575 }
3576 }
cristy4c08aed2011-07-01 19:47:50 +00003577 /*
3578 Free resources.
3579 */
cristy105ba3c2011-07-18 02:28:38 +00003580 if (virtual_metacontent != (void *) NULL)
3581 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003582 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3583 return(pixels);
3584}
3585
3586/*
3587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3588% %
3589% %
3590% %
3591+ G e t V i r t u a l P i x e l C a c h e %
3592% %
3593% %
3594% %
3595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596%
3597% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3598% cache as defined by the geometry parameters. A pointer to the pixels
3599% is returned if the pixels are transferred, otherwise a NULL is returned.
3600%
3601% The format of the GetVirtualPixelCache() method is:
3602%
cristy4c08aed2011-07-01 19:47:50 +00003603% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003604% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3605% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003606% ExceptionInfo *exception)
3607%
3608% A description of each parameter follows:
3609%
3610% o image: the image.
3611%
3612% o virtual_pixel_method: the virtual pixel method.
3613%
3614% o x,y,columns,rows: These values define the perimeter of a region of
3615% pixels.
3616%
3617% o exception: return any errors or warnings in this structure.
3618%
3619*/
cristy4c08aed2011-07-01 19:47:50 +00003620static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003621 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3622 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003623{
3624 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003625 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003626
cristy5c9e6f22010-09-17 17:31:01 +00003627 const int
3628 id = GetOpenMPThreadId();
3629
cristy4c08aed2011-07-01 19:47:50 +00003630 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003631 *p;
cristy4c08aed2011-07-01 19:47:50 +00003632
cristye7cc7cf2010-09-21 13:26:47 +00003633 assert(image != (const Image *) NULL);
3634 assert(image->signature == MagickSignature);
3635 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003636 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003637 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003638 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003639 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003640 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003641 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
3649% G e t V i r t u a l P i x e l Q u e u e %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
cristy4c08aed2011-07-01 19:47:50 +00003655% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3656% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003657%
3658% The format of the GetVirtualPixelQueue() method is:
3659%
cristy4c08aed2011-07-01 19:47:50 +00003660% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003661%
3662% A description of each parameter follows:
3663%
3664% o image: the image.
3665%
3666*/
cristy4c08aed2011-07-01 19:47:50 +00003667MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003668{
3669 CacheInfo
3670 *cache_info;
3671
cristy2036f5c2010-09-19 21:18:17 +00003672 const int
3673 id = GetOpenMPThreadId();
3674
cristy3ed852e2009-09-05 21:47:34 +00003675 assert(image != (const Image *) NULL);
3676 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003677 assert(image->cache != (Cache) NULL);
3678 cache_info=(CacheInfo *) image->cache;
3679 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003680 if (cache_info->methods.get_virtual_pixels_handler !=
3681 (GetVirtualPixelsHandler) NULL)
3682 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003683 assert(id < (int) cache_info->number_threads);
3684 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003685}
3686
3687/*
3688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3689% %
3690% %
3691% %
3692% G e t V i r t u a l P i x e l s %
3693% %
3694% %
3695% %
3696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3697%
3698% GetVirtualPixels() returns an immutable pixel region. If the
3699% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003700% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003701% copy of the pixels or it may point to the original pixels in memory.
3702% Performance is maximized if the selected region is part of one row, or one
3703% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003704% (without a copy) if the image is in memory, or in a memory-mapped file. The
3705% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003706%
3707% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003708% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3709% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3710% access the meta-content (of type void) corresponding to the the
3711% region.
cristy3ed852e2009-09-05 21:47:34 +00003712%
3713% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3714%
3715% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3716% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3717% GetCacheViewAuthenticPixels() instead.
3718%
3719% The format of the GetVirtualPixels() method is:
3720%
cristy4c08aed2011-07-01 19:47:50 +00003721% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003722% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003723% ExceptionInfo *exception)
3724%
3725% A description of each parameter follows:
3726%
3727% o image: the image.
3728%
3729% o x,y,columns,rows: These values define the perimeter of a region of
3730% pixels.
3731%
3732% o exception: return any errors or warnings in this structure.
3733%
3734*/
cristy4c08aed2011-07-01 19:47:50 +00003735MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003736 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3737 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003738{
3739 CacheInfo
3740 *cache_info;
3741
cristy2036f5c2010-09-19 21:18:17 +00003742 const int
3743 id = GetOpenMPThreadId();
3744
cristy4c08aed2011-07-01 19:47:50 +00003745 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003746 *p;
cristy4c08aed2011-07-01 19:47:50 +00003747
cristy3ed852e2009-09-05 21:47:34 +00003748 assert(image != (const Image *) NULL);
3749 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003750 assert(image->cache != (Cache) NULL);
3751 cache_info=(CacheInfo *) image->cache;
3752 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003753 if (cache_info->methods.get_virtual_pixel_handler !=
3754 (GetVirtualPixelHandler) NULL)
3755 return(cache_info->methods.get_virtual_pixel_handler(image,
3756 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003757 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003758 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003759 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003760 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003761}
3762
3763/*
3764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765% %
3766% %
3767% %
3768+ 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 %
3769% %
3770% %
3771% %
3772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3773%
cristy4c08aed2011-07-01 19:47:50 +00003774% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3775% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003776%
3777% The format of the GetVirtualPixelsCache() method is:
3778%
cristy4c08aed2011-07-01 19:47:50 +00003779% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003780%
3781% A description of each parameter follows:
3782%
3783% o image: the image.
3784%
3785*/
cristy4c08aed2011-07-01 19:47:50 +00003786static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003787{
3788 CacheInfo
3789 *cache_info;
3790
cristy5c9e6f22010-09-17 17:31:01 +00003791 const int
3792 id = GetOpenMPThreadId();
3793
cristye7cc7cf2010-09-21 13:26:47 +00003794 assert(image != (const Image *) NULL);
3795 assert(image->signature == MagickSignature);
3796 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003797 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003798 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003799 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003800 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003801}
3802
3803/*
3804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3805% %
3806% %
3807% %
3808+ G e t V i r t u a l P i x e l s N e x u s %
3809% %
3810% %
3811% %
3812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3813%
3814% GetVirtualPixelsNexus() returns the pixels associated with the specified
3815% cache nexus.
3816%
3817% The format of the GetVirtualPixelsNexus() method is:
3818%
cristy4c08aed2011-07-01 19:47:50 +00003819% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003820% NexusInfo *nexus_info)
3821%
3822% A description of each parameter follows:
3823%
3824% o cache: the pixel cache.
3825%
3826% o nexus_info: the cache nexus to return the colormap pixels.
3827%
3828*/
cristya6577ff2011-09-02 19:54:26 +00003829MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003830 NexusInfo *nexus_info)
3831{
3832 CacheInfo
3833 *cache_info;
3834
cristye7cc7cf2010-09-21 13:26:47 +00003835 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003836 cache_info=(CacheInfo *) cache;
3837 assert(cache_info->signature == MagickSignature);
3838 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003839 return((Quantum *) NULL);
3840 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003841}
3842
3843/*
3844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3845% %
3846% %
3847% %
3848+ M a s k P i x e l C a c h e N e x u s %
3849% %
3850% %
3851% %
3852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3853%
3854% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3855% The method returns MagickTrue if the pixel region is masked, otherwise
3856% MagickFalse.
3857%
3858% The format of the MaskPixelCacheNexus() method is:
3859%
3860% MagickBooleanType MaskPixelCacheNexus(Image *image,
3861% NexusInfo *nexus_info,ExceptionInfo *exception)
3862%
3863% A description of each parameter follows:
3864%
3865% o image: the image.
3866%
3867% o nexus_info: the cache nexus to clip.
3868%
3869% o exception: return any errors or warnings in this structure.
3870%
3871*/
3872
cristy4c08aed2011-07-01 19:47:50 +00003873static inline void MagickPixelCompositeMask(const PixelInfo *p,
3874 const MagickRealType alpha,const PixelInfo *q,
3875 const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003876{
3877 MagickRealType
3878 gamma;
3879
cristyaa83c2c2011-09-21 13:36:25 +00003880 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003881 {
3882 *composite=(*q);
3883 return;
3884 }
3885 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3886 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003887 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3888 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3889 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003890 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003891 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003892}
3893
3894static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3895 ExceptionInfo *exception)
3896{
3897 CacheInfo
3898 *cache_info;
3899
cristy4c08aed2011-07-01 19:47:50 +00003900 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003901 alpha,
3902 beta;
3903
3904 MagickSizeType
3905 number_pixels;
3906
3907 NexusInfo
3908 **clip_nexus,
3909 **image_nexus;
3910
cristy4c08aed2011-07-01 19:47:50 +00003911 register const Quantum
3912 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003913 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003914
cristy4c08aed2011-07-01 19:47:50 +00003915 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003916 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003917
cristye076a6e2010-08-15 19:59:43 +00003918 register ssize_t
3919 i;
3920
cristy3ed852e2009-09-05 21:47:34 +00003921 /*
3922 Apply clip mask.
3923 */
3924 if (image->debug != MagickFalse)
3925 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3926 if (image->mask == (Image *) NULL)
3927 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003928 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003929 if (cache_info == (Cache) NULL)
3930 return(MagickFalse);
3931 image_nexus=AcquirePixelCacheNexus(1);
3932 clip_nexus=AcquirePixelCacheNexus(1);
3933 if ((image_nexus == (NexusInfo **) NULL) ||
3934 (clip_nexus == (NexusInfo **) NULL))
3935 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003936 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3937 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3938 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003939 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003940 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3941 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003942 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003943 GetPixelInfo(image,&alpha);
3944 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003945 number_pixels=(MagickSizeType) nexus_info->region.width*
3946 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003947 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003948 {
cristy4c08aed2011-07-01 19:47:50 +00003949 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003950 break;
cristy4c08aed2011-07-01 19:47:50 +00003951 SetPixelInfo(image,p,&alpha);
3952 SetPixelInfo(image,q,&beta);
3953 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3954 &alpha,alpha.alpha,&beta);
3955 SetPixelRed(image,ClampToQuantum(beta.red),q);
3956 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3957 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3958 if (cache_info->colorspace == CMYKColorspace)
3959 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3960 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003961 p++;
3962 q++;
3963 r++;
3964 }
3965 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3966 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003967 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003968 return(MagickFalse);
3969 return(MagickTrue);
3970}
3971
3972/*
3973%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3974% %
3975% %
3976% %
3977+ O p e n P i x e l C a c h e %
3978% %
3979% %
3980% %
3981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3982%
3983% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3984% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003985% metacontent, and memory mapping the cache if it is disk based. The cache
3986% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003987%
3988% The format of the OpenPixelCache() method is:
3989%
3990% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3991% ExceptionInfo *exception)
3992%
3993% A description of each parameter follows:
3994%
3995% o image: the image.
3996%
3997% o mode: ReadMode, WriteMode, or IOMode.
3998%
3999% o exception: return any errors or warnings in this structure.
4000%
4001*/
4002
cristyd43a46b2010-01-21 02:13:41 +00004003static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004004{
4005 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00004006 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00004007 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004008 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004009 {
4010 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004011 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00004012 cache_info->length);
4013 }
4014}
4015
4016static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4017{
4018 CacheInfo
4019 *cache_info;
4020
4021 MagickOffsetType
4022 count,
4023 extent,
4024 offset;
4025
4026 cache_info=(CacheInfo *) image->cache;
4027 if (image->debug != MagickFalse)
4028 {
4029 char
4030 format[MaxTextExtent],
4031 message[MaxTextExtent];
4032
cristyb9080c92009-12-01 20:13:26 +00004033 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004034 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004035 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004036 cache_info->cache_filename,cache_info->file,format);
4037 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4038 }
4039 if (length != (MagickSizeType) ((MagickOffsetType) length))
4040 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004041 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004042 if (extent < 0)
4043 return(MagickFalse);
4044 if ((MagickSizeType) extent >= length)
4045 return(MagickTrue);
4046 offset=(MagickOffsetType) length-1;
4047 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4048 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4049}
4050
4051static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4052 ExceptionInfo *exception)
4053{
cristy3ed852e2009-09-05 21:47:34 +00004054 CacheInfo
4055 *cache_info,
4056 source_info;
4057
cristyf3a6a9d2010-11-07 21:02:56 +00004058 char
4059 format[MaxTextExtent],
4060 message[MaxTextExtent];
4061
cristy4c08aed2011-07-01 19:47:50 +00004062 MagickBooleanType
4063 status;
4064
cristy3ed852e2009-09-05 21:47:34 +00004065 MagickSizeType
4066 length,
4067 number_pixels;
4068
cristy3ed852e2009-09-05 21:47:34 +00004069 size_t
cristye076a6e2010-08-15 19:59:43 +00004070 columns,
cristy3ed852e2009-09-05 21:47:34 +00004071 packet_size;
4072
cristye7cc7cf2010-09-21 13:26:47 +00004073 assert(image != (const Image *) NULL);
4074 assert(image->signature == MagickSignature);
4075 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004076 if (image->debug != MagickFalse)
4077 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4078 if ((image->columns == 0) || (image->rows == 0))
4079 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4080 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004081 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004082 source_info=(*cache_info);
4083 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004084 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004085 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004086 cache_info->storage_class=image->storage_class;
4087 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004088 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004089 cache_info->rows=image->rows;
4090 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004091 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004092 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004093 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004094 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004095 if (image->ping != MagickFalse)
4096 {
cristy73724512010-04-12 14:43:14 +00004097 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004098 cache_info->pixels=(Quantum *) NULL;
4099 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004100 cache_info->length=0;
4101 return(MagickTrue);
4102 }
cristy3ed852e2009-09-05 21:47:34 +00004103 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004104 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004105 if (image->metacontent_extent != 0)
4106 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004107 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004108 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004109 if (cache_info->columns != columns)
4110 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4111 image->filename);
4112 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004113 if ((cache_info->type != UndefinedCache) &&
4114 (cache_info->columns <= source_info.columns) &&
4115 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004116 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004117 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4118 {
4119 /*
4120 Inline pixel cache clone optimization.
4121 */
4122 if ((cache_info->columns == source_info.columns) &&
4123 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004124 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004125 (cache_info->metacontent_extent == source_info.metacontent_extent))
4126 return(MagickTrue);
4127 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4128 }
cristy3ed852e2009-09-05 21:47:34 +00004129 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004130 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004131 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004132 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4133 {
4134 status=AcquireMagickResource(MemoryResource,cache_info->length);
4135 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4136 (cache_info->type == MemoryCache))
4137 {
cristyd43a46b2010-01-21 02:13:41 +00004138 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004139 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004140 cache_info->pixels=source_info.pixels;
4141 else
4142 {
4143 /*
4144 Create memory pixel cache.
4145 */
cristy4c08aed2011-07-01 19:47:50 +00004146 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004147 if (image->debug != MagickFalse)
4148 {
cristy97e7a572009-12-05 15:07:53 +00004149 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004150 format);
cristyb51dff52011-05-19 16:55:47 +00004151 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004152 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4153 cache_info->filename,cache_info->mapped != MagickFalse ?
4154 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004155 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004156 format);
cristy3ed852e2009-09-05 21:47:34 +00004157 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4158 message);
4159 }
cristy3ed852e2009-09-05 21:47:34 +00004160 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004161 cache_info->metacontent=(void *) NULL;
4162 if (cache_info->metacontent_extent != 0)
4163 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004164 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004165 if (source_info.storage_class != UndefinedClass)
4166 {
cristy4c08aed2011-07-01 19:47:50 +00004167 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004168 exception);
4169 RelinquishPixelCachePixels(&source_info);
4170 }
cristy4c08aed2011-07-01 19:47:50 +00004171 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004172 }
4173 }
4174 RelinquishMagickResource(MemoryResource,cache_info->length);
4175 }
4176 /*
4177 Create pixel cache on disk.
4178 */
4179 status=AcquireMagickResource(DiskResource,cache_info->length);
4180 if (status == MagickFalse)
4181 {
4182 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4183 "CacheResourcesExhausted","`%s'",image->filename);
4184 return(MagickFalse);
4185 }
4186 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4187 {
4188 RelinquishMagickResource(DiskResource,cache_info->length);
4189 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4190 image->filename);
4191 return(MagickFalse);
4192 }
4193 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4194 cache_info->length);
4195 if (status == MagickFalse)
4196 {
4197 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4198 image->filename);
4199 return(MagickFalse);
4200 }
cristyed231572011-07-14 02:18:59 +00004201 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004202 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004203 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004204 cache_info->type=DiskCache;
4205 else
4206 {
4207 status=AcquireMagickResource(MapResource,cache_info->length);
4208 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4209 (cache_info->type != MemoryCache))
4210 cache_info->type=DiskCache;
4211 else
4212 {
cristy4c08aed2011-07-01 19:47:50 +00004213 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004214 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004215 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004216 {
cristy3ed852e2009-09-05 21:47:34 +00004217 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004218 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004219 }
4220 else
4221 {
4222 /*
4223 Create file-backed memory-mapped pixel cache.
4224 */
cristy4c08aed2011-07-01 19:47:50 +00004225 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004226 (void) ClosePixelCacheOnDisk(cache_info);
4227 cache_info->type=MapCache;
4228 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004229 cache_info->metacontent=(void *) NULL;
4230 if (cache_info->metacontent_extent != 0)
4231 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004232 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004233 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004234 {
4235 status=ClonePixelCachePixels(cache_info,&source_info,
4236 exception);
4237 RelinquishPixelCachePixels(&source_info);
4238 }
4239 if (image->debug != MagickFalse)
4240 {
cristy97e7a572009-12-05 15:07:53 +00004241 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004242 format);
cristyb51dff52011-05-19 16:55:47 +00004243 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004244 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004245 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004246 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004247 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004248 format);
cristy3ed852e2009-09-05 21:47:34 +00004249 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4250 message);
4251 }
cristy4c08aed2011-07-01 19:47:50 +00004252 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004253 }
4254 }
4255 RelinquishMagickResource(MapResource,cache_info->length);
4256 }
cristy4c08aed2011-07-01 19:47:50 +00004257 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004258 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4259 {
4260 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4261 RelinquishPixelCachePixels(&source_info);
4262 }
4263 if (image->debug != MagickFalse)
4264 {
cristyb9080c92009-12-01 20:13:26 +00004265 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004266 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004267 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004268 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004269 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004270 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004271 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4272 }
cristy4c08aed2011-07-01 19:47:50 +00004273 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004274}
4275
4276/*
4277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4278% %
4279% %
4280% %
4281+ P e r s i s t P i x e l C a c h e %
4282% %
4283% %
4284% %
4285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4286%
4287% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4288% persistent pixel cache is one that resides on disk and is not destroyed
4289% when the program exits.
4290%
4291% The format of the PersistPixelCache() method is:
4292%
4293% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4294% const MagickBooleanType attach,MagickOffsetType *offset,
4295% ExceptionInfo *exception)
4296%
4297% A description of each parameter follows:
4298%
4299% o image: the image.
4300%
4301% o filename: the persistent pixel cache filename.
4302%
cristyf3a6a9d2010-11-07 21:02:56 +00004303% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004304%
cristy3ed852e2009-09-05 21:47:34 +00004305% o initialize: A value other than zero initializes the persistent pixel
4306% cache.
4307%
4308% o offset: the offset in the persistent cache to store pixels.
4309%
4310% o exception: return any errors or warnings in this structure.
4311%
4312*/
4313MagickExport MagickBooleanType PersistPixelCache(Image *image,
4314 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4315 ExceptionInfo *exception)
4316{
4317 CacheInfo
4318 *cache_info,
4319 *clone_info;
4320
4321 Image
4322 clone_image;
4323
cristy3ed852e2009-09-05 21:47:34 +00004324 MagickBooleanType
4325 status;
4326
cristye076a6e2010-08-15 19:59:43 +00004327 ssize_t
4328 page_size;
4329
cristy3ed852e2009-09-05 21:47:34 +00004330 assert(image != (Image *) NULL);
4331 assert(image->signature == MagickSignature);
4332 if (image->debug != MagickFalse)
4333 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4334 assert(image->cache != (void *) NULL);
4335 assert(filename != (const char *) NULL);
4336 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004337 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004338 cache_info=(CacheInfo *) image->cache;
4339 assert(cache_info->signature == MagickSignature);
4340 if (attach != MagickFalse)
4341 {
4342 /*
cristy01b7eb02009-09-10 23:10:14 +00004343 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004344 */
4345 if (image->debug != MagickFalse)
4346 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004347 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004348 (void) CopyMagickString(cache_info->cache_filename,filename,
4349 MaxTextExtent);
4350 cache_info->type=DiskCache;
4351 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004352 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004353 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004354 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004355 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004356 }
cristy01b7eb02009-09-10 23:10:14 +00004357 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4358 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004359 {
cristyf84a1932010-01-03 18:00:18 +00004360 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004361 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004362 (cache_info->reference_count == 1))
4363 {
4364 int
4365 status;
4366
4367 /*
cristy01b7eb02009-09-10 23:10:14 +00004368 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004369 */
cristy320684d2011-09-23 14:55:47 +00004370 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004371 if (status == 0)
4372 {
4373 (void) CopyMagickString(cache_info->cache_filename,filename,
4374 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004375 *offset+=cache_info->length+page_size-(cache_info->length %
4376 page_size);
cristyf84a1932010-01-03 18:00:18 +00004377 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004378 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004379 if (image->debug != MagickFalse)
4380 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4381 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004382 return(MagickTrue);
4383 }
4384 }
cristyf84a1932010-01-03 18:00:18 +00004385 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004386 }
4387 /*
cristy01b7eb02009-09-10 23:10:14 +00004388 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004389 */
4390 clone_image=(*image);
4391 clone_info=(CacheInfo *) clone_image.cache;
4392 image->cache=ClonePixelCache(cache_info);
4393 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4394 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4395 cache_info->type=DiskCache;
4396 cache_info->offset=(*offset);
4397 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004398 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004399 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004400 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004401 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004402 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4403 return(status);
4404}
4405
4406/*
4407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4408% %
4409% %
4410% %
4411+ Q u e u e A u t h e n t i c N e x u s %
4412% %
4413% %
4414% %
4415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4416%
4417% QueueAuthenticNexus() allocates an region to store image pixels as defined
4418% by the region rectangle and returns a pointer to the region. This region is
4419% subsequently transferred from the pixel cache with
4420% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4421% pixels are transferred, otherwise a NULL is returned.
4422%
4423% The format of the QueueAuthenticNexus() method is:
4424%
cristy4c08aed2011-07-01 19:47:50 +00004425% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004426% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004427% const MagickBooleanType clone,NexusInfo *nexus_info,
4428% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004429%
4430% A description of each parameter follows:
4431%
4432% o image: the image.
4433%
4434% o x,y,columns,rows: These values define the perimeter of a region of
4435% pixels.
4436%
4437% o nexus_info: the cache nexus to set.
4438%
cristy65dbf172011-10-06 17:32:04 +00004439% o clone: clone the pixel cache.
4440%
cristy3ed852e2009-09-05 21:47:34 +00004441% o exception: return any errors or warnings in this structure.
4442%
4443*/
cristya6577ff2011-09-02 19:54:26 +00004444MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004445 const ssize_t y,const size_t columns,const size_t rows,
4446 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004447{
4448 CacheInfo
4449 *cache_info;
4450
4451 MagickOffsetType
4452 offset;
4453
4454 MagickSizeType
4455 number_pixels;
4456
4457 RectangleInfo
4458 region;
4459
4460 /*
4461 Validate pixel cache geometry.
4462 */
cristye7cc7cf2010-09-21 13:26:47 +00004463 assert(image != (const Image *) NULL);
4464 assert(image->signature == MagickSignature);
4465 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004466 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004467 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004468 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004469 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004470 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4471 {
4472 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4473 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004474 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004475 }
cristybb503372010-05-27 20:51:26 +00004476 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4477 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004478 {
4479 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4480 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004481 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004482 }
4483 offset=(MagickOffsetType) y*cache_info->columns+x;
4484 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004485 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004486 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4487 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4488 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004489 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004490 /*
4491 Return pixel cache.
4492 */
4493 region.x=x;
4494 region.y=y;
4495 region.width=columns;
4496 region.height=rows;
4497 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4498}
4499
4500/*
4501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4502% %
4503% %
4504% %
4505+ 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 %
4506% %
4507% %
4508% %
4509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4510%
4511% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4512% defined by the region rectangle and returns a pointer to the region. This
4513% region is subsequently transferred from the pixel cache with
4514% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4515% pixels are transferred, otherwise a NULL is returned.
4516%
4517% The format of the QueueAuthenticPixelsCache() method is:
4518%
cristy4c08aed2011-07-01 19:47:50 +00004519% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004520% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004521% ExceptionInfo *exception)
4522%
4523% A description of each parameter follows:
4524%
4525% o image: the image.
4526%
4527% o x,y,columns,rows: These values define the perimeter of a region of
4528% pixels.
4529%
4530% o exception: return any errors or warnings in this structure.
4531%
4532*/
cristy4c08aed2011-07-01 19:47:50 +00004533static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004534 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004535 ExceptionInfo *exception)
4536{
4537 CacheInfo
4538 *cache_info;
4539
cristy5c9e6f22010-09-17 17:31:01 +00004540 const int
4541 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004542
cristy4c08aed2011-07-01 19:47:50 +00004543 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004544 *q;
cristy4c08aed2011-07-01 19:47:50 +00004545
cristye7cc7cf2010-09-21 13:26:47 +00004546 assert(image != (const Image *) NULL);
4547 assert(image->signature == MagickSignature);
4548 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004549 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004550 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004551 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004552 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4553 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004554 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004555}
4556
4557/*
4558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4559% %
4560% %
4561% %
4562% Q u e u e A u t h e n t i c P i x e l s %
4563% %
4564% %
4565% %
4566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4567%
4568% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004569% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004570% region is returned, otherwise NULL is returned. The returned pointer may
4571% point to a temporary working buffer for the pixels or it may point to the
4572% final location of the pixels in memory.
4573%
4574% Write-only access means that any existing pixel values corresponding to
4575% the region are ignored. This is useful if the initial image is being
4576% created from scratch, or if the existing pixel values are to be
4577% completely replaced without need to refer to their pre-existing values.
4578% The application is free to read and write the pixel buffer returned by
4579% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4580% initialize the pixel array values. Initializing pixel array values is the
4581% application's responsibility.
4582%
4583% Performance is maximized if the selected region is part of one row, or
4584% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004585% pixels in-place (without a copy) if the image is in memory, or in a
4586% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004587% by the user.
4588%
4589% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004590% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4591% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4592% obtain the meta-content (of type void) corresponding to the region.
4593% Once the Quantum (and/or Quantum) array has been updated, the
4594% changes must be saved back to the underlying image using
4595% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004596%
4597% The format of the QueueAuthenticPixels() method is:
4598%
cristy4c08aed2011-07-01 19:47:50 +00004599% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004600% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004601% ExceptionInfo *exception)
4602%
4603% A description of each parameter follows:
4604%
4605% o image: the image.
4606%
4607% o x,y,columns,rows: These values define the perimeter of a region of
4608% pixels.
4609%
4610% o exception: return any errors or warnings in this structure.
4611%
4612*/
cristy4c08aed2011-07-01 19:47:50 +00004613MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004614 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004615 ExceptionInfo *exception)
4616{
4617 CacheInfo
4618 *cache_info;
4619
cristy2036f5c2010-09-19 21:18:17 +00004620 const int
4621 id = GetOpenMPThreadId();
4622
cristy4c08aed2011-07-01 19:47:50 +00004623 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004624 *q;
cristy4c08aed2011-07-01 19:47:50 +00004625
cristy3ed852e2009-09-05 21:47:34 +00004626 assert(image != (Image *) NULL);
4627 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004628 assert(image->cache != (Cache) NULL);
4629 cache_info=(CacheInfo *) image->cache;
4630 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004631 if (cache_info->methods.queue_authentic_pixels_handler !=
4632 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004633 {
cristyacd2ed22011-08-30 01:44:23 +00004634 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004635 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004636 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004637 }
cristy2036f5c2010-09-19 21:18:17 +00004638 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004639 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4640 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004641 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004642}
4643
4644/*
4645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4646% %
4647% %
4648% %
cristy4c08aed2011-07-01 19:47:50 +00004649+ 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 +00004650% %
4651% %
4652% %
4653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4654%
cristy4c08aed2011-07-01 19:47:50 +00004655% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004656% the pixel cache.
4657%
cristy4c08aed2011-07-01 19:47:50 +00004658% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004659%
cristy4c08aed2011-07-01 19:47:50 +00004660% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004661% NexusInfo *nexus_info,ExceptionInfo *exception)
4662%
4663% A description of each parameter follows:
4664%
4665% o cache_info: the pixel cache.
4666%
cristy4c08aed2011-07-01 19:47:50 +00004667% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004668%
4669% o exception: return any errors or warnings in this structure.
4670%
4671*/
cristy4c08aed2011-07-01 19:47:50 +00004672static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004673 NexusInfo *nexus_info,ExceptionInfo *exception)
4674{
4675 MagickOffsetType
4676 count,
4677 offset;
4678
4679 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004680 extent,
4681 length;
cristy3ed852e2009-09-05 21:47:34 +00004682
cristybb503372010-05-27 20:51:26 +00004683 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004684 y;
4685
cristy4c08aed2011-07-01 19:47:50 +00004686 register unsigned char
4687 *restrict q;
4688
cristybb503372010-05-27 20:51:26 +00004689 size_t
cristy3ed852e2009-09-05 21:47:34 +00004690 rows;
4691
cristy4c08aed2011-07-01 19:47:50 +00004692 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004693 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004694 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004695 return(MagickTrue);
4696 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4697 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004698 length=(MagickSizeType) nexus_info->region.width*
4699 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004700 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004701 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004702 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004703 switch (cache_info->type)
4704 {
4705 case MemoryCache:
4706 case MapCache:
4707 {
cristy4c08aed2011-07-01 19:47:50 +00004708 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004709 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004710
4711 /*
cristy4c08aed2011-07-01 19:47:50 +00004712 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004713 */
cristydd341db2010-03-04 19:06:38 +00004714 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004715 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004716 {
cristy48078b12010-09-23 17:11:01 +00004717 length=extent;
cristydd341db2010-03-04 19:06:38 +00004718 rows=1UL;
4719 }
cristy4c08aed2011-07-01 19:47:50 +00004720 p=(unsigned char *) cache_info->metacontent+offset*
4721 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004722 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004723 {
cristy8f036fe2010-09-18 02:02:00 +00004724 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004725 p+=cache_info->metacontent_extent*cache_info->columns;
4726 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004727 }
4728 break;
4729 }
4730 case DiskCache:
4731 {
4732 /*
cristy4c08aed2011-07-01 19:47:50 +00004733 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004734 */
4735 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4736 {
4737 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4738 cache_info->cache_filename);
4739 return(MagickFalse);
4740 }
cristydd341db2010-03-04 19:06:38 +00004741 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004742 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004743 {
cristy48078b12010-09-23 17:11:01 +00004744 length=extent;
cristydd341db2010-03-04 19:06:38 +00004745 rows=1UL;
4746 }
cristy48078b12010-09-23 17:11:01 +00004747 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004748 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004749 {
cristy48078b12010-09-23 17:11:01 +00004750 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004751 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004752 cache_info->metacontent_extent,length,(unsigned char *) q);
4753 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004754 break;
4755 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004756 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004757 }
cristybb503372010-05-27 20:51:26 +00004758 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004759 {
4760 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4761 cache_info->cache_filename);
4762 return(MagickFalse);
4763 }
4764 break;
4765 }
4766 default:
4767 break;
4768 }
4769 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004770 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004771 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004772 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004773 nexus_info->region.width,(double) nexus_info->region.height,(double)
4774 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004775 return(MagickTrue);
4776}
4777
4778/*
4779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4780% %
4781% %
4782% %
4783+ R e a d P i x e l C a c h e P i x e l s %
4784% %
4785% %
4786% %
4787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4788%
4789% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4790% cache.
4791%
4792% The format of the ReadPixelCachePixels() method is:
4793%
4794% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4795% NexusInfo *nexus_info,ExceptionInfo *exception)
4796%
4797% A description of each parameter follows:
4798%
4799% o cache_info: the pixel cache.
4800%
4801% o nexus_info: the cache nexus to read the pixels.
4802%
4803% o exception: return any errors or warnings in this structure.
4804%
4805*/
4806static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4807 NexusInfo *nexus_info,ExceptionInfo *exception)
4808{
4809 MagickOffsetType
4810 count,
4811 offset;
4812
4813 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004814 extent,
4815 length;
cristy3ed852e2009-09-05 21:47:34 +00004816
cristy4c08aed2011-07-01 19:47:50 +00004817 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004818 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004819
cristye076a6e2010-08-15 19:59:43 +00004820 register ssize_t
4821 y;
4822
cristybb503372010-05-27 20:51:26 +00004823 size_t
cristy3ed852e2009-09-05 21:47:34 +00004824 rows;
4825
cristy4c08aed2011-07-01 19:47:50 +00004826 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004827 return(MagickTrue);
4828 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4829 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004830 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004831 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004832 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004833 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004834 q=nexus_info->pixels;
4835 switch (cache_info->type)
4836 {
4837 case MemoryCache:
4838 case MapCache:
4839 {
cristy4c08aed2011-07-01 19:47:50 +00004840 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004841 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004842
4843 /*
4844 Read pixels from memory.
4845 */
cristydd341db2010-03-04 19:06:38 +00004846 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004847 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004848 {
cristy48078b12010-09-23 17:11:01 +00004849 length=extent;
cristydd341db2010-03-04 19:06:38 +00004850 rows=1UL;
4851 }
cristyed231572011-07-14 02:18:59 +00004852 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004853 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004854 {
cristy8f036fe2010-09-18 02:02:00 +00004855 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004856 p+=cache_info->number_channels*cache_info->columns;
4857 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004858 }
4859 break;
4860 }
4861 case DiskCache:
4862 {
4863 /*
4864 Read pixels from disk.
4865 */
4866 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4867 {
4868 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4869 cache_info->cache_filename);
4870 return(MagickFalse);
4871 }
cristydd341db2010-03-04 19:06:38 +00004872 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004873 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004874 {
cristy48078b12010-09-23 17:11:01 +00004875 length=extent;
cristydd341db2010-03-04 19:06:38 +00004876 rows=1UL;
4877 }
cristybb503372010-05-27 20:51:26 +00004878 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004879 {
4880 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004881 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004882 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004883 break;
4884 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004885 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004886 }
cristybb503372010-05-27 20:51:26 +00004887 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004888 {
4889 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4890 cache_info->cache_filename);
4891 return(MagickFalse);
4892 }
4893 break;
4894 }
4895 default:
4896 break;
4897 }
4898 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004899 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004900 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004901 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004902 nexus_info->region.width,(double) nexus_info->region.height,(double)
4903 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004904 return(MagickTrue);
4905}
4906
4907/*
4908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4909% %
4910% %
4911% %
4912+ R e f e r e n c e P i x e l C a c h e %
4913% %
4914% %
4915% %
4916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4917%
4918% ReferencePixelCache() increments the reference count associated with the
4919% pixel cache returning a pointer to the cache.
4920%
4921% The format of the ReferencePixelCache method is:
4922%
4923% Cache ReferencePixelCache(Cache cache_info)
4924%
4925% A description of each parameter follows:
4926%
4927% o cache_info: the pixel cache.
4928%
4929*/
cristya6577ff2011-09-02 19:54:26 +00004930MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004931{
4932 CacheInfo
4933 *cache_info;
4934
4935 assert(cache != (Cache *) NULL);
4936 cache_info=(CacheInfo *) cache;
4937 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004938 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004939 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004940 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004941 return(cache_info);
4942}
4943
4944/*
4945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4946% %
4947% %
4948% %
4949+ S e t P i x e l C a c h e M e t h o d s %
4950% %
4951% %
4952% %
4953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4954%
4955% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4956%
4957% The format of the SetPixelCacheMethods() method is:
4958%
4959% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4960%
4961% A description of each parameter follows:
4962%
4963% o cache: the pixel cache.
4964%
4965% o cache_methods: Specifies a pointer to a CacheMethods structure.
4966%
4967*/
cristya6577ff2011-09-02 19:54:26 +00004968MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004969{
4970 CacheInfo
4971 *cache_info;
4972
4973 GetOneAuthenticPixelFromHandler
4974 get_one_authentic_pixel_from_handler;
4975
4976 GetOneVirtualPixelFromHandler
4977 get_one_virtual_pixel_from_handler;
4978
4979 /*
4980 Set cache pixel methods.
4981 */
4982 assert(cache != (Cache) NULL);
4983 assert(cache_methods != (CacheMethods *) NULL);
4984 cache_info=(CacheInfo *) cache;
4985 assert(cache_info->signature == MagickSignature);
4986 if (cache_info->debug != MagickFalse)
4987 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4988 cache_info->filename);
4989 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4990 cache_info->methods.get_virtual_pixel_handler=
4991 cache_methods->get_virtual_pixel_handler;
4992 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4993 cache_info->methods.destroy_pixel_handler=
4994 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004995 if (cache_methods->get_virtual_metacontent_from_handler !=
4996 (GetVirtualMetacontentFromHandler) NULL)
4997 cache_info->methods.get_virtual_metacontent_from_handler=
4998 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004999 if (cache_methods->get_authentic_pixels_handler !=
5000 (GetAuthenticPixelsHandler) NULL)
5001 cache_info->methods.get_authentic_pixels_handler=
5002 cache_methods->get_authentic_pixels_handler;
5003 if (cache_methods->queue_authentic_pixels_handler !=
5004 (QueueAuthenticPixelsHandler) NULL)
5005 cache_info->methods.queue_authentic_pixels_handler=
5006 cache_methods->queue_authentic_pixels_handler;
5007 if (cache_methods->sync_authentic_pixels_handler !=
5008 (SyncAuthenticPixelsHandler) NULL)
5009 cache_info->methods.sync_authentic_pixels_handler=
5010 cache_methods->sync_authentic_pixels_handler;
5011 if (cache_methods->get_authentic_pixels_from_handler !=
5012 (GetAuthenticPixelsFromHandler) NULL)
5013 cache_info->methods.get_authentic_pixels_from_handler=
5014 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00005015 if (cache_methods->get_authentic_metacontent_from_handler !=
5016 (GetAuthenticMetacontentFromHandler) NULL)
5017 cache_info->methods.get_authentic_metacontent_from_handler=
5018 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00005019 get_one_virtual_pixel_from_handler=
5020 cache_info->methods.get_one_virtual_pixel_from_handler;
5021 if (get_one_virtual_pixel_from_handler !=
5022 (GetOneVirtualPixelFromHandler) NULL)
5023 cache_info->methods.get_one_virtual_pixel_from_handler=
5024 cache_methods->get_one_virtual_pixel_from_handler;
5025 get_one_authentic_pixel_from_handler=
5026 cache_methods->get_one_authentic_pixel_from_handler;
5027 if (get_one_authentic_pixel_from_handler !=
5028 (GetOneAuthenticPixelFromHandler) NULL)
5029 cache_info->methods.get_one_authentic_pixel_from_handler=
5030 cache_methods->get_one_authentic_pixel_from_handler;
5031}
5032
5033/*
5034%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5035% %
5036% %
5037% %
5038+ S e t P i x e l C a c h e N e x u s P i x e l s %
5039% %
5040% %
5041% %
5042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5043%
5044% SetPixelCacheNexusPixels() defines the region of the cache for the
5045% specified cache nexus.
5046%
5047% The format of the SetPixelCacheNexusPixels() method is:
5048%
cristy4c08aed2011-07-01 19:47:50 +00005049% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005050% const RectangleInfo *region,NexusInfo *nexus_info,
5051% ExceptionInfo *exception)
5052%
5053% A description of each parameter follows:
5054%
5055% o image: the image.
5056%
5057% o region: A pointer to the RectangleInfo structure that defines the
5058% region of this particular cache nexus.
5059%
5060% o nexus_info: the cache nexus to set.
5061%
5062% o exception: return any errors or warnings in this structure.
5063%
5064*/
cristyabd6e372010-09-15 19:11:26 +00005065
5066static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5067 NexusInfo *nexus_info,ExceptionInfo *exception)
5068{
5069 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5070 return(MagickFalse);
5071 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005072 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005073 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005074 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005075 {
5076 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005077 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005078 nexus_info->length);
5079 }
cristy4c08aed2011-07-01 19:47:50 +00005080 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005081 {
5082 (void) ThrowMagickException(exception,GetMagickModule(),
5083 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5084 cache_info->filename);
5085 return(MagickFalse);
5086 }
5087 return(MagickTrue);
5088}
5089
cristy4c08aed2011-07-01 19:47:50 +00005090static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005091 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5092{
5093 CacheInfo
5094 *cache_info;
5095
5096 MagickBooleanType
5097 status;
5098
cristy3ed852e2009-09-05 21:47:34 +00005099 MagickSizeType
5100 length,
5101 number_pixels;
5102
cristy3ed852e2009-09-05 21:47:34 +00005103 cache_info=(CacheInfo *) image->cache;
5104 assert(cache_info->signature == MagickSignature);
5105 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005106 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005107 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005108 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5109 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005110 {
cristybb503372010-05-27 20:51:26 +00005111 ssize_t
cristybad067a2010-02-15 17:20:55 +00005112 x,
5113 y;
cristy3ed852e2009-09-05 21:47:34 +00005114
cristyeaedf062010-05-29 22:36:02 +00005115 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5116 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005117 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5118 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005119 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005120 ((nexus_info->region.width == cache_info->columns) ||
5121 ((nexus_info->region.width % cache_info->columns) == 0)))))
5122 {
5123 MagickOffsetType
5124 offset;
5125
5126 /*
5127 Pixels are accessed directly from memory.
5128 */
5129 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5130 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005131 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005132 offset;
5133 nexus_info->metacontent=(void *) NULL;
5134 if (cache_info->metacontent_extent != 0)
5135 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5136 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005137 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005138 }
5139 }
5140 /*
5141 Pixels are stored in a cache region until they are synced to the cache.
5142 */
5143 number_pixels=(MagickSizeType) nexus_info->region.width*
5144 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005145 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005146 if (cache_info->metacontent_extent != 0)
5147 length+=number_pixels*cache_info->metacontent_extent;
5148 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005149 {
5150 nexus_info->length=length;
5151 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5152 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005153 {
5154 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005155 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005156 }
cristy3ed852e2009-09-05 21:47:34 +00005157 }
5158 else
5159 if (nexus_info->length != length)
5160 {
5161 RelinquishCacheNexusPixels(nexus_info);
5162 nexus_info->length=length;
5163 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5164 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005165 {
5166 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005167 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005168 }
cristy3ed852e2009-09-05 21:47:34 +00005169 }
5170 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005171 nexus_info->metacontent=(void *) NULL;
5172 if (cache_info->metacontent_extent != 0)
5173 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005174 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005175 return(nexus_info->pixels);
5176}
5177
5178/*
5179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5180% %
5181% %
5182% %
5183% 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 %
5184% %
5185% %
5186% %
5187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5188%
5189% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5190% pixel cache and returns the previous setting. A virtual pixel is any pixel
5191% access that is outside the boundaries of the image cache.
5192%
5193% The format of the SetPixelCacheVirtualMethod() method is:
5194%
5195% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5196% const VirtualPixelMethod virtual_pixel_method)
5197%
5198% A description of each parameter follows:
5199%
5200% o image: the image.
5201%
5202% o virtual_pixel_method: choose the type of virtual pixel.
5203%
5204*/
cristyd1dd6e42011-09-04 01:46:08 +00005205MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005206 const VirtualPixelMethod virtual_pixel_method)
5207{
5208 CacheInfo
5209 *cache_info;
5210
5211 VirtualPixelMethod
5212 method;
5213
5214 assert(image != (Image *) NULL);
5215 assert(image->signature == MagickSignature);
5216 if (image->debug != MagickFalse)
5217 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5218 assert(image->cache != (Cache) NULL);
5219 cache_info=(CacheInfo *) image->cache;
5220 assert(cache_info->signature == MagickSignature);
5221 method=cache_info->virtual_pixel_method;
5222 cache_info->virtual_pixel_method=virtual_pixel_method;
5223 return(method);
5224}
5225
5226/*
5227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228% %
5229% %
5230% %
5231+ 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 %
5232% %
5233% %
5234% %
5235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5236%
5237% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5238% in-memory or disk cache. The method returns MagickTrue if the pixel region
5239% is synced, otherwise MagickFalse.
5240%
5241% The format of the SyncAuthenticPixelCacheNexus() method is:
5242%
5243% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5244% NexusInfo *nexus_info,ExceptionInfo *exception)
5245%
5246% A description of each parameter follows:
5247%
5248% o image: the image.
5249%
5250% o nexus_info: the cache nexus to sync.
5251%
5252% o exception: return any errors or warnings in this structure.
5253%
5254*/
cristya6577ff2011-09-02 19:54:26 +00005255MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005256 NexusInfo *nexus_info,ExceptionInfo *exception)
5257{
5258 CacheInfo
5259 *cache_info;
5260
5261 MagickBooleanType
5262 status;
5263
5264 /*
5265 Transfer pixels to the cache.
5266 */
5267 assert(image != (Image *) NULL);
5268 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005269 if (image->cache == (Cache) NULL)
5270 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5271 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005272 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005273 if (cache_info->type == UndefinedCache)
5274 return(MagickFalse);
5275 if ((image->clip_mask != (Image *) NULL) &&
5276 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5277 return(MagickFalse);
5278 if ((image->mask != (Image *) NULL) &&
5279 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5280 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005281 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005282 return(MagickTrue);
5283 assert(cache_info->signature == MagickSignature);
5284 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005285 if ((cache_info->metacontent_extent != 0) &&
5286 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005287 return(MagickFalse);
5288 return(status);
5289}
5290
5291/*
5292%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5293% %
5294% %
5295% %
5296+ S y n c A u t h e n t i c P i x e l C a c h e %
5297% %
5298% %
5299% %
5300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5301%
5302% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5303% or disk cache. The method returns MagickTrue if the pixel region is synced,
5304% otherwise MagickFalse.
5305%
5306% The format of the SyncAuthenticPixelsCache() method is:
5307%
5308% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5309% ExceptionInfo *exception)
5310%
5311% A description of each parameter follows:
5312%
5313% o image: the image.
5314%
5315% o exception: return any errors or warnings in this structure.
5316%
5317*/
5318static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5319 ExceptionInfo *exception)
5320{
5321 CacheInfo
5322 *cache_info;
5323
cristy5c9e6f22010-09-17 17:31:01 +00005324 const int
5325 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005326
cristy4c08aed2011-07-01 19:47:50 +00005327 MagickBooleanType
5328 status;
5329
cristye7cc7cf2010-09-21 13:26:47 +00005330 assert(image != (Image *) NULL);
5331 assert(image->signature == MagickSignature);
5332 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005333 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005334 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005335 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005336 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5337 exception);
5338 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005339}
5340
5341/*
5342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5343% %
5344% %
5345% %
5346% S y n c A u t h e n t i c P i x e l s %
5347% %
5348% %
5349% %
5350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5351%
5352% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5353% The method returns MagickTrue if the pixel region is flushed, otherwise
5354% MagickFalse.
5355%
5356% The format of the SyncAuthenticPixels() method is:
5357%
5358% MagickBooleanType SyncAuthenticPixels(Image *image,
5359% ExceptionInfo *exception)
5360%
5361% A description of each parameter follows:
5362%
5363% o image: the image.
5364%
5365% o exception: return any errors or warnings in this structure.
5366%
5367*/
5368MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5369 ExceptionInfo *exception)
5370{
5371 CacheInfo
5372 *cache_info;
5373
cristy2036f5c2010-09-19 21:18:17 +00005374 const int
5375 id = GetOpenMPThreadId();
5376
cristy4c08aed2011-07-01 19:47:50 +00005377 MagickBooleanType
5378 status;
5379
cristy3ed852e2009-09-05 21:47:34 +00005380 assert(image != (Image *) NULL);
5381 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005382 assert(image->cache != (Cache) NULL);
5383 cache_info=(CacheInfo *) image->cache;
5384 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005385 if (cache_info->methods.sync_authentic_pixels_handler !=
5386 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005387 {
5388 status=cache_info->methods.sync_authentic_pixels_handler(image,
5389 exception);
5390 return(status);
5391 }
cristy2036f5c2010-09-19 21:18:17 +00005392 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005393 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5394 exception);
5395 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005396}
5397
5398/*
5399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5400% %
5401% %
5402% %
cristyd1dd6e42011-09-04 01:46:08 +00005403+ 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 +00005404% %
5405% %
5406% %
5407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5408%
5409% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5410% The method returns MagickTrue if the pixel region is flushed, otherwise
5411% MagickFalse.
5412%
5413% The format of the SyncImagePixelCache() method is:
5414%
5415% MagickBooleanType SyncImagePixelCache(Image *image,
5416% ExceptionInfo *exception)
5417%
5418% A description of each parameter follows:
5419%
5420% o image: the image.
5421%
5422% o exception: return any errors or warnings in this structure.
5423%
5424*/
cristyd1dd6e42011-09-04 01:46:08 +00005425MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005426 ExceptionInfo *exception)
5427{
5428 CacheInfo
5429 *cache_info;
5430
5431 assert(image != (Image *) NULL);
5432 assert(exception != (ExceptionInfo *) NULL);
5433 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5434 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5435}
5436
5437/*
5438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5439% %
5440% %
5441% %
cristy4c08aed2011-07-01 19:47:50 +00005442+ 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 +00005443% %
5444% %
5445% %
5446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5447%
cristy4c08aed2011-07-01 19:47:50 +00005448% WritePixelCacheMetacontent() writes the meta-content to the specified region
5449% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005450%
cristy4c08aed2011-07-01 19:47:50 +00005451% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005452%
cristy4c08aed2011-07-01 19:47:50 +00005453% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005454% NexusInfo *nexus_info,ExceptionInfo *exception)
5455%
5456% A description of each parameter follows:
5457%
5458% o cache_info: the pixel cache.
5459%
cristy4c08aed2011-07-01 19:47:50 +00005460% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005461%
5462% o exception: return any errors or warnings in this structure.
5463%
5464*/
cristy4c08aed2011-07-01 19:47:50 +00005465static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005466 NexusInfo *nexus_info,ExceptionInfo *exception)
5467{
5468 MagickOffsetType
5469 count,
5470 offset;
5471
5472 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005473 extent,
5474 length;
cristy3ed852e2009-09-05 21:47:34 +00005475
cristy4c08aed2011-07-01 19:47:50 +00005476 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005477 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005478
cristybb503372010-05-27 20:51:26 +00005479 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005480 y;
5481
cristybb503372010-05-27 20:51:26 +00005482 size_t
cristy3ed852e2009-09-05 21:47:34 +00005483 rows;
5484
cristy4c08aed2011-07-01 19:47:50 +00005485 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005486 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005487 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005488 return(MagickTrue);
5489 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5490 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005491 length=(MagickSizeType) nexus_info->region.width*
5492 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005493 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005494 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005495 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005496 switch (cache_info->type)
5497 {
5498 case MemoryCache:
5499 case MapCache:
5500 {
cristy4c08aed2011-07-01 19:47:50 +00005501 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005502 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005503
5504 /*
cristy4c08aed2011-07-01 19:47:50 +00005505 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005506 */
cristydd341db2010-03-04 19:06:38 +00005507 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005508 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005509 {
cristy48078b12010-09-23 17:11:01 +00005510 length=extent;
cristydd341db2010-03-04 19:06:38 +00005511 rows=1UL;
5512 }
cristy4c08aed2011-07-01 19:47:50 +00005513 q=(unsigned char *) cache_info->metacontent+offset*
5514 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005515 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005516 {
cristy8f036fe2010-09-18 02:02:00 +00005517 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005518 p+=nexus_info->region.width*cache_info->metacontent_extent;
5519 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005520 }
5521 break;
5522 }
5523 case DiskCache:
5524 {
5525 /*
cristy4c08aed2011-07-01 19:47:50 +00005526 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005527 */
5528 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5529 {
5530 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5531 cache_info->cache_filename);
5532 return(MagickFalse);
5533 }
cristydd341db2010-03-04 19:06:38 +00005534 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005535 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005536 {
cristy48078b12010-09-23 17:11:01 +00005537 length=extent;
cristydd341db2010-03-04 19:06:38 +00005538 rows=1UL;
5539 }
cristy48078b12010-09-23 17:11:01 +00005540 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005541 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005542 {
cristy48078b12010-09-23 17:11:01 +00005543 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005544 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005545 cache_info->metacontent_extent,length,(const unsigned char *) p);
5546 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005547 break;
cristy4c08aed2011-07-01 19:47:50 +00005548 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005549 offset+=cache_info->columns;
5550 }
cristybb503372010-05-27 20:51:26 +00005551 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005552 {
5553 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5554 cache_info->cache_filename);
5555 return(MagickFalse);
5556 }
5557 break;
5558 }
5559 default:
5560 break;
5561 }
5562 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005563 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005564 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005565 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005566 nexus_info->region.width,(double) nexus_info->region.height,(double)
5567 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005568 return(MagickTrue);
5569}
5570
5571/*
5572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5573% %
5574% %
5575% %
5576+ W r i t e C a c h e P i x e l s %
5577% %
5578% %
5579% %
5580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5581%
5582% WritePixelCachePixels() writes image pixels to the specified region of the
5583% pixel cache.
5584%
5585% The format of the WritePixelCachePixels() method is:
5586%
5587% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5588% NexusInfo *nexus_info,ExceptionInfo *exception)
5589%
5590% A description of each parameter follows:
5591%
5592% o cache_info: the pixel cache.
5593%
5594% o nexus_info: the cache nexus to write the pixels.
5595%
5596% o exception: return any errors or warnings in this structure.
5597%
5598*/
5599static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5600 NexusInfo *nexus_info,ExceptionInfo *exception)
5601{
5602 MagickOffsetType
5603 count,
5604 offset;
5605
5606 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005607 extent,
5608 length;
cristy3ed852e2009-09-05 21:47:34 +00005609
cristy4c08aed2011-07-01 19:47:50 +00005610 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005611 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005612
cristybb503372010-05-27 20:51:26 +00005613 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005614 y;
5615
cristybb503372010-05-27 20:51:26 +00005616 size_t
cristy3ed852e2009-09-05 21:47:34 +00005617 rows;
5618
cristy4c08aed2011-07-01 19:47:50 +00005619 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005620 return(MagickTrue);
5621 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5622 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005623 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005624 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005625 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005626 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005627 p=nexus_info->pixels;
5628 switch (cache_info->type)
5629 {
5630 case MemoryCache:
5631 case MapCache:
5632 {
cristy4c08aed2011-07-01 19:47:50 +00005633 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005634 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005635
5636 /*
5637 Write pixels to memory.
5638 */
cristydd341db2010-03-04 19:06:38 +00005639 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005640 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005641 {
cristy48078b12010-09-23 17:11:01 +00005642 length=extent;
cristydd341db2010-03-04 19:06:38 +00005643 rows=1UL;
5644 }
cristyed231572011-07-14 02:18:59 +00005645 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005646 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005647 {
cristy8f036fe2010-09-18 02:02:00 +00005648 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005649 p+=nexus_info->region.width*cache_info->number_channels;
5650 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005651 }
5652 break;
5653 }
5654 case DiskCache:
5655 {
5656 /*
5657 Write pixels to disk.
5658 */
5659 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5660 {
5661 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5662 cache_info->cache_filename);
5663 return(MagickFalse);
5664 }
cristydd341db2010-03-04 19:06:38 +00005665 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005666 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005667 {
cristy48078b12010-09-23 17:11:01 +00005668 length=extent;
cristydd341db2010-03-04 19:06:38 +00005669 rows=1UL;
5670 }
cristybb503372010-05-27 20:51:26 +00005671 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005672 {
5673 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005674 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005675 p);
5676 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005677 break;
cristyed231572011-07-14 02:18:59 +00005678 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005679 offset+=cache_info->columns;
5680 }
cristybb503372010-05-27 20:51:26 +00005681 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005682 {
5683 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5684 cache_info->cache_filename);
5685 return(MagickFalse);
5686 }
5687 break;
5688 }
5689 default:
5690 break;
5691 }
5692 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005693 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005694 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005695 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005696 nexus_info->region.width,(double) nexus_info->region.height,(double)
5697 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005698 return(MagickTrue);
5699}