blob: af7060b12d3dcbb141097229c8c2377c7ea4d70c [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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 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;
cristy4d9c1922011-12-31 18:37:34 +0000673 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000674 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000675 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000676 return(MagickTrue);
677}
678
679static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
680 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000681 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000682{
683 register MagickOffsetType
684 i;
685
686 ssize_t
687 count;
688
cristy08a88202010-03-04 19:18:05 +0000689 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000690#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000691 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000692 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000693 {
cristyf84a1932010-01-03 18:00:18 +0000694 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000695 return((MagickOffsetType) -1);
696 }
697#endif
698 count=0;
699 for (i=0; i < (MagickOffsetType) length; i+=count)
700 {
701#if !defined(MAGICKCORE_HAVE_PREAD)
702 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
703 (MagickSizeType) SSIZE_MAX));
704#else
705 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000706 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000707#endif
708 if (count > 0)
709 continue;
710 count=0;
711 if (errno != EINTR)
712 {
713 i=(-1);
714 break;
715 }
716 }
717#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000718 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000719#endif
720 return(i);
721}
722
723static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
724 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000725 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000726{
727 register MagickOffsetType
728 i;
729
730 ssize_t
731 count;
732
cristy08a88202010-03-04 19:18:05 +0000733 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000734#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000735 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000736 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000737 {
cristyf84a1932010-01-03 18:00:18 +0000738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 return((MagickOffsetType) -1);
740 }
741#endif
742 count=0;
743 for (i=0; i < (MagickOffsetType) length; i+=count)
744 {
745#if !defined(MAGICKCORE_HAVE_PWRITE)
746 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
747 (MagickSizeType) SSIZE_MAX));
748#else
749 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000750 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000751#endif
752 if (count > 0)
753 continue;
754 count=0;
755 if (errno != EINTR)
756 {
757 i=(-1);
758 break;
759 }
760 }
761#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000762 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000763#endif
764 return(i);
765}
766
cristy4c08aed2011-07-01 19:47:50 +0000767static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000768 CacheInfo *cache_info,ExceptionInfo *exception)
769{
770 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000771 count;
cristy3ed852e2009-09-05 21:47:34 +0000772
cristy4c08aed2011-07-01 19:47:50 +0000773 register MagickOffsetType
774 i;
cristye076a6e2010-08-15 19:59:43 +0000775
cristybb503372010-05-27 20:51:26 +0000776 size_t
cristy4c08aed2011-07-01 19:47:50 +0000777 length;
cristy3ed852e2009-09-05 21:47:34 +0000778
cristy4c08aed2011-07-01 19:47:50 +0000779 unsigned char
780 *blob;
781
782 /*
783 Clone pixel cache (both caches on disk).
784 */
cristy3ed852e2009-09-05 21:47:34 +0000785 if (cache_info->debug != MagickFalse)
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000787 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000788 sizeof(*blob));
789 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000790 {
cristy4c08aed2011-07-01 19:47:50 +0000791 (void) ThrowMagickException(exception,GetMagickModule(),
792 ResourceLimitError,"MemoryAllocationFailed","`%s'",
793 cache_info->filename);
794 return(MagickFalse);
795 }
cristy3dedf062011-07-02 14:07:40 +0000796 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000797 {
798 blob=(unsigned char *) RelinquishMagickMemory(blob);
799 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
800 cache_info->cache_filename);
801 return(MagickFalse);
802 }
cristy3dedf062011-07-02 14:07:40 +0000803 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000804 {
805 (void) ClosePixelCacheOnDisk(cache_info);
806 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000807 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
808 clone_info->cache_filename);
809 return(MagickFalse);
810 }
cristy4c08aed2011-07-01 19:47:50 +0000811 count=0;
812 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
815 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
816 blob);
817 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000818 {
cristy4c08aed2011-07-01 19:47:50 +0000819 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
820 cache_info->cache_filename);
821 break;
cristy3ed852e2009-09-05 21:47:34 +0000822 }
cristy4c08aed2011-07-01 19:47:50 +0000823 length=(size_t) count;
824 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
825 if ((MagickSizeType) count != length)
826 {
827 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
828 clone_info->cache_filename);
829 break;
830 }
831 }
832 (void) ClosePixelCacheOnDisk(clone_info);
833 (void) ClosePixelCacheOnDisk(cache_info);
834 blob=(unsigned char *) RelinquishMagickMemory(blob);
835 if (i < (MagickOffsetType) cache_info->length)
836 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000837 return(MagickTrue);
838}
839
cristy4c08aed2011-07-01 19:47:50 +0000840static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000841 CacheInfo *cache_info,ExceptionInfo *exception)
842{
843 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000844 count;
cristy3ed852e2009-09-05 21:47:34 +0000845
cristy4c08aed2011-07-01 19:47:50 +0000846 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000847 {
cristy3ed852e2009-09-05 21:47:34 +0000848 /*
cristy4c08aed2011-07-01 19:47:50 +0000849 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000850 */
cristy4c08aed2011-07-01 19:47:50 +0000851 if (cache_info->debug != MagickFalse)
852 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
853 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
854 cache_info->length);
855 return(MagickTrue);
856 }
857 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
858 {
859 /*
860 Clone pixel cache (one cache on disk, one in memory).
861 */
862 if (cache_info->debug != MagickFalse)
863 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
864 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
cristy4c08aed2011-07-01 19:47:50 +0000866 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000867 cache_info->cache_filename);
868 return(MagickFalse);
869 }
cristy4c08aed2011-07-01 19:47:50 +0000870 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
871 cache_info->length,(unsigned char *) clone_info->pixels);
872 (void) ClosePixelCacheOnDisk(cache_info);
873 if ((MagickSizeType) count != cache_info->length)
874 {
875 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
876 cache_info->cache_filename);
877 return(MagickFalse);
878 }
879 return(MagickTrue);
880 }
881 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
882 {
883 /*
884 Clone pixel cache (one cache on disk, one in memory).
885 */
886 if (clone_info->debug != MagickFalse)
887 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
888 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
889 {
890 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
891 clone_info->cache_filename);
892 return(MagickFalse);
893 }
894 count=WritePixelCacheRegion(clone_info,clone_info->offset,
895 clone_info->length,(unsigned char *) cache_info->pixels);
896 (void) ClosePixelCacheOnDisk(clone_info);
897 if ((MagickSizeType) count != clone_info->length)
898 {
899 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
900 clone_info->cache_filename);
901 return(MagickFalse);
902 }
903 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000904 }
905 /*
cristy4c08aed2011-07-01 19:47:50 +0000906 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000907 */
cristy4c08aed2011-07-01 19:47:50 +0000908 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000909}
910
cristy4c08aed2011-07-01 19:47:50 +0000911static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000912 CacheInfo *cache_info,ExceptionInfo *exception)
913{
cristy4c08aed2011-07-01 19:47:50 +0000914 MagickBooleanType
915 status;
cristy3ed852e2009-09-05 21:47:34 +0000916
cristy4c08aed2011-07-01 19:47:50 +0000917 MagickOffsetType
918 cache_offset,
919 clone_offset,
920 count;
921
922 register ssize_t
923 x;
924
925 size_t
cristy3ed852e2009-09-05 21:47:34 +0000926 length;
927
cristy4c08aed2011-07-01 19:47:50 +0000928 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000929 y;
930
cristy4c08aed2011-07-01 19:47:50 +0000931 unsigned char
932 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000933
cristy4c08aed2011-07-01 19:47:50 +0000934 /*
935 Clone pixel cache (unoptimized).
936 */
cristy3ed852e2009-09-05 21:47:34 +0000937 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000938 {
cristy4c08aed2011-07-01 19:47:50 +0000939 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
940 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
941 else
942 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
943 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
944 else
945 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
947 else
948 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
949 }
cristyed231572011-07-14 02:18:59 +0000950 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
951 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000952 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000953 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000954 if (blob == (unsigned char *) NULL)
955 {
956 (void) ThrowMagickException(exception,GetMagickModule(),
957 ResourceLimitError,"MemoryAllocationFailed","`%s'",
958 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000959 return(MagickFalse);
960 }
cristy4c08aed2011-07-01 19:47:50 +0000961 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
962 cache_offset=0;
963 clone_offset=0;
964 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000965 {
cristy4c08aed2011-07-01 19:47:50 +0000966 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000967 {
cristy4c08aed2011-07-01 19:47:50 +0000968 blob=(unsigned char *) RelinquishMagickMemory(blob);
969 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000970 cache_info->cache_filename);
971 return(MagickFalse);
972 }
cristy4c08aed2011-07-01 19:47:50 +0000973 cache_offset=cache_info->offset;
974 }
975 if (clone_info->type == DiskCache)
976 {
cristy3dedf062011-07-02 14:07:40 +0000977 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000978 {
cristy4c08aed2011-07-01 19:47:50 +0000979 blob=(unsigned char *) RelinquishMagickMemory(blob);
980 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
981 clone_info->cache_filename);
982 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000983 }
cristy4c08aed2011-07-01 19:47:50 +0000984 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000985 }
986 /*
cristy4c08aed2011-07-01 19:47:50 +0000987 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000988 */
cristy4c08aed2011-07-01 19:47:50 +0000989 status=MagickTrue;
990 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
cristy4c08aed2011-07-01 19:47:50 +0000992 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000993 {
cristy9e0719b2011-12-29 03:45:45 +0000994 register ssize_t
995 i;
996
cristy3ed852e2009-09-05 21:47:34 +0000997 /*
cristy4c08aed2011-07-01 19:47:50 +0000998 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000999 */
cristyed231572011-07-14 02:18:59 +00001000 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001001 if (cache_info->type != DiskCache)
1002 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1003 length);
cristy3ed852e2009-09-05 21:47:34 +00001004 else
1005 {
cristy4c08aed2011-07-01 19:47:50 +00001006 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1007 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001008 {
cristy4c08aed2011-07-01 19:47:50 +00001009 status=MagickFalse;
1010 break;
cristy3ed852e2009-09-05 21:47:34 +00001011 }
1012 }
cristy4c08aed2011-07-01 19:47:50 +00001013 cache_offset+=length;
1014 if ((y < (ssize_t) clone_info->rows) &&
1015 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001016 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001017 {
cristy9e0719b2011-12-29 03:45:45 +00001018 PixelChannel
1019 channel;
1020
1021 PixelTrait
1022 traits;
1023
1024 ssize_t
1025 offset;
1026
cristy4c08aed2011-07-01 19:47:50 +00001027 /*
cristy3b8fe922011-12-29 18:56:23 +00001028 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001029 */
cristy9e0719b2011-12-29 03:45:45 +00001030 channel=clone_info->channel_map[i].channel;
1031 traits=cache_info->channel_map[channel].traits;
1032 if (traits == UndefinedPixelTrait)
1033 {
cristy0f4425e2011-12-31 20:33:02 +00001034 clone_offset+=sizeof(Quantum);
1035 continue;
cristy9e0719b2011-12-29 03:45:45 +00001036 }
cristy0f4425e2011-12-31 20:33:02 +00001037 offset=cache_info->channel_map[channel].offset;
1038 if (clone_info->type != DiskCache)
1039 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1040 blob+offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +00001041 else
1042 {
cristy0f4425e2011-12-31 20:33:02 +00001043 count=WritePixelCacheRegion(clone_info,clone_offset,
1044 sizeof(Quantum),blob+offset*sizeof(Quantum));
1045 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +00001046 {
cristy0f4425e2011-12-31 20:33:02 +00001047 status=MagickFalse;
1048 break;
cristy4c08aed2011-07-01 19:47:50 +00001049 }
1050 }
cristy9e0719b2011-12-29 03:45:45 +00001051 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001052 }
1053 }
cristyed231572011-07-14 02:18:59 +00001054 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001055 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1056 for ( ; x < (ssize_t) clone_info->columns; x++)
1057 {
1058 /*
cristy9e0719b2011-12-29 03:45:45 +00001059 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001060 */
1061 if (clone_info->type != DiskCache)
1062 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1063 length);
1064 else
1065 {
1066 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1067 if ((MagickSizeType) count != length)
1068 {
1069 status=MagickFalse;
1070 break;
1071 }
1072 }
1073 clone_offset+=length;
1074 }
1075 }
cristyed231572011-07-14 02:18:59 +00001076 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001077 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1078 for ( ; y < (ssize_t) clone_info->rows; y++)
1079 {
1080 /*
cristy9e0719b2011-12-29 03:45:45 +00001081 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001082 */
1083 for (x=0; x < (ssize_t) clone_info->columns; x++)
1084 {
1085 if (clone_info->type != DiskCache)
1086 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1087 length);
1088 else
1089 {
1090 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1091 if ((MagickSizeType) count != length)
1092 {
1093 status=MagickFalse;
1094 break;
1095 }
1096 }
1097 clone_offset+=length;
1098 }
1099 }
cristy9e0719b2011-12-29 03:45:45 +00001100 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001101 (clone_info->metacontent_extent != 0))
1102 {
1103 /*
1104 Clone metacontent.
1105 */
1106 for (y=0; y < (ssize_t) cache_info->rows; y++)
1107 {
1108 for (x=0; x < (ssize_t) cache_info->columns; x++)
1109 {
1110 /*
1111 Read a set of metacontent.
1112 */
1113 length=cache_info->metacontent_extent;
1114 if (cache_info->type != DiskCache)
1115 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1116 cache_offset,length);
1117 else
1118 {
1119 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1120 if ((MagickSizeType) count != length)
1121 {
1122 status=MagickFalse;
1123 break;
1124 }
1125 }
1126 cache_offset+=length;
1127 if ((y < (ssize_t) clone_info->rows) &&
1128 (x < (ssize_t) clone_info->columns))
1129 {
1130 /*
1131 Write a set of metacontent.
1132 */
1133 length=clone_info->metacontent_extent;
1134 if (clone_info->type != DiskCache)
1135 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1136 blob,length);
1137 else
1138 {
1139 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1140 blob);
1141 if ((MagickSizeType) count != length)
1142 {
1143 status=MagickFalse;
1144 break;
1145 }
1146 }
1147 clone_offset+=length;
1148 }
1149 }
1150 length=clone_info->metacontent_extent;
1151 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1152 for ( ; x < (ssize_t) clone_info->columns; x++)
1153 {
1154 /*
cristy9e0719b2011-12-29 03:45:45 +00001155 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001156 */
1157 if (clone_info->type != DiskCache)
1158 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1159 blob,length);
1160 else
1161 {
cristy208b1002011-08-07 18:51:50 +00001162 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001163 if ((MagickSizeType) count != length)
1164 {
1165 status=MagickFalse;
1166 break;
1167 }
1168 }
1169 clone_offset+=length;
1170 }
1171 }
1172 length=clone_info->metacontent_extent;
1173 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1174 for ( ; y < (ssize_t) clone_info->rows; y++)
1175 {
1176 /*
cristy9e0719b2011-12-29 03:45:45 +00001177 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001178 */
1179 for (x=0; x < (ssize_t) clone_info->columns; x++)
1180 {
1181 if (clone_info->type != DiskCache)
1182 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1183 blob,length);
1184 else
1185 {
1186 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1187 if ((MagickSizeType) count != length)
1188 {
1189 status=MagickFalse;
1190 break;
1191 }
1192 }
1193 clone_offset+=length;
1194 }
1195 }
1196 }
1197 if (clone_info->type == DiskCache)
1198 (void) ClosePixelCacheOnDisk(clone_info);
1199 if (cache_info->type == DiskCache)
1200 (void) ClosePixelCacheOnDisk(cache_info);
1201 blob=(unsigned char *) RelinquishMagickMemory(blob);
1202 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001203}
1204
1205static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1206 CacheInfo *cache_info,ExceptionInfo *exception)
1207{
cristy3dfccb22011-12-28 21:47:20 +00001208 PixelChannelMap
1209 *p,
1210 *q;
1211
cristy5a7fbfb2010-11-06 16:10:59 +00001212 if (cache_info->type == PingCache)
1213 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001214 p=cache_info->channel_map;
1215 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001216 if ((cache_info->columns == clone_info->columns) &&
1217 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001218 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001219 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001220 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1221 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1222 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001223}
1224
1225/*
1226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1227% %
1228% %
1229% %
1230+ C l o n e P i x e l C a c h e M e t h o d s %
1231% %
1232% %
1233% %
1234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1235%
1236% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1237% another.
1238%
1239% The format of the ClonePixelCacheMethods() method is:
1240%
1241% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1242%
1243% A description of each parameter follows:
1244%
1245% o clone: Specifies a pointer to a Cache structure.
1246%
1247% o cache: the pixel cache.
1248%
1249*/
cristya6577ff2011-09-02 19:54:26 +00001250MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001251{
1252 CacheInfo
1253 *cache_info,
1254 *source_info;
1255
1256 assert(clone != (Cache) NULL);
1257 source_info=(CacheInfo *) clone;
1258 assert(source_info->signature == MagickSignature);
1259 if (source_info->debug != MagickFalse)
1260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1261 source_info->filename);
1262 assert(cache != (Cache) NULL);
1263 cache_info=(CacheInfo *) cache;
1264 assert(cache_info->signature == MagickSignature);
1265 source_info->methods=cache_info->methods;
1266}
1267
1268/*
1269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1270% %
1271% %
1272% %
1273+ D e s t r o y I m a g e P i x e l C a c h e %
1274% %
1275% %
1276% %
1277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1278%
1279% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1280%
1281% The format of the DestroyImagePixelCache() method is:
1282%
1283% void DestroyImagePixelCache(Image *image)
1284%
1285% A description of each parameter follows:
1286%
1287% o image: the image.
1288%
1289*/
1290static void DestroyImagePixelCache(Image *image)
1291{
1292 assert(image != (Image *) NULL);
1293 assert(image->signature == MagickSignature);
1294 if (image->debug != MagickFalse)
1295 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1296 if (image->cache == (void *) NULL)
1297 return;
1298 image->cache=DestroyPixelCache(image->cache);
1299}
1300
1301/*
1302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303% %
1304% %
1305% %
1306+ D e s t r o y I m a g e P i x e l s %
1307% %
1308% %
1309% %
1310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311%
1312% DestroyImagePixels() deallocates memory associated with the pixel cache.
1313%
1314% The format of the DestroyImagePixels() method is:
1315%
1316% void DestroyImagePixels(Image *image)
1317%
1318% A description of each parameter follows:
1319%
1320% o image: the image.
1321%
1322*/
1323MagickExport void DestroyImagePixels(Image *image)
1324{
1325 CacheInfo
1326 *cache_info;
1327
1328 assert(image != (const Image *) NULL);
1329 assert(image->signature == MagickSignature);
1330 if (image->debug != MagickFalse)
1331 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1332 assert(image->cache != (Cache) NULL);
1333 cache_info=(CacheInfo *) image->cache;
1334 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001335 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1336 {
1337 cache_info->methods.destroy_pixel_handler(image);
1338 return;
1339 }
cristy2036f5c2010-09-19 21:18:17 +00001340 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001341}
1342
1343/*
1344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345% %
1346% %
1347% %
1348+ D e s t r o y P i x e l C a c h e %
1349% %
1350% %
1351% %
1352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353%
1354% DestroyPixelCache() deallocates memory associated with the pixel cache.
1355%
1356% The format of the DestroyPixelCache() method is:
1357%
1358% Cache DestroyPixelCache(Cache cache)
1359%
1360% A description of each parameter follows:
1361%
1362% o cache: the pixel cache.
1363%
1364*/
1365
1366static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1367{
1368 switch (cache_info->type)
1369 {
1370 case MemoryCache:
1371 {
1372 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001373 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001374 cache_info->pixels);
1375 else
cristy4c08aed2011-07-01 19:47:50 +00001376 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001377 (size_t) cache_info->length);
1378 RelinquishMagickResource(MemoryResource,cache_info->length);
1379 break;
1380 }
1381 case MapCache:
1382 {
cristy4c08aed2011-07-01 19:47:50 +00001383 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001384 cache_info->length);
1385 RelinquishMagickResource(MapResource,cache_info->length);
1386 }
1387 case DiskCache:
1388 {
1389 if (cache_info->file != -1)
1390 (void) ClosePixelCacheOnDisk(cache_info);
1391 RelinquishMagickResource(DiskResource,cache_info->length);
1392 break;
1393 }
1394 default:
1395 break;
1396 }
1397 cache_info->type=UndefinedCache;
1398 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001399 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001400}
1401
cristya6577ff2011-09-02 19:54:26 +00001402MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001403{
1404 CacheInfo
1405 *cache_info;
1406
cristy3ed852e2009-09-05 21:47:34 +00001407 assert(cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) cache;
1409 assert(cache_info->signature == MagickSignature);
1410 if (cache_info->debug != MagickFalse)
1411 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1412 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001413 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001414 cache_info->reference_count--;
1415 if (cache_info->reference_count != 0)
1416 {
cristyf84a1932010-01-03 18:00:18 +00001417 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001418 return((Cache) NULL);
1419 }
cristyf84a1932010-01-03 18:00:18 +00001420 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001421 if (cache_resources != (SplayTreeInfo *) NULL)
1422 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001423 if (cache_info->debug != MagickFalse)
1424 {
1425 char
1426 message[MaxTextExtent];
1427
cristyb51dff52011-05-19 16:55:47 +00001428 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001429 cache_info->filename);
1430 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1431 }
cristyc2e1bdd2009-09-10 23:43:34 +00001432 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1433 (cache_info->type != DiskCache)))
1434 RelinquishPixelCachePixels(cache_info);
1435 else
1436 {
1437 RelinquishPixelCachePixels(cache_info);
1438 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1439 }
cristy3ed852e2009-09-05 21:47:34 +00001440 *cache_info->cache_filename='\0';
1441 if (cache_info->nexus_info != (NexusInfo **) NULL)
1442 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1443 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001444 if (cache_info->random_info != (RandomInfo *) NULL)
1445 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001446 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1447 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1448 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1449 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001450 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001451 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001452 cache=(Cache) NULL;
1453 return(cache);
1454}
1455
1456/*
1457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458% %
1459% %
1460% %
1461+ D e s t r o y P i x e l C a c h e N e x u s %
1462% %
1463% %
1464% %
1465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466%
1467% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1468%
1469% The format of the DestroyPixelCacheNexus() method is:
1470%
1471% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001472% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001473%
1474% A description of each parameter follows:
1475%
1476% o nexus_info: the nexus to destroy.
1477%
1478% o number_threads: the number of nexus threads.
1479%
1480*/
1481
1482static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1483{
1484 if (nexus_info->mapped == MagickFalse)
1485 (void) RelinquishMagickMemory(nexus_info->cache);
1486 else
1487 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001488 nexus_info->cache=(Quantum *) NULL;
1489 nexus_info->pixels=(Quantum *) NULL;
1490 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001491 nexus_info->length=0;
1492 nexus_info->mapped=MagickFalse;
1493}
1494
cristya6577ff2011-09-02 19:54:26 +00001495MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001496 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001497{
cristybb503372010-05-27 20:51:26 +00001498 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001499 i;
1500
1501 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001502 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001503 {
cristy4c08aed2011-07-01 19:47:50 +00001504 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001505 RelinquishCacheNexusPixels(nexus_info[i]);
1506 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001507 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001508 }
cristyb41ee102010-10-04 16:46:15 +00001509 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001510 return(nexus_info);
1511}
1512
1513/*
1514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1515% %
1516% %
1517% %
cristy4c08aed2011-07-01 19:47:50 +00001518% 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 +00001519% %
1520% %
1521% %
1522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1523%
cristy4c08aed2011-07-01 19:47:50 +00001524% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1525% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1526% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001527%
cristy4c08aed2011-07-01 19:47:50 +00001528% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001529%
cristy4c08aed2011-07-01 19:47:50 +00001530% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001531%
1532% A description of each parameter follows:
1533%
1534% o image: the image.
1535%
1536*/
cristy4c08aed2011-07-01 19:47:50 +00001537MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001538{
1539 CacheInfo
1540 *cache_info;
1541
cristy5c9e6f22010-09-17 17:31:01 +00001542 const int
1543 id = GetOpenMPThreadId();
1544
cristy4c08aed2011-07-01 19:47:50 +00001545 void
1546 *metacontent;
1547
cristye7cc7cf2010-09-21 13:26:47 +00001548 assert(image != (const Image *) NULL);
1549 assert(image->signature == MagickSignature);
1550 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001551 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001552 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001553 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1554 (GetAuthenticMetacontentFromHandler) NULL)
1555 {
1556 metacontent=cache_info->methods.
1557 get_authentic_metacontent_from_handler(image);
1558 return(metacontent);
1559 }
cristy6ebe97c2010-07-03 01:17:28 +00001560 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001561 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1562 cache_info->nexus_info[id]);
1563 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001564}
1565
1566/*
1567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568% %
1569% %
1570% %
cristy4c08aed2011-07-01 19:47:50 +00001571+ 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 +00001572% %
1573% %
1574% %
1575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1576%
cristy4c08aed2011-07-01 19:47:50 +00001577% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1578% with the last call to QueueAuthenticPixelsCache() or
1579% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001580%
cristy4c08aed2011-07-01 19:47:50 +00001581% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001582%
cristy4c08aed2011-07-01 19:47:50 +00001583% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001584%
1585% A description of each parameter follows:
1586%
1587% o image: the image.
1588%
1589*/
cristy4c08aed2011-07-01 19:47:50 +00001590static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001591{
1592 CacheInfo
1593 *cache_info;
1594
cristy2036f5c2010-09-19 21:18:17 +00001595 const int
1596 id = GetOpenMPThreadId();
1597
cristy4c08aed2011-07-01 19:47:50 +00001598 void
1599 *metacontent;
1600
cristy3ed852e2009-09-05 21:47:34 +00001601 assert(image != (const Image *) NULL);
1602 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001603 assert(image->cache != (Cache) NULL);
1604 cache_info=(CacheInfo *) image->cache;
1605 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001606 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001607 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1608 cache_info->nexus_info[id]);
1609 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001610}
1611
1612/*
1613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1614% %
1615% %
1616% %
1617+ 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 %
1618% %
1619% %
1620% %
1621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1622%
1623% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1624% disk pixel cache as defined by the geometry parameters. A pointer to the
1625% pixels is returned if the pixels are transferred, otherwise a NULL is
1626% returned.
1627%
1628% The format of the GetAuthenticPixelCacheNexus() method is:
1629%
cristy4c08aed2011-07-01 19:47:50 +00001630% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001631% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001632% NexusInfo *nexus_info,ExceptionInfo *exception)
1633%
1634% A description of each parameter follows:
1635%
1636% o image: the image.
1637%
1638% o x,y,columns,rows: These values define the perimeter of a region of
1639% pixels.
1640%
1641% o nexus_info: the cache nexus to return.
1642%
1643% o exception: return any errors or warnings in this structure.
1644%
1645*/
1646
cristy4c08aed2011-07-01 19:47:50 +00001647static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001648 NexusInfo *nexus_info)
1649{
cristy4c08aed2011-07-01 19:47:50 +00001650 MagickBooleanType
1651 status;
1652
cristy3ed852e2009-09-05 21:47:34 +00001653 MagickOffsetType
1654 offset;
1655
cristy73724512010-04-12 14:43:14 +00001656 if (cache_info->type == PingCache)
1657 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001658 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1659 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001660 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001661 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001662 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001663}
1664
cristya6577ff2011-09-02 19:54:26 +00001665MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001666 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001667 NexusInfo *nexus_info,ExceptionInfo *exception)
1668{
1669 CacheInfo
1670 *cache_info;
1671
cristy4c08aed2011-07-01 19:47:50 +00001672 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001673 *q;
cristy3ed852e2009-09-05 21:47:34 +00001674
1675 /*
1676 Transfer pixels from the cache.
1677 */
1678 assert(image != (Image *) NULL);
1679 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001680 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001681 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001682 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001683 cache_info=(CacheInfo *) image->cache;
1684 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001685 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001686 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001687 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001688 return((Quantum *) NULL);
1689 if (cache_info->metacontent_extent != 0)
1690 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1691 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001692 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001693}
1694
1695/*
1696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1697% %
1698% %
1699% %
1700+ 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 %
1701% %
1702% %
1703% %
1704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1705%
1706% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1707% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1708%
1709% The format of the GetAuthenticPixelsFromCache() method is:
1710%
cristy4c08aed2011-07-01 19:47:50 +00001711% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001712%
1713% A description of each parameter follows:
1714%
1715% o image: the image.
1716%
1717*/
cristy4c08aed2011-07-01 19:47:50 +00001718static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001719{
1720 CacheInfo
1721 *cache_info;
1722
cristy5c9e6f22010-09-17 17:31:01 +00001723 const int
1724 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001725
cristye7cc7cf2010-09-21 13:26:47 +00001726 assert(image != (const Image *) NULL);
1727 assert(image->signature == MagickSignature);
1728 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001729 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001730 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001731 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001732 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001733}
1734
1735/*
1736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1737% %
1738% %
1739% %
1740% G e t A u t h e n t i c P i x e l Q u e u e %
1741% %
1742% %
1743% %
1744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745%
cristy4c08aed2011-07-01 19:47:50 +00001746% GetAuthenticPixelQueue() returns the authentic pixels associated
1747% corresponding with the last call to QueueAuthenticPixels() or
1748% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001749%
1750% The format of the GetAuthenticPixelQueue() method is:
1751%
cristy4c08aed2011-07-01 19:47:50 +00001752% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001753%
1754% A description of each parameter follows:
1755%
1756% o image: the image.
1757%
1758*/
cristy4c08aed2011-07-01 19:47:50 +00001759MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001760{
1761 CacheInfo
1762 *cache_info;
1763
cristy2036f5c2010-09-19 21:18:17 +00001764 const int
1765 id = GetOpenMPThreadId();
1766
cristy3ed852e2009-09-05 21:47:34 +00001767 assert(image != (const Image *) NULL);
1768 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001769 assert(image->cache != (Cache) NULL);
1770 cache_info=(CacheInfo *) image->cache;
1771 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001772 if (cache_info->methods.get_authentic_pixels_from_handler !=
1773 (GetAuthenticPixelsFromHandler) NULL)
1774 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001775 assert(id < (int) cache_info->number_threads);
1776 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001777}
1778
1779/*
1780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1781% %
1782% %
1783% %
1784% G e t A u t h e n t i c P i x e l s %
1785% %
1786% %
cristy4c08aed2011-07-01 19:47:50 +00001787% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001788%
1789% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001790% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001791% representing the region is returned, otherwise NULL is returned.
1792%
1793% The returned pointer may point to a temporary working copy of the pixels
1794% or it may point to the original pixels in memory. Performance is maximized
1795% if the selected region is part of one row, or one or more full rows, since
1796% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001797% if the image is in memory, or in a memory-mapped file. The returned pointer
1798% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001799%
1800% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001801% Quantum. If the image has corresponding metacontent,call
1802% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1803% meta-content corresponding to the region. Once the Quantum array has
1804% been updated, the changes must be saved back to the underlying image using
1805% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001806%
1807% The format of the GetAuthenticPixels() method is:
1808%
cristy4c08aed2011-07-01 19:47:50 +00001809% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001810% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001811% ExceptionInfo *exception)
1812%
1813% A description of each parameter follows:
1814%
1815% o image: the image.
1816%
1817% o x,y,columns,rows: These values define the perimeter of a region of
1818% pixels.
1819%
1820% o exception: return any errors or warnings in this structure.
1821%
1822*/
cristy4c08aed2011-07-01 19:47:50 +00001823MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001824 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001825 ExceptionInfo *exception)
1826{
1827 CacheInfo
1828 *cache_info;
1829
cristy2036f5c2010-09-19 21:18:17 +00001830 const int
1831 id = GetOpenMPThreadId();
1832
cristy4c08aed2011-07-01 19:47:50 +00001833 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001834 *q;
cristy4c08aed2011-07-01 19:47:50 +00001835
cristy3ed852e2009-09-05 21:47:34 +00001836 assert(image != (Image *) NULL);
1837 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001838 assert(image->cache != (Cache) NULL);
1839 cache_info=(CacheInfo *) image->cache;
1840 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001841 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001842 (GetAuthenticPixelsHandler) NULL)
1843 {
cristyacd2ed22011-08-30 01:44:23 +00001844 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1845 exception);
1846 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001847 }
cristy2036f5c2010-09-19 21:18:17 +00001848 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001849 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001850 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001851 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001852}
1853
1854/*
1855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1856% %
1857% %
1858% %
1859+ G e t A u t h e n t i c P i x e l s C a c h e %
1860% %
1861% %
1862% %
1863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1864%
1865% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1866% as defined by the geometry parameters. A pointer to the pixels is returned
1867% if the pixels are transferred, otherwise a NULL is returned.
1868%
1869% The format of the GetAuthenticPixelsCache() method is:
1870%
cristy4c08aed2011-07-01 19:47:50 +00001871% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001872% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001873% ExceptionInfo *exception)
1874%
1875% A description of each parameter follows:
1876%
1877% o image: the image.
1878%
1879% o x,y,columns,rows: These values define the perimeter of a region of
1880% pixels.
1881%
1882% o exception: return any errors or warnings in this structure.
1883%
1884*/
cristy4c08aed2011-07-01 19:47:50 +00001885static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001886 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001887 ExceptionInfo *exception)
1888{
1889 CacheInfo
1890 *cache_info;
1891
cristy5c9e6f22010-09-17 17:31:01 +00001892 const int
1893 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001894
cristy4c08aed2011-07-01 19:47:50 +00001895 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001896 *q;
cristy4c08aed2011-07-01 19:47:50 +00001897
cristye7cc7cf2010-09-21 13:26:47 +00001898 assert(image != (const Image *) NULL);
1899 assert(image->signature == MagickSignature);
1900 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001901 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001902 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001903 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001904 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001905 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001906 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001907 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001908 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001909}
1910
1911/*
1912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1913% %
1914% %
1915% %
1916+ G e t I m a g e E x t e n t %
1917% %
1918% %
1919% %
1920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1921%
cristy4c08aed2011-07-01 19:47:50 +00001922% GetImageExtent() returns the extent of the pixels associated corresponding
1923% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001924%
1925% The format of the GetImageExtent() method is:
1926%
1927% MagickSizeType GetImageExtent(const Image *image)
1928%
1929% A description of each parameter follows:
1930%
1931% o image: the image.
1932%
1933*/
1934MagickExport MagickSizeType GetImageExtent(const Image *image)
1935{
1936 CacheInfo
1937 *cache_info;
1938
cristy5c9e6f22010-09-17 17:31:01 +00001939 const int
1940 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001941
cristy3ed852e2009-09-05 21:47:34 +00001942 assert(image != (Image *) NULL);
1943 assert(image->signature == MagickSignature);
1944 if (image->debug != MagickFalse)
1945 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1946 assert(image->cache != (Cache) NULL);
1947 cache_info=(CacheInfo *) image->cache;
1948 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001949 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001950 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001951}
1952
1953/*
1954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1955% %
1956% %
1957% %
1958+ G e t I m a g e P i x e l C a c h e %
1959% %
1960% %
1961% %
1962%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1963%
1964% GetImagePixelCache() ensures that there is only a single reference to the
1965% pixel cache to be modified, updating the provided cache pointer to point to
1966% a clone of the original pixel cache if necessary.
1967%
1968% The format of the GetImagePixelCache method is:
1969%
1970% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1971% ExceptionInfo *exception)
1972%
1973% A description of each parameter follows:
1974%
1975% o image: the image.
1976%
1977% o clone: any value other than MagickFalse clones the cache pixels.
1978%
1979% o exception: return any errors or warnings in this structure.
1980%
1981*/
cristyaf894d72011-08-06 23:03:10 +00001982
cristy3ed852e2009-09-05 21:47:34 +00001983static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1984{
1985 CacheInfo
1986 *cache_info;
1987
cristy9e0719b2011-12-29 03:45:45 +00001988 PixelChannelMap
1989 *p,
1990 *q;
1991
cristy3ed852e2009-09-05 21:47:34 +00001992 /*
1993 Does the image match the pixel cache morphology?
1994 */
1995 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001996 p=image->channel_map;
1997 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001998 if ((image->storage_class != cache_info->storage_class) ||
1999 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002000 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002001 (image->columns != cache_info->columns) ||
2002 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002003 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002004 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002005 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002006 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2007 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2008 return(MagickFalse);
2009 return(MagickTrue);
2010}
2011
cristycd01fae2011-08-06 23:52:42 +00002012static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2013 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002014{
2015 CacheInfo
2016 *cache_info;
2017
cristy3ed852e2009-09-05 21:47:34 +00002018 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002019 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002020 status;
2021
cristy50a10922010-02-15 18:35:25 +00002022 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002023 cpu_throttle = 0,
2024 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002025 time_limit = 0;
2026
cristy1ea34962010-07-01 19:49:21 +00002027 static time_t
cristy208b1002011-08-07 18:51:50 +00002028 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002029
cristyc4f9f132010-03-04 18:50:01 +00002030 status=MagickTrue;
2031 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002032 if (cpu_throttle == 0)
2033 {
2034 char
2035 *limit;
2036
2037 /*
2038 Set CPU throttle in milleseconds.
2039 */
2040 cpu_throttle=MagickResourceInfinity;
2041 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2042 if (limit == (char *) NULL)
2043 limit=GetPolicyValue("throttle");
2044 if (limit != (char *) NULL)
2045 {
2046 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2047 limit=DestroyString(limit);
2048 }
2049 }
2050 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2051 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002052 if (time_limit == 0)
2053 {
cristy6ebe97c2010-07-03 01:17:28 +00002054 /*
2055 Set the exire time in seconds.
2056 */
cristy1ea34962010-07-01 19:49:21 +00002057 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002058 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002059 }
2060 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002061 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002062 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002063 assert(image->cache != (Cache) NULL);
2064 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002065 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002066 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002067 {
cristyceb55ee2010-11-06 16:05:49 +00002068 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002069 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002070 {
cristyceb55ee2010-11-06 16:05:49 +00002071 Image
2072 clone_image;
2073
2074 CacheInfo
2075 *clone_info;
2076
2077 /*
2078 Clone pixel cache.
2079 */
2080 clone_image=(*image);
2081 clone_image.semaphore=AllocateSemaphoreInfo();
2082 clone_image.reference_count=1;
2083 clone_image.cache=ClonePixelCache(cache_info);
2084 clone_info=(CacheInfo *) clone_image.cache;
2085 status=OpenPixelCache(&clone_image,IOMode,exception);
2086 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002087 {
cristy5a7fbfb2010-11-06 16:10:59 +00002088 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002089 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002090 if (status != MagickFalse)
2091 {
cristy979bf772011-08-08 00:04:15 +00002092 if (cache_info->mode == ReadMode)
2093 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002094 destroy=MagickTrue;
2095 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002096 }
2097 }
cristyceb55ee2010-11-06 16:05:49 +00002098 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002099 }
cristyceb55ee2010-11-06 16:05:49 +00002100 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002101 }
cristy4320e0e2009-09-10 15:00:08 +00002102 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002103 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002104 if (status != MagickFalse)
2105 {
2106 /*
2107 Ensure the image matches the pixel cache morphology.
2108 */
2109 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002110 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002111 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2112 status=OpenPixelCache(image,IOMode,exception);
2113 }
cristyf84a1932010-01-03 18:00:18 +00002114 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002115 if (status == MagickFalse)
2116 return((Cache) NULL);
2117 return(image->cache);
2118}
2119
2120/*
2121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2122% %
2123% %
2124% %
2125% G e t O n e A u t h e n t i c P i x e l %
2126% %
2127% %
2128% %
2129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2130%
2131% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2132% location. The image background color is returned if an error occurs.
2133%
2134% The format of the GetOneAuthenticPixel() method is:
2135%
cristybb503372010-05-27 20:51:26 +00002136% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002137% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002138%
2139% A description of each parameter follows:
2140%
2141% o image: the image.
2142%
2143% o x,y: These values define the location of the pixel to return.
2144%
2145% o pixel: return a pixel at the specified (x,y) location.
2146%
2147% o exception: return any errors or warnings in this structure.
2148%
2149*/
cristyacbbb7c2010-06-30 18:56:48 +00002150MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002151 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002152{
2153 CacheInfo
2154 *cache_info;
2155
cristy4c08aed2011-07-01 19:47:50 +00002156 register Quantum
2157 *q;
cristy2036f5c2010-09-19 21:18:17 +00002158
cristy2ed42f62011-10-02 19:49:57 +00002159 register ssize_t
2160 i;
2161
cristy3ed852e2009-09-05 21:47:34 +00002162 assert(image != (Image *) NULL);
2163 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002164 assert(image->cache != (Cache) NULL);
2165 cache_info=(CacheInfo *) image->cache;
2166 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002167 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002168 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2169 (GetOneAuthenticPixelFromHandler) NULL)
2170 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2171 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002172 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2173 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002174 {
cristy9e0719b2011-12-29 03:45:45 +00002175 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2176 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2177 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2178 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2179 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002180 return(MagickFalse);
2181 }
2182 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2183 {
2184 PixelChannel
2185 channel;
2186
cristye2a912b2011-12-05 20:02:07 +00002187 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002188 pixel[channel]=q[i];
2189 }
cristy2036f5c2010-09-19 21:18:17 +00002190 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002191}
2192
2193/*
2194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2195% %
2196% %
2197% %
2198+ 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 %
2199% %
2200% %
2201% %
2202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2203%
2204% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2205% location. The image background color is returned if an error occurs.
2206%
2207% The format of the GetOneAuthenticPixelFromCache() method is:
2208%
2209% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002210% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002211% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002212%
2213% A description of each parameter follows:
2214%
2215% o image: the image.
2216%
2217% o x,y: These values define the location of the pixel to return.
2218%
2219% o pixel: return a pixel at the specified (x,y) location.
2220%
2221% o exception: return any errors or warnings in this structure.
2222%
2223*/
2224static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002225 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002226{
cristy098f78c2010-09-23 17:28:44 +00002227 CacheInfo
2228 *cache_info;
2229
2230 const int
2231 id = GetOpenMPThreadId();
2232
cristy4c08aed2011-07-01 19:47:50 +00002233 register Quantum
2234 *q;
cristy3ed852e2009-09-05 21:47:34 +00002235
cristy2ed42f62011-10-02 19:49:57 +00002236 register ssize_t
2237 i;
2238
cristy0158a4b2010-09-20 13:59:45 +00002239 assert(image != (const Image *) NULL);
2240 assert(image->signature == MagickSignature);
2241 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002242 cache_info=(CacheInfo *) image->cache;
2243 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002244 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002245 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002246 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2247 exception);
2248 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002249 {
cristy9e0719b2011-12-29 03:45:45 +00002250 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2251 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2252 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2253 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2254 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002255 return(MagickFalse);
2256 }
2257 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2258 {
2259 PixelChannel
2260 channel;
2261
cristye2a912b2011-12-05 20:02:07 +00002262 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002263 pixel[channel]=q[i];
2264 }
cristy3ed852e2009-09-05 21:47:34 +00002265 return(MagickTrue);
2266}
2267
2268/*
2269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270% %
2271% %
2272% %
cristy3ed852e2009-09-05 21:47:34 +00002273% G e t O n e V i r t u a l P i x e l %
2274% %
2275% %
2276% %
2277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278%
2279% GetOneVirtualPixel() returns a single virtual pixel at the specified
2280% (x,y) location. The image background color is returned if an error occurs.
2281% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2282%
2283% The format of the GetOneVirtualPixel() method is:
2284%
cristybb503372010-05-27 20:51:26 +00002285% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002286% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002287%
2288% A description of each parameter follows:
2289%
2290% o image: the image.
2291%
2292% o x,y: These values define the location of the pixel to return.
2293%
2294% o pixel: return a pixel at the specified (x,y) location.
2295%
2296% o exception: return any errors or warnings in this structure.
2297%
2298*/
2299MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002300 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002301{
cristy3ed852e2009-09-05 21:47:34 +00002302 CacheInfo
2303 *cache_info;
2304
cristy0158a4b2010-09-20 13:59:45 +00002305 const int
2306 id = GetOpenMPThreadId();
2307
cristy4c08aed2011-07-01 19:47:50 +00002308 const Quantum
2309 *p;
cristy2036f5c2010-09-19 21:18:17 +00002310
cristy2ed42f62011-10-02 19:49:57 +00002311 register ssize_t
2312 i;
2313
cristy3ed852e2009-09-05 21:47:34 +00002314 assert(image != (const Image *) NULL);
2315 assert(image->signature == MagickSignature);
2316 assert(image->cache != (Cache) NULL);
2317 cache_info=(CacheInfo *) image->cache;
2318 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002319 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002320 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2321 (GetOneVirtualPixelFromHandler) NULL)
2322 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2323 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002324 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002325 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002326 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002327 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002328 {
cristy9e0719b2011-12-29 03:45:45 +00002329 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2330 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2331 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2332 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2333 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002334 return(MagickFalse);
2335 }
2336 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2337 {
2338 PixelChannel
2339 channel;
2340
cristye2a912b2011-12-05 20:02:07 +00002341 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002342 pixel[channel]=p[i];
2343 }
cristy2036f5c2010-09-19 21:18:17 +00002344 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002345}
2346
2347/*
2348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2349% %
2350% %
2351% %
2352+ 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 %
2353% %
2354% %
2355% %
2356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2357%
2358% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2359% specified (x,y) location. The image background color is returned if an
2360% error occurs.
2361%
2362% The format of the GetOneVirtualPixelFromCache() method is:
2363%
2364% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002365% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002366% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002367%
2368% A description of each parameter follows:
2369%
2370% o image: the image.
2371%
2372% o virtual_pixel_method: the virtual pixel method.
2373%
2374% o x,y: These values define the location of the pixel to return.
2375%
2376% o pixel: return a pixel at the specified (x,y) location.
2377%
2378% o exception: return any errors or warnings in this structure.
2379%
2380*/
2381static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002382 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002383 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002384{
cristy0158a4b2010-09-20 13:59:45 +00002385 CacheInfo
2386 *cache_info;
2387
2388 const int
2389 id = GetOpenMPThreadId();
2390
cristy4c08aed2011-07-01 19:47:50 +00002391 const Quantum
2392 *p;
cristy3ed852e2009-09-05 21:47:34 +00002393
cristy2ed42f62011-10-02 19:49:57 +00002394 register ssize_t
2395 i;
2396
cristye7cc7cf2010-09-21 13:26:47 +00002397 assert(image != (const Image *) NULL);
2398 assert(image->signature == MagickSignature);
2399 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002400 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002401 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002402 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002403 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002404 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002405 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002406 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002407 {
cristy9e0719b2011-12-29 03:45:45 +00002408 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2409 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2410 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2411 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2412 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002413 return(MagickFalse);
2414 }
2415 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2416 {
2417 PixelChannel
2418 channel;
2419
cristye2a912b2011-12-05 20:02:07 +00002420 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002421 pixel[channel]=p[i];
2422 }
cristy3ed852e2009-09-05 21:47:34 +00002423 return(MagickTrue);
2424}
2425
2426/*
2427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2428% %
2429% %
2430% %
cristy3aa93752011-12-18 15:54:24 +00002431% G e t O n e V i r t u a l P i x e l I n f o %
2432% %
2433% %
2434% %
2435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2436%
2437% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2438% location. The image background color is returned if an error occurs. If
2439% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2440%
2441% The format of the GetOneVirtualPixelInfo() method is:
2442%
2443% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2444% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2445% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2446%
2447% A description of each parameter follows:
2448%
2449% o image: the image.
2450%
2451% o virtual_pixel_method: the virtual pixel method.
2452%
2453% o x,y: these values define the location of the pixel to return.
2454%
2455% o pixel: return a pixel at the specified (x,y) location.
2456%
2457% o exception: return any errors or warnings in this structure.
2458%
2459*/
2460MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2461 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2462 PixelInfo *pixel,ExceptionInfo *exception)
2463{
2464 CacheInfo
2465 *cache_info;
2466
2467 const int
2468 id = GetOpenMPThreadId();
2469
2470 register const Quantum
2471 *p;
2472
2473 assert(image != (const Image *) NULL);
2474 assert(image->signature == MagickSignature);
2475 assert(image->cache != (Cache) NULL);
2476 cache_info=(CacheInfo *) image->cache;
2477 assert(cache_info->signature == MagickSignature);
2478 assert(id < (int) cache_info->number_threads);
2479 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2480 cache_info->nexus_info[id],exception);
2481 GetPixelInfo(image,pixel);
2482 if (p == (const Quantum *) NULL)
2483 return(MagickFalse);
2484 GetPixelInfoPixel(image,p,pixel);
2485 return(MagickTrue);
2486}
2487
2488/*
2489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2490% %
2491% %
2492% %
cristy3ed852e2009-09-05 21:47:34 +00002493+ G e t P i x e l C a c h e C o l o r s p a c e %
2494% %
2495% %
2496% %
2497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2498%
2499% GetPixelCacheColorspace() returns the class type of the pixel cache.
2500%
2501% The format of the GetPixelCacheColorspace() method is:
2502%
2503% Colorspace GetPixelCacheColorspace(Cache cache)
2504%
2505% A description of each parameter follows:
2506%
2507% o cache: the pixel cache.
2508%
2509*/
cristya6577ff2011-09-02 19:54:26 +00002510MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002511{
2512 CacheInfo
2513 *cache_info;
2514
2515 assert(cache != (Cache) NULL);
2516 cache_info=(CacheInfo *) cache;
2517 assert(cache_info->signature == MagickSignature);
2518 if (cache_info->debug != MagickFalse)
2519 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2520 cache_info->filename);
2521 return(cache_info->colorspace);
2522}
2523
2524/*
2525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2526% %
2527% %
2528% %
2529+ G e t P i x e l C a c h e M e t h o d s %
2530% %
2531% %
2532% %
2533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2534%
2535% GetPixelCacheMethods() initializes the CacheMethods structure.
2536%
2537% The format of the GetPixelCacheMethods() method is:
2538%
2539% void GetPixelCacheMethods(CacheMethods *cache_methods)
2540%
2541% A description of each parameter follows:
2542%
2543% o cache_methods: Specifies a pointer to a CacheMethods structure.
2544%
2545*/
cristya6577ff2011-09-02 19:54:26 +00002546MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002547{
2548 assert(cache_methods != (CacheMethods *) NULL);
2549 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2550 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2551 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002552 cache_methods->get_virtual_metacontent_from_handler=
2553 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002554 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2555 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002556 cache_methods->get_authentic_metacontent_from_handler=
2557 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002558 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2559 cache_methods->get_one_authentic_pixel_from_handler=
2560 GetOneAuthenticPixelFromCache;
2561 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2562 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2563 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2564}
2565
2566/*
2567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2568% %
2569% %
2570% %
2571+ G e t P i x e l C a c h e N e x u s E x t e n t %
2572% %
2573% %
2574% %
2575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2576%
cristy4c08aed2011-07-01 19:47:50 +00002577% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2578% corresponding with the last call to SetPixelCacheNexusPixels() or
2579% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002580%
2581% The format of the GetPixelCacheNexusExtent() method is:
2582%
2583% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2584% NexusInfo *nexus_info)
2585%
2586% A description of each parameter follows:
2587%
2588% o nexus_info: the nexus info.
2589%
2590*/
cristya6577ff2011-09-02 19:54:26 +00002591MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002592 NexusInfo *nexus_info)
2593{
2594 CacheInfo
2595 *cache_info;
2596
2597 MagickSizeType
2598 extent;
2599
cristy9f027d12011-09-21 01:17:17 +00002600 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002601 cache_info=(CacheInfo *) cache;
2602 assert(cache_info->signature == MagickSignature);
2603 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2604 if (extent == 0)
2605 return((MagickSizeType) cache_info->columns*cache_info->rows);
2606 return(extent);
2607}
2608
2609/*
2610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2611% %
2612% %
2613% %
cristy4c08aed2011-07-01 19:47:50 +00002614+ 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 +00002615% %
2616% %
2617% %
2618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2619%
cristy4c08aed2011-07-01 19:47:50 +00002620% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2621% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002622%
cristy4c08aed2011-07-01 19:47:50 +00002623% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002624%
cristy4c08aed2011-07-01 19:47:50 +00002625% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002626% NexusInfo *nexus_info)
2627%
2628% A description of each parameter follows:
2629%
2630% o cache: the pixel cache.
2631%
cristy4c08aed2011-07-01 19:47:50 +00002632% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002633%
2634*/
cristya6577ff2011-09-02 19:54:26 +00002635MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002636 NexusInfo *nexus_info)
2637{
2638 CacheInfo
2639 *cache_info;
2640
cristy9f027d12011-09-21 01:17:17 +00002641 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002642 cache_info=(CacheInfo *) cache;
2643 assert(cache_info->signature == MagickSignature);
2644 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002645 return((void *) NULL);
2646 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002647}
2648
2649/*
2650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2651% %
2652% %
2653% %
2654+ G e t P i x e l C a c h e N e x u s P i x e l s %
2655% %
2656% %
2657% %
2658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2659%
2660% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2661% cache nexus.
2662%
2663% The format of the GetPixelCacheNexusPixels() method is:
2664%
cristy4c08aed2011-07-01 19:47:50 +00002665% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002666% NexusInfo *nexus_info)
2667%
2668% A description of each parameter follows:
2669%
2670% o cache: the pixel cache.
2671%
2672% o nexus_info: the cache nexus to return the pixels.
2673%
2674*/
cristya6577ff2011-09-02 19:54:26 +00002675MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002676 NexusInfo *nexus_info)
2677{
2678 CacheInfo
2679 *cache_info;
2680
cristy9f027d12011-09-21 01:17:17 +00002681 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002682 cache_info=(CacheInfo *) cache;
2683 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002684 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002685 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002686 return(nexus_info->pixels);
2687}
2688
2689/*
2690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2691% %
2692% %
2693% %
cristy056ba772010-01-02 23:33:54 +00002694+ G e t P i x e l C a c h e P i x e l s %
2695% %
2696% %
2697% %
2698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2699%
2700% GetPixelCachePixels() returns the pixels associated with the specified image.
2701%
2702% The format of the GetPixelCachePixels() method is:
2703%
cristyf84a1932010-01-03 18:00:18 +00002704% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2705% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002706%
2707% A description of each parameter follows:
2708%
2709% o image: the image.
2710%
2711% o length: the pixel cache length.
2712%
cristyf84a1932010-01-03 18:00:18 +00002713% o exception: return any errors or warnings in this structure.
2714%
cristy056ba772010-01-02 23:33:54 +00002715*/
cristyd1dd6e42011-09-04 01:46:08 +00002716MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002717 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002718{
2719 CacheInfo
2720 *cache_info;
2721
2722 assert(image != (const Image *) NULL);
2723 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002724 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002725 assert(length != (MagickSizeType *) NULL);
2726 assert(exception != (ExceptionInfo *) NULL);
2727 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002728 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002729 assert(cache_info->signature == MagickSignature);
2730 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002731 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002732 return((void *) NULL);
2733 *length=cache_info->length;
2734 return((void *) cache_info->pixels);
2735}
2736
2737/*
2738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2739% %
2740% %
2741% %
cristyb32b90a2009-09-07 21:45:48 +00002742+ 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 +00002743% %
2744% %
2745% %
2746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2747%
2748% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2749%
2750% The format of the GetPixelCacheStorageClass() method is:
2751%
2752% ClassType GetPixelCacheStorageClass(Cache cache)
2753%
2754% A description of each parameter follows:
2755%
2756% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2757%
2758% o cache: the pixel cache.
2759%
2760*/
cristya6577ff2011-09-02 19:54:26 +00002761MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002762{
2763 CacheInfo
2764 *cache_info;
2765
2766 assert(cache != (Cache) NULL);
2767 cache_info=(CacheInfo *) cache;
2768 assert(cache_info->signature == MagickSignature);
2769 if (cache_info->debug != MagickFalse)
2770 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2771 cache_info->filename);
2772 return(cache_info->storage_class);
2773}
2774
2775/*
2776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777% %
2778% %
2779% %
cristyb32b90a2009-09-07 21:45:48 +00002780+ G e t P i x e l C a c h e T i l e S i z e %
2781% %
2782% %
2783% %
2784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2785%
2786% GetPixelCacheTileSize() returns the pixel cache tile size.
2787%
2788% The format of the GetPixelCacheTileSize() method is:
2789%
cristybb503372010-05-27 20:51:26 +00002790% void GetPixelCacheTileSize(const Image *image,size_t *width,
2791% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002792%
2793% A description of each parameter follows:
2794%
2795% o image: the image.
2796%
2797% o width: the optimize cache tile width in pixels.
2798%
2799% o height: the optimize cache tile height in pixels.
2800%
2801*/
cristya6577ff2011-09-02 19:54:26 +00002802MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002803 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002804{
cristy4c08aed2011-07-01 19:47:50 +00002805 CacheInfo
2806 *cache_info;
2807
cristyb32b90a2009-09-07 21:45:48 +00002808 assert(image != (Image *) NULL);
2809 assert(image->signature == MagickSignature);
2810 if (image->debug != MagickFalse)
2811 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002812 cache_info=(CacheInfo *) image->cache;
2813 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002814 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002815 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002816 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002817 *height=(*width);
2818}
2819
2820/*
2821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2822% %
2823% %
2824% %
2825+ G e t P i x e l C a c h e T y p e %
2826% %
2827% %
2828% %
2829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2830%
2831% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2832%
2833% The format of the GetPixelCacheType() method is:
2834%
2835% CacheType GetPixelCacheType(const Image *image)
2836%
2837% A description of each parameter follows:
2838%
2839% o image: the image.
2840%
2841*/
cristya6577ff2011-09-02 19:54:26 +00002842MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002843{
2844 CacheInfo
2845 *cache_info;
2846
2847 assert(image != (Image *) NULL);
2848 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002849 assert(image->cache != (Cache) NULL);
2850 cache_info=(CacheInfo *) image->cache;
2851 assert(cache_info->signature == MagickSignature);
2852 return(cache_info->type);
2853}
2854
2855/*
2856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2857% %
2858% %
2859% %
cristy3ed852e2009-09-05 21:47:34 +00002860+ 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 %
2861% %
2862% %
2863% %
2864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2865%
2866% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2867% pixel cache. A virtual pixel is any pixel access that is outside the
2868% boundaries of the image cache.
2869%
2870% The format of the GetPixelCacheVirtualMethod() method is:
2871%
2872% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2873%
2874% A description of each parameter follows:
2875%
2876% o image: the image.
2877%
2878*/
cristyd1dd6e42011-09-04 01:46:08 +00002879MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002880{
2881 CacheInfo
2882 *cache_info;
2883
2884 assert(image != (Image *) NULL);
2885 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002886 assert(image->cache != (Cache) NULL);
2887 cache_info=(CacheInfo *) image->cache;
2888 assert(cache_info->signature == MagickSignature);
2889 return(cache_info->virtual_pixel_method);
2890}
2891
2892/*
2893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2894% %
2895% %
2896% %
cristy4c08aed2011-07-01 19:47:50 +00002897+ 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 +00002898% %
2899% %
2900% %
2901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2902%
cristy4c08aed2011-07-01 19:47:50 +00002903% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2904% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002905%
cristy4c08aed2011-07-01 19:47:50 +00002906% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002907%
cristy4c08aed2011-07-01 19:47:50 +00002908% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002909%
2910% A description of each parameter follows:
2911%
2912% o image: the image.
2913%
2914*/
cristy4c08aed2011-07-01 19:47:50 +00002915static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002916{
2917 CacheInfo
2918 *cache_info;
2919
cristy5c9e6f22010-09-17 17:31:01 +00002920 const int
2921 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002922
cristy4c08aed2011-07-01 19:47:50 +00002923 const void
2924 *metacontent;
2925
cristye7cc7cf2010-09-21 13:26:47 +00002926 assert(image != (const Image *) NULL);
2927 assert(image->signature == MagickSignature);
2928 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002929 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002930 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002931 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002932 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2933 cache_info->nexus_info[id]);
2934 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002935}
2936
2937/*
2938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2939% %
2940% %
2941% %
cristy4c08aed2011-07-01 19:47:50 +00002942+ 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 +00002943% %
2944% %
2945% %
2946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2947%
cristy4c08aed2011-07-01 19:47:50 +00002948% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2949% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002950%
cristy4c08aed2011-07-01 19:47:50 +00002951% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002952%
cristy4c08aed2011-07-01 19:47:50 +00002953% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002954% NexusInfo *nexus_info)
2955%
2956% A description of each parameter follows:
2957%
2958% o cache: the pixel cache.
2959%
cristy4c08aed2011-07-01 19:47:50 +00002960% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002961%
2962*/
cristya6577ff2011-09-02 19:54:26 +00002963MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002964 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002965{
2966 CacheInfo
2967 *cache_info;
2968
cristye7cc7cf2010-09-21 13:26:47 +00002969 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002970 cache_info=(CacheInfo *) cache;
2971 assert(cache_info->signature == MagickSignature);
2972 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002973 return((void *) NULL);
2974 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002975}
2976
2977/*
2978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2979% %
2980% %
2981% %
cristy4c08aed2011-07-01 19:47:50 +00002982% 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 +00002983% %
2984% %
2985% %
2986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2987%
cristy4c08aed2011-07-01 19:47:50 +00002988% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2989% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2990% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002991%
cristy4c08aed2011-07-01 19:47:50 +00002992% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002993%
cristy4c08aed2011-07-01 19:47:50 +00002994% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002995%
2996% A description of each parameter follows:
2997%
2998% o image: the image.
2999%
3000*/
cristy4c08aed2011-07-01 19:47:50 +00003001MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003002{
3003 CacheInfo
3004 *cache_info;
3005
cristy2036f5c2010-09-19 21:18:17 +00003006 const int
3007 id = GetOpenMPThreadId();
3008
cristy4c08aed2011-07-01 19:47:50 +00003009 const void
3010 *metacontent;
3011
cristy3ed852e2009-09-05 21:47:34 +00003012 assert(image != (const Image *) NULL);
3013 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003014 assert(image->cache != (Cache) NULL);
3015 cache_info=(CacheInfo *) image->cache;
3016 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003017 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3018 (GetVirtualMetacontentFromHandler) NULL)
3019 {
3020 metacontent=cache_info->methods.
3021 get_virtual_metacontent_from_handler(image);
3022 return(metacontent);
3023 }
cristy2036f5c2010-09-19 21:18:17 +00003024 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003025 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3026 cache_info->nexus_info[id]);
3027 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003028}
3029
3030/*
3031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3032% %
3033% %
3034% %
3035+ 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 %
3036% %
3037% %
3038% %
3039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040%
3041% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3042% pixel cache as defined by the geometry parameters. A pointer to the pixels
3043% is returned if the pixels are transferred, otherwise a NULL is returned.
3044%
3045% The format of the GetVirtualPixelsFromNexus() method is:
3046%
cristy4c08aed2011-07-01 19:47:50 +00003047% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003048% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003049% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3050% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003051%
3052% A description of each parameter follows:
3053%
3054% o image: the image.
3055%
3056% o virtual_pixel_method: the virtual pixel method.
3057%
3058% o x,y,columns,rows: These values define the perimeter of a region of
3059% pixels.
3060%
3061% o nexus_info: the cache nexus to acquire.
3062%
3063% o exception: return any errors or warnings in this structure.
3064%
3065*/
3066
cristybb503372010-05-27 20:51:26 +00003067static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003068 DitherMatrix[64] =
3069 {
3070 0, 48, 12, 60, 3, 51, 15, 63,
3071 32, 16, 44, 28, 35, 19, 47, 31,
3072 8, 56, 4, 52, 11, 59, 7, 55,
3073 40, 24, 36, 20, 43, 27, 39, 23,
3074 2, 50, 14, 62, 1, 49, 13, 61,
3075 34, 18, 46, 30, 33, 17, 45, 29,
3076 10, 58, 6, 54, 9, 57, 5, 53,
3077 42, 26, 38, 22, 41, 25, 37, 21
3078 };
3079
cristybb503372010-05-27 20:51:26 +00003080static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003081{
cristybb503372010-05-27 20:51:26 +00003082 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003083 index;
3084
3085 index=x+DitherMatrix[x & 0x07]-32L;
3086 if (index < 0L)
3087 return(0L);
cristybb503372010-05-27 20:51:26 +00003088 if (index >= (ssize_t) columns)
3089 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003090 return(index);
3091}
3092
cristybb503372010-05-27 20:51:26 +00003093static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003094{
cristybb503372010-05-27 20:51:26 +00003095 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003096 index;
3097
3098 index=y+DitherMatrix[y & 0x07]-32L;
3099 if (index < 0L)
3100 return(0L);
cristybb503372010-05-27 20:51:26 +00003101 if (index >= (ssize_t) rows)
3102 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003103 return(index);
3104}
3105
cristybb503372010-05-27 20:51:26 +00003106static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003107{
3108 if (x < 0L)
3109 return(0L);
cristybb503372010-05-27 20:51:26 +00003110 if (x >= (ssize_t) columns)
3111 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003112 return(x);
3113}
3114
cristybb503372010-05-27 20:51:26 +00003115static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003116{
3117 if (y < 0L)
3118 return(0L);
cristybb503372010-05-27 20:51:26 +00003119 if (y >= (ssize_t) rows)
3120 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003121 return(y);
3122}
3123
cristybb503372010-05-27 20:51:26 +00003124static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003125{
cristybb503372010-05-27 20:51:26 +00003126 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003127}
3128
cristybb503372010-05-27 20:51:26 +00003129static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003130{
cristybb503372010-05-27 20:51:26 +00003131 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003132}
3133
cristybb503372010-05-27 20:51:26 +00003134static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3135 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003136{
3137 MagickModulo
3138 modulo;
3139
cristy6162bb42011-07-18 11:34:09 +00003140 /*
3141 Compute the remainder of dividing offset by extent. It returns not only
3142 the quotient (tile the offset falls in) but also the positive remainer
3143 within that tile such that 0 <= remainder < extent. This method is
3144 essentially a ldiv() using a floored modulo division rather than the
3145 normal default truncated modulo division.
3146 */
cristybb503372010-05-27 20:51:26 +00003147 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003148 if (offset < 0L)
3149 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003150 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003151 return(modulo);
3152}
3153
cristya6577ff2011-09-02 19:54:26 +00003154MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003155 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3156 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003157 ExceptionInfo *exception)
3158{
3159 CacheInfo
3160 *cache_info;
3161
3162 MagickOffsetType
3163 offset;
3164
3165 MagickSizeType
3166 length,
3167 number_pixels;
3168
3169 NexusInfo
3170 **virtual_nexus;
3171
cristy4c08aed2011-07-01 19:47:50 +00003172 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003173 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003174 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003175
3176 RectangleInfo
3177 region;
3178
cristy4c08aed2011-07-01 19:47:50 +00003179 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003180 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003181
cristy4c08aed2011-07-01 19:47:50 +00003182 register const void
3183 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003184
cristy4c08aed2011-07-01 19:47:50 +00003185 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003186 *restrict q;
3187
cristybb503372010-05-27 20:51:26 +00003188 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003189 i,
3190 u;
cristy3ed852e2009-09-05 21:47:34 +00003191
cristy4c08aed2011-07-01 19:47:50 +00003192 register unsigned char
3193 *restrict s;
3194
cristy105ba3c2011-07-18 02:28:38 +00003195 ssize_t
3196 v;
3197
cristy4c08aed2011-07-01 19:47:50 +00003198 void
cristy105ba3c2011-07-18 02:28:38 +00003199 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003200
cristy3ed852e2009-09-05 21:47:34 +00003201 /*
3202 Acquire pixels.
3203 */
cristye7cc7cf2010-09-21 13:26:47 +00003204 assert(image != (const Image *) NULL);
3205 assert(image->signature == MagickSignature);
3206 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003207 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003208 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003209 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003210 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003211 region.x=x;
3212 region.y=y;
3213 region.width=columns;
3214 region.height=rows;
3215 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003216 if (pixels == (Quantum *) NULL)
3217 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003218 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003219 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3220 nexus_info->region.x;
3221 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3222 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003223 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3224 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003225 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3226 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003227 {
3228 MagickBooleanType
3229 status;
3230
3231 /*
3232 Pixel request is inside cache extents.
3233 */
cristy4c08aed2011-07-01 19:47:50 +00003234 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003235 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003236 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3237 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003238 return((const Quantum *) NULL);
3239 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003240 {
cristy4c08aed2011-07-01 19:47:50 +00003241 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003242 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003243 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003244 }
cristyacd2ed22011-08-30 01:44:23 +00003245 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003246 }
3247 /*
3248 Pixel request is outside cache extents.
3249 */
cristy4c08aed2011-07-01 19:47:50 +00003250 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003251 virtual_nexus=AcquirePixelCacheNexus(1);
3252 if (virtual_nexus == (NexusInfo **) NULL)
3253 {
cristy4c08aed2011-07-01 19:47:50 +00003254 if (virtual_nexus != (NexusInfo **) NULL)
3255 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003256 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3257 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003258 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003259 }
cristy105ba3c2011-07-18 02:28:38 +00003260 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3261 sizeof(*virtual_pixel));
3262 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003263 switch (virtual_pixel_method)
3264 {
cristy4c08aed2011-07-01 19:47:50 +00003265 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003266 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003267 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003268 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003269 case MaskVirtualPixelMethod:
3270 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003271 case EdgeVirtualPixelMethod:
3272 case CheckerTileVirtualPixelMethod:
3273 case HorizontalTileVirtualPixelMethod:
3274 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003275 {
cristy4c08aed2011-07-01 19:47:50 +00003276 if (cache_info->metacontent_extent != 0)
3277 {
cristy6162bb42011-07-18 11:34:09 +00003278 /*
3279 Acquire a metacontent buffer.
3280 */
cristya64b85d2011-09-14 01:02:31 +00003281 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003282 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003283 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003284 {
cristy4c08aed2011-07-01 19:47:50 +00003285 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3286 (void) ThrowMagickException(exception,GetMagickModule(),
3287 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3288 return((const Quantum *) NULL);
3289 }
cristy105ba3c2011-07-18 02:28:38 +00003290 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003291 cache_info->metacontent_extent);
3292 }
3293 switch (virtual_pixel_method)
3294 {
3295 case BlackVirtualPixelMethod:
3296 {
cristy30301712011-07-18 15:06:51 +00003297 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3298 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003299 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3300 break;
3301 }
3302 case GrayVirtualPixelMethod:
3303 {
cristy30301712011-07-18 15:06:51 +00003304 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003305 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3306 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003307 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3308 break;
3309 }
3310 case TransparentVirtualPixelMethod:
3311 {
cristy30301712011-07-18 15:06:51 +00003312 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3313 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003314 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3315 break;
3316 }
3317 case MaskVirtualPixelMethod:
3318 case WhiteVirtualPixelMethod:
3319 {
cristy30301712011-07-18 15:06:51 +00003320 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3321 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003322 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3323 break;
3324 }
3325 default:
3326 {
cristy9e0719b2011-12-29 03:45:45 +00003327 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3328 virtual_pixel);
3329 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3330 virtual_pixel);
3331 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3332 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003333 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003334 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3335 virtual_pixel);
3336 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3337 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003338 break;
3339 }
3340 }
cristy3ed852e2009-09-05 21:47:34 +00003341 break;
3342 }
3343 default:
cristy3ed852e2009-09-05 21:47:34 +00003344 break;
cristy3ed852e2009-09-05 21:47:34 +00003345 }
cristybb503372010-05-27 20:51:26 +00003346 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003347 {
cristybb503372010-05-27 20:51:26 +00003348 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003349 {
3350 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003351 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003352 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3353 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003354 {
3355 MagickModulo
3356 x_modulo,
3357 y_modulo;
3358
3359 /*
3360 Transfer a single pixel.
3361 */
3362 length=(MagickSizeType) 1;
3363 switch (virtual_pixel_method)
3364 {
cristy3ed852e2009-09-05 21:47:34 +00003365 default:
3366 {
3367 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003368 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003369 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003370 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003371 break;
3372 }
3373 case RandomVirtualPixelMethod:
3374 {
3375 if (cache_info->random_info == (RandomInfo *) NULL)
3376 cache_info->random_info=AcquireRandomInfo();
3377 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003378 RandomX(cache_info->random_info,cache_info->columns),
3379 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003380 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003381 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003382 break;
3383 }
3384 case DitherVirtualPixelMethod:
3385 {
3386 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003387 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003388 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003389 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003390 break;
3391 }
3392 case TileVirtualPixelMethod:
3393 {
3394 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3395 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3396 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003397 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003398 exception);
cristy4c08aed2011-07-01 19:47:50 +00003399 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003400 break;
3401 }
3402 case MirrorVirtualPixelMethod:
3403 {
3404 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3405 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003406 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003407 x_modulo.remainder-1L;
3408 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3409 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003410 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003411 y_modulo.remainder-1L;
3412 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003413 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003414 exception);
cristy4c08aed2011-07-01 19:47:50 +00003415 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003416 break;
3417 }
3418 case HorizontalTileEdgeVirtualPixelMethod:
3419 {
3420 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003422 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003423 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003424 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003425 break;
3426 }
3427 case VerticalTileEdgeVirtualPixelMethod:
3428 {
3429 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003431 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003432 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003433 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3434 break;
3435 }
3436 case BackgroundVirtualPixelMethod:
3437 case BlackVirtualPixelMethod:
3438 case GrayVirtualPixelMethod:
3439 case TransparentVirtualPixelMethod:
3440 case MaskVirtualPixelMethod:
3441 case WhiteVirtualPixelMethod:
3442 {
3443 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003444 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003445 break;
3446 }
3447 case EdgeVirtualPixelMethod:
3448 case CheckerTileVirtualPixelMethod:
3449 {
3450 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3451 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3452 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3453 {
3454 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003455 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003456 break;
3457 }
3458 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3459 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3460 exception);
3461 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3462 break;
3463 }
3464 case HorizontalTileVirtualPixelMethod:
3465 {
3466 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3467 {
3468 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003469 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003470 break;
3471 }
3472 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3475 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3476 exception);
3477 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3478 break;
3479 }
3480 case VerticalTileVirtualPixelMethod:
3481 {
3482 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3483 {
3484 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003485 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003486 break;
3487 }
3488 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3489 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3490 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3491 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3492 exception);
3493 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003494 break;
3495 }
3496 }
cristy4c08aed2011-07-01 19:47:50 +00003497 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003498 break;
cristyed231572011-07-14 02:18:59 +00003499 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003500 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003501 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003502 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003503 {
3504 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3505 s+=cache_info->metacontent_extent;
3506 }
cristy3ed852e2009-09-05 21:47:34 +00003507 continue;
3508 }
3509 /*
3510 Transfer a run of pixels.
3511 */
cristy4c08aed2011-07-01 19:47:50 +00003512 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3513 length,1UL,*virtual_nexus,exception);
3514 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003515 break;
cristy4c08aed2011-07-01 19:47:50 +00003516 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003517 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3518 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003519 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003520 {
cristy4c08aed2011-07-01 19:47:50 +00003521 (void) memcpy(s,r,(size_t) length);
3522 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003523 }
3524 }
3525 }
cristy4c08aed2011-07-01 19:47:50 +00003526 /*
3527 Free resources.
3528 */
cristy105ba3c2011-07-18 02:28:38 +00003529 if (virtual_metacontent != (void *) NULL)
3530 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003531 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3532 return(pixels);
3533}
3534
3535/*
3536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3537% %
3538% %
3539% %
3540+ G e t V i r t u a l P i x e l C a c h e %
3541% %
3542% %
3543% %
3544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3545%
3546% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3547% cache as defined by the geometry parameters. A pointer to the pixels
3548% is returned if the pixels are transferred, otherwise a NULL is returned.
3549%
3550% The format of the GetVirtualPixelCache() method is:
3551%
cristy4c08aed2011-07-01 19:47:50 +00003552% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003553% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3554% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003555% ExceptionInfo *exception)
3556%
3557% A description of each parameter follows:
3558%
3559% o image: the image.
3560%
3561% o virtual_pixel_method: the virtual pixel method.
3562%
3563% o x,y,columns,rows: These values define the perimeter of a region of
3564% pixels.
3565%
3566% o exception: return any errors or warnings in this structure.
3567%
3568*/
cristy4c08aed2011-07-01 19:47:50 +00003569static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003570 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3571 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003572{
3573 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003574 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003575
cristy5c9e6f22010-09-17 17:31:01 +00003576 const int
3577 id = GetOpenMPThreadId();
3578
cristy4c08aed2011-07-01 19:47:50 +00003579 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003580 *p;
cristy4c08aed2011-07-01 19:47:50 +00003581
cristye7cc7cf2010-09-21 13:26:47 +00003582 assert(image != (const Image *) NULL);
3583 assert(image->signature == MagickSignature);
3584 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003585 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003586 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003587 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003588 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003589 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003590 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003591}
3592
3593/*
3594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3595% %
3596% %
3597% %
3598% G e t V i r t u a l P i x e l Q u e u e %
3599% %
3600% %
3601% %
3602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3603%
cristy4c08aed2011-07-01 19:47:50 +00003604% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3605% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003606%
3607% The format of the GetVirtualPixelQueue() method is:
3608%
cristy4c08aed2011-07-01 19:47:50 +00003609% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003610%
3611% A description of each parameter follows:
3612%
3613% o image: the image.
3614%
3615*/
cristy4c08aed2011-07-01 19:47:50 +00003616MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003617{
3618 CacheInfo
3619 *cache_info;
3620
cristy2036f5c2010-09-19 21:18:17 +00003621 const int
3622 id = GetOpenMPThreadId();
3623
cristy3ed852e2009-09-05 21:47:34 +00003624 assert(image != (const Image *) NULL);
3625 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003626 assert(image->cache != (Cache) NULL);
3627 cache_info=(CacheInfo *) image->cache;
3628 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003629 if (cache_info->methods.get_virtual_pixels_handler !=
3630 (GetVirtualPixelsHandler) NULL)
3631 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003632 assert(id < (int) cache_info->number_threads);
3633 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003634}
3635
3636/*
3637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3638% %
3639% %
3640% %
3641% G e t V i r t u a l P i x e l s %
3642% %
3643% %
3644% %
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646%
3647% GetVirtualPixels() returns an immutable pixel region. If the
3648% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003649% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003650% copy of the pixels or it may point to the original pixels in memory.
3651% Performance is maximized if the selected region is part of one row, or one
3652% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003653% (without a copy) if the image is in memory, or in a memory-mapped file. The
3654% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003655%
3656% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003657% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3658% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3659% access the meta-content (of type void) corresponding to the the
3660% region.
cristy3ed852e2009-09-05 21:47:34 +00003661%
3662% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3663%
3664% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3665% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3666% GetCacheViewAuthenticPixels() instead.
3667%
3668% The format of the GetVirtualPixels() method is:
3669%
cristy4c08aed2011-07-01 19:47:50 +00003670% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003671% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003672% ExceptionInfo *exception)
3673%
3674% A description of each parameter follows:
3675%
3676% o image: the image.
3677%
3678% o x,y,columns,rows: These values define the perimeter of a region of
3679% pixels.
3680%
3681% o exception: return any errors or warnings in this structure.
3682%
3683*/
cristy4c08aed2011-07-01 19:47:50 +00003684MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003685 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3686 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003687{
3688 CacheInfo
3689 *cache_info;
3690
cristy2036f5c2010-09-19 21:18:17 +00003691 const int
3692 id = GetOpenMPThreadId();
3693
cristy4c08aed2011-07-01 19:47:50 +00003694 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003695 *p;
cristy4c08aed2011-07-01 19:47:50 +00003696
cristy3ed852e2009-09-05 21:47:34 +00003697 assert(image != (const Image *) NULL);
3698 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003699 assert(image->cache != (Cache) NULL);
3700 cache_info=(CacheInfo *) image->cache;
3701 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003702 if (cache_info->methods.get_virtual_pixel_handler !=
3703 (GetVirtualPixelHandler) NULL)
3704 return(cache_info->methods.get_virtual_pixel_handler(image,
3705 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003706 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003707 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003708 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003709 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003710}
3711
3712/*
3713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3714% %
3715% %
3716% %
3717+ 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 %
3718% %
3719% %
3720% %
3721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3722%
cristy4c08aed2011-07-01 19:47:50 +00003723% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3724% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003725%
3726% The format of the GetVirtualPixelsCache() method is:
3727%
cristy4c08aed2011-07-01 19:47:50 +00003728% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003729%
3730% A description of each parameter follows:
3731%
3732% o image: the image.
3733%
3734*/
cristy4c08aed2011-07-01 19:47:50 +00003735static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003736{
3737 CacheInfo
3738 *cache_info;
3739
cristy5c9e6f22010-09-17 17:31:01 +00003740 const int
3741 id = GetOpenMPThreadId();
3742
cristye7cc7cf2010-09-21 13:26:47 +00003743 assert(image != (const Image *) NULL);
3744 assert(image->signature == MagickSignature);
3745 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003746 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003747 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003748 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003749 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003750}
3751
3752/*
3753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3754% %
3755% %
3756% %
3757+ G e t V i r t u a l P i x e l s N e x u s %
3758% %
3759% %
3760% %
3761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3762%
3763% GetVirtualPixelsNexus() returns the pixels associated with the specified
3764% cache nexus.
3765%
3766% The format of the GetVirtualPixelsNexus() method is:
3767%
cristy4c08aed2011-07-01 19:47:50 +00003768% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003769% NexusInfo *nexus_info)
3770%
3771% A description of each parameter follows:
3772%
3773% o cache: the pixel cache.
3774%
3775% o nexus_info: the cache nexus to return the colormap pixels.
3776%
3777*/
cristya6577ff2011-09-02 19:54:26 +00003778MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003779 NexusInfo *nexus_info)
3780{
3781 CacheInfo
3782 *cache_info;
3783
cristye7cc7cf2010-09-21 13:26:47 +00003784 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003785 cache_info=(CacheInfo *) cache;
3786 assert(cache_info->signature == MagickSignature);
3787 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003788 return((Quantum *) NULL);
3789 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003790}
3791
3792/*
3793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3794% %
3795% %
3796% %
3797+ M a s k P i x e l C a c h e N e x u s %
3798% %
3799% %
3800% %
3801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3802%
3803% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3804% The method returns MagickTrue if the pixel region is masked, otherwise
3805% MagickFalse.
3806%
3807% The format of the MaskPixelCacheNexus() method is:
3808%
3809% MagickBooleanType MaskPixelCacheNexus(Image *image,
3810% NexusInfo *nexus_info,ExceptionInfo *exception)
3811%
3812% A description of each parameter follows:
3813%
3814% o image: the image.
3815%
3816% o nexus_info: the cache nexus to clip.
3817%
3818% o exception: return any errors or warnings in this structure.
3819%
3820*/
3821
cristy3aa93752011-12-18 15:54:24 +00003822static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3823 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003824{
3825 MagickRealType
3826 gamma;
3827
cristyaa83c2c2011-09-21 13:36:25 +00003828 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003829 {
3830 *composite=(*q);
3831 return;
3832 }
3833 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3834 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003835 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3836 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3837 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003838 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003839 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003840}
3841
3842static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3843 ExceptionInfo *exception)
3844{
3845 CacheInfo
3846 *cache_info;
3847
cristy4c08aed2011-07-01 19:47:50 +00003848 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003849 alpha,
3850 beta;
3851
3852 MagickSizeType
3853 number_pixels;
3854
3855 NexusInfo
3856 **clip_nexus,
3857 **image_nexus;
3858
cristy4c08aed2011-07-01 19:47:50 +00003859 register const Quantum
3860 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003861 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003862
cristy4c08aed2011-07-01 19:47:50 +00003863 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003864 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003865
cristye076a6e2010-08-15 19:59:43 +00003866 register ssize_t
3867 i;
3868
cristy3ed852e2009-09-05 21:47:34 +00003869 /*
3870 Apply clip mask.
3871 */
3872 if (image->debug != MagickFalse)
3873 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3874 if (image->mask == (Image *) NULL)
3875 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003876 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003877 if (cache_info == (Cache) NULL)
3878 return(MagickFalse);
3879 image_nexus=AcquirePixelCacheNexus(1);
3880 clip_nexus=AcquirePixelCacheNexus(1);
3881 if ((image_nexus == (NexusInfo **) NULL) ||
3882 (clip_nexus == (NexusInfo **) NULL))
3883 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003884 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3885 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3886 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003887 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003888 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3889 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003890 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003891 GetPixelInfo(image,&alpha);
3892 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003893 number_pixels=(MagickSizeType) nexus_info->region.width*
3894 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003895 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003896 {
cristy4c08aed2011-07-01 19:47:50 +00003897 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003898 break;
cristy803640d2011-11-17 02:11:32 +00003899 GetPixelInfoPixel(image,p,&alpha);
3900 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003901 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003902 &alpha,alpha.alpha,&beta);
3903 SetPixelRed(image,ClampToQuantum(beta.red),q);
3904 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3905 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3906 if (cache_info->colorspace == CMYKColorspace)
3907 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3908 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003909 p++;
3910 q++;
3911 r++;
3912 }
3913 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3914 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003915 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003916 return(MagickFalse);
3917 return(MagickTrue);
3918}
3919
3920/*
3921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3922% %
3923% %
3924% %
3925+ O p e n P i x e l C a c h e %
3926% %
3927% %
3928% %
3929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3930%
3931% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3932% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003933% metacontent, and memory mapping the cache if it is disk based. The cache
3934% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003935%
3936% The format of the OpenPixelCache() method is:
3937%
3938% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3939% ExceptionInfo *exception)
3940%
3941% A description of each parameter follows:
3942%
3943% o image: the image.
3944%
3945% o mode: ReadMode, WriteMode, or IOMode.
3946%
3947% o exception: return any errors or warnings in this structure.
3948%
3949*/
3950
cristyd43a46b2010-01-21 02:13:41 +00003951static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003952{
3953 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003954 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003955 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003956 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003957 {
3958 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003959 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003960 cache_info->length);
3961 }
3962}
3963
3964static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3965{
3966 CacheInfo
3967 *cache_info;
3968
3969 MagickOffsetType
3970 count,
3971 extent,
3972 offset;
3973
3974 cache_info=(CacheInfo *) image->cache;
3975 if (image->debug != MagickFalse)
3976 {
3977 char
3978 format[MaxTextExtent],
3979 message[MaxTextExtent];
3980
cristyb9080c92009-12-01 20:13:26 +00003981 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003982 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003983 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003984 cache_info->cache_filename,cache_info->file,format);
3985 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3986 }
3987 if (length != (MagickSizeType) ((MagickOffsetType) length))
3988 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003989 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003990 if (extent < 0)
3991 return(MagickFalse);
3992 if ((MagickSizeType) extent >= length)
3993 return(MagickTrue);
3994 offset=(MagickOffsetType) length-1;
3995 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3996 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3997}
3998
3999static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4000 ExceptionInfo *exception)
4001{
cristy3ed852e2009-09-05 21:47:34 +00004002 CacheInfo
4003 *cache_info,
4004 source_info;
4005
cristyf3a6a9d2010-11-07 21:02:56 +00004006 char
4007 format[MaxTextExtent],
4008 message[MaxTextExtent];
4009
cristy4c08aed2011-07-01 19:47:50 +00004010 MagickBooleanType
4011 status;
4012
cristy3ed852e2009-09-05 21:47:34 +00004013 MagickSizeType
4014 length,
4015 number_pixels;
4016
cristy3b8fe922011-12-29 18:56:23 +00004017 PixelChannelMap
4018 *p,
4019 *q;
4020
cristy3ed852e2009-09-05 21:47:34 +00004021 size_t
cristye076a6e2010-08-15 19:59:43 +00004022 columns,
cristy3ed852e2009-09-05 21:47:34 +00004023 packet_size;
4024
cristye7cc7cf2010-09-21 13:26:47 +00004025 assert(image != (const Image *) NULL);
4026 assert(image->signature == MagickSignature);
4027 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004028 if (image->debug != MagickFalse)
4029 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4030 if ((image->columns == 0) || (image->rows == 0))
4031 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4032 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004033 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004034 source_info=(*cache_info);
4035 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004036 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004037 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004038 cache_info->storage_class=image->storage_class;
4039 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004040 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004041 cache_info->rows=image->rows;
4042 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004043 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004044 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004045 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4046 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004047 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004048 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004049 if (image->ping != MagickFalse)
4050 {
cristy73724512010-04-12 14:43:14 +00004051 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004052 cache_info->pixels=(Quantum *) NULL;
4053 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004054 cache_info->length=0;
4055 return(MagickTrue);
4056 }
cristy3ed852e2009-09-05 21:47:34 +00004057 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004058 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004059 if (image->metacontent_extent != 0)
4060 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004061 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004062 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004063 if (cache_info->columns != columns)
4064 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4065 image->filename);
4066 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004067 p=cache_info->channel_map;
4068 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004069 if ((cache_info->type != UndefinedCache) &&
4070 (cache_info->columns <= source_info.columns) &&
4071 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004072 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004073 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004074 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4075 {
4076 /*
4077 Inline pixel cache clone optimization.
4078 */
4079 if ((cache_info->columns == source_info.columns) &&
4080 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004081 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004082 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004083 (cache_info->metacontent_extent == source_info.metacontent_extent))
4084 return(MagickTrue);
4085 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4086 }
cristy3ed852e2009-09-05 21:47:34 +00004087 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004088 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004089 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004090 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4091 {
4092 status=AcquireMagickResource(MemoryResource,cache_info->length);
4093 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4094 (cache_info->type == MemoryCache))
4095 {
cristyd43a46b2010-01-21 02:13:41 +00004096 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004097 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004098 cache_info->pixels=source_info.pixels;
4099 else
4100 {
4101 /*
4102 Create memory pixel cache.
4103 */
cristy4c08aed2011-07-01 19:47:50 +00004104 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004105 if (image->debug != MagickFalse)
4106 {
cristy32cacff2011-12-31 03:36:27 +00004107 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004108 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004109 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4110 cache_info->filename,cache_info->mapped != MagickFalse ?
4111 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004112 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004113 format);
cristy3ed852e2009-09-05 21:47:34 +00004114 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4115 message);
4116 }
cristy3ed852e2009-09-05 21:47:34 +00004117 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004118 cache_info->metacontent=(void *) NULL;
4119 if (cache_info->metacontent_extent != 0)
4120 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004121 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004122 if ((source_info.storage_class != UndefinedClass) &&
4123 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004124 {
cristy4c08aed2011-07-01 19:47:50 +00004125 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004126 exception);
4127 RelinquishPixelCachePixels(&source_info);
4128 }
cristy4c08aed2011-07-01 19:47:50 +00004129 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004130 }
4131 }
4132 RelinquishMagickResource(MemoryResource,cache_info->length);
4133 }
4134 /*
4135 Create pixel cache on disk.
4136 */
4137 status=AcquireMagickResource(DiskResource,cache_info->length);
4138 if (status == MagickFalse)
4139 {
4140 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4141 "CacheResourcesExhausted","`%s'",image->filename);
4142 return(MagickFalse);
4143 }
cristy413f1302012-01-01 17:48:27 +00004144 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4145 {
4146 (void) ClosePixelCacheOnDisk(cache_info);
4147 *cache_info->cache_filename='\0';
4148 }
cristy3ed852e2009-09-05 21:47:34 +00004149 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4150 {
4151 RelinquishMagickResource(DiskResource,cache_info->length);
4152 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4153 image->filename);
4154 return(MagickFalse);
4155 }
4156 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4157 cache_info->length);
4158 if (status == MagickFalse)
4159 {
4160 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4161 image->filename);
4162 return(MagickFalse);
4163 }
cristyed231572011-07-14 02:18:59 +00004164 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004165 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004166 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004167 cache_info->type=DiskCache;
4168 else
4169 {
4170 status=AcquireMagickResource(MapResource,cache_info->length);
4171 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4172 (cache_info->type != MemoryCache))
4173 cache_info->type=DiskCache;
4174 else
4175 {
cristy4c08aed2011-07-01 19:47:50 +00004176 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004177 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004178 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004179 {
cristy3ed852e2009-09-05 21:47:34 +00004180 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004181 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004182 }
4183 else
4184 {
4185 /*
4186 Create file-backed memory-mapped pixel cache.
4187 */
cristy4c08aed2011-07-01 19:47:50 +00004188 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004189 (void) ClosePixelCacheOnDisk(cache_info);
4190 cache_info->type=MapCache;
4191 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004192 cache_info->metacontent=(void *) NULL;
4193 if (cache_info->metacontent_extent != 0)
4194 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004195 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004196 if ((source_info.storage_class != UndefinedClass) &&
4197 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004198 {
4199 status=ClonePixelCachePixels(cache_info,&source_info,
4200 exception);
4201 RelinquishPixelCachePixels(&source_info);
4202 }
4203 if (image->debug != MagickFalse)
4204 {
cristy413f1302012-01-01 17:48:27 +00004205 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004206 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004207 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004208 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004209 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004210 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004211 format);
cristy3ed852e2009-09-05 21:47:34 +00004212 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4213 message);
4214 }
cristy4c08aed2011-07-01 19:47:50 +00004215 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004216 }
4217 }
4218 RelinquishMagickResource(MapResource,cache_info->length);
4219 }
cristy4c08aed2011-07-01 19:47:50 +00004220 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00004221 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004222 {
4223 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4224 RelinquishPixelCachePixels(&source_info);
4225 }
4226 if (image->debug != MagickFalse)
4227 {
cristyb9080c92009-12-01 20:13:26 +00004228 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004229 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004230 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004231 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004232 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004233 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004234 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4235 }
cristy4c08aed2011-07-01 19:47:50 +00004236 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004237}
4238
4239/*
4240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4241% %
4242% %
4243% %
4244+ P e r s i s t P i x e l C a c h e %
4245% %
4246% %
4247% %
4248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4249%
4250% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4251% persistent pixel cache is one that resides on disk and is not destroyed
4252% when the program exits.
4253%
4254% The format of the PersistPixelCache() method is:
4255%
4256% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4257% const MagickBooleanType attach,MagickOffsetType *offset,
4258% ExceptionInfo *exception)
4259%
4260% A description of each parameter follows:
4261%
4262% o image: the image.
4263%
4264% o filename: the persistent pixel cache filename.
4265%
cristyf3a6a9d2010-11-07 21:02:56 +00004266% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004267%
cristy3ed852e2009-09-05 21:47:34 +00004268% o initialize: A value other than zero initializes the persistent pixel
4269% cache.
4270%
4271% o offset: the offset in the persistent cache to store pixels.
4272%
4273% o exception: return any errors or warnings in this structure.
4274%
4275*/
4276MagickExport MagickBooleanType PersistPixelCache(Image *image,
4277 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4278 ExceptionInfo *exception)
4279{
4280 CacheInfo
4281 *cache_info,
4282 *clone_info;
4283
4284 Image
4285 clone_image;
4286
cristy3ed852e2009-09-05 21:47:34 +00004287 MagickBooleanType
4288 status;
4289
cristye076a6e2010-08-15 19:59:43 +00004290 ssize_t
4291 page_size;
4292
cristy3ed852e2009-09-05 21:47:34 +00004293 assert(image != (Image *) NULL);
4294 assert(image->signature == MagickSignature);
4295 if (image->debug != MagickFalse)
4296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4297 assert(image->cache != (void *) NULL);
4298 assert(filename != (const char *) NULL);
4299 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004300 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004301 cache_info=(CacheInfo *) image->cache;
4302 assert(cache_info->signature == MagickSignature);
4303 if (attach != MagickFalse)
4304 {
4305 /*
cristy01b7eb02009-09-10 23:10:14 +00004306 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004307 */
4308 if (image->debug != MagickFalse)
4309 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004310 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004311 (void) CopyMagickString(cache_info->cache_filename,filename,
4312 MaxTextExtent);
4313 cache_info->type=DiskCache;
4314 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004315 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004316 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004317 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004318 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004319 }
cristy01b7eb02009-09-10 23:10:14 +00004320 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4321 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004322 {
cristyf84a1932010-01-03 18:00:18 +00004323 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004324 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004325 (cache_info->reference_count == 1))
4326 {
4327 int
4328 status;
4329
4330 /*
cristy01b7eb02009-09-10 23:10:14 +00004331 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004332 */
cristy320684d2011-09-23 14:55:47 +00004333 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004334 if (status == 0)
4335 {
4336 (void) CopyMagickString(cache_info->cache_filename,filename,
4337 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004338 *offset+=cache_info->length+page_size-(cache_info->length %
4339 page_size);
cristyf84a1932010-01-03 18:00:18 +00004340 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004341 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004342 if (image->debug != MagickFalse)
4343 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4344 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004345 return(MagickTrue);
4346 }
4347 }
cristyf84a1932010-01-03 18:00:18 +00004348 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004349 }
4350 /*
cristy01b7eb02009-09-10 23:10:14 +00004351 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004352 */
4353 clone_image=(*image);
4354 clone_info=(CacheInfo *) clone_image.cache;
4355 image->cache=ClonePixelCache(cache_info);
4356 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4357 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4358 cache_info->type=DiskCache;
4359 cache_info->offset=(*offset);
4360 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004361 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004362 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004363 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004364 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004365 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4366 return(status);
4367}
4368
4369/*
4370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4371% %
4372% %
4373% %
4374+ Q u e u e A u t h e n t i c N e x u s %
4375% %
4376% %
4377% %
4378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4379%
4380% QueueAuthenticNexus() allocates an region to store image pixels as defined
4381% by the region rectangle and returns a pointer to the region. This region is
4382% subsequently transferred from the pixel cache with
4383% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4384% pixels are transferred, otherwise a NULL is returned.
4385%
4386% The format of the QueueAuthenticNexus() method is:
4387%
cristy4c08aed2011-07-01 19:47:50 +00004388% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004389% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004390% const MagickBooleanType clone,NexusInfo *nexus_info,
4391% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004392%
4393% A description of each parameter follows:
4394%
4395% o image: the image.
4396%
4397% o x,y,columns,rows: These values define the perimeter of a region of
4398% pixels.
4399%
4400% o nexus_info: the cache nexus to set.
4401%
cristy65dbf172011-10-06 17:32:04 +00004402% o clone: clone the pixel cache.
4403%
cristy3ed852e2009-09-05 21:47:34 +00004404% o exception: return any errors or warnings in this structure.
4405%
4406*/
cristya6577ff2011-09-02 19:54:26 +00004407MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004408 const ssize_t y,const size_t columns,const size_t rows,
4409 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004410{
4411 CacheInfo
4412 *cache_info;
4413
4414 MagickOffsetType
4415 offset;
4416
4417 MagickSizeType
4418 number_pixels;
4419
4420 RectangleInfo
4421 region;
4422
4423 /*
4424 Validate pixel cache geometry.
4425 */
cristye7cc7cf2010-09-21 13:26:47 +00004426 assert(image != (const Image *) NULL);
4427 assert(image->signature == MagickSignature);
4428 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004429 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004430 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004431 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004432 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004433 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4434 {
4435 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4436 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004437 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004438 }
cristybb503372010-05-27 20:51:26 +00004439 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4440 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004441 {
4442 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4443 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004444 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004445 }
4446 offset=(MagickOffsetType) y*cache_info->columns+x;
4447 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004448 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004449 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4450 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4451 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004452 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004453 /*
4454 Return pixel cache.
4455 */
4456 region.x=x;
4457 region.y=y;
4458 region.width=columns;
4459 region.height=rows;
4460 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4461}
4462
4463/*
4464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4465% %
4466% %
4467% %
4468+ 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 %
4469% %
4470% %
4471% %
4472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4473%
4474% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4475% defined by the region rectangle and returns a pointer to the region. This
4476% region is subsequently transferred from the pixel cache with
4477% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4478% pixels are transferred, otherwise a NULL is returned.
4479%
4480% The format of the QueueAuthenticPixelsCache() method is:
4481%
cristy4c08aed2011-07-01 19:47:50 +00004482% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004483% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004484% ExceptionInfo *exception)
4485%
4486% A description of each parameter follows:
4487%
4488% o image: the image.
4489%
4490% o x,y,columns,rows: These values define the perimeter of a region of
4491% pixels.
4492%
4493% o exception: return any errors or warnings in this structure.
4494%
4495*/
cristy4c08aed2011-07-01 19:47:50 +00004496static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004497 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004498 ExceptionInfo *exception)
4499{
4500 CacheInfo
4501 *cache_info;
4502
cristy5c9e6f22010-09-17 17:31:01 +00004503 const int
4504 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004505
cristy4c08aed2011-07-01 19:47:50 +00004506 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004507 *q;
cristy4c08aed2011-07-01 19:47:50 +00004508
cristye7cc7cf2010-09-21 13:26:47 +00004509 assert(image != (const Image *) NULL);
4510 assert(image->signature == MagickSignature);
4511 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004512 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004513 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004514 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004515 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4516 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004517 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004518}
4519
4520/*
4521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4522% %
4523% %
4524% %
4525% Q u e u e A u t h e n t i c P i x e l s %
4526% %
4527% %
4528% %
4529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4530%
4531% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004532% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004533% region is returned, otherwise NULL is returned. The returned pointer may
4534% point to a temporary working buffer for the pixels or it may point to the
4535% final location of the pixels in memory.
4536%
4537% Write-only access means that any existing pixel values corresponding to
4538% the region are ignored. This is useful if the initial image is being
4539% created from scratch, or if the existing pixel values are to be
4540% completely replaced without need to refer to their pre-existing values.
4541% The application is free to read and write the pixel buffer returned by
4542% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4543% initialize the pixel array values. Initializing pixel array values is the
4544% application's responsibility.
4545%
4546% Performance is maximized if the selected region is part of one row, or
4547% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004548% pixels in-place (without a copy) if the image is in memory, or in a
4549% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004550% by the user.
4551%
4552% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004553% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4554% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4555% obtain the meta-content (of type void) corresponding to the region.
4556% Once the Quantum (and/or Quantum) array has been updated, the
4557% changes must be saved back to the underlying image using
4558% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004559%
4560% The format of the QueueAuthenticPixels() method is:
4561%
cristy4c08aed2011-07-01 19:47:50 +00004562% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004563% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004564% ExceptionInfo *exception)
4565%
4566% A description of each parameter follows:
4567%
4568% o image: the image.
4569%
4570% o x,y,columns,rows: These values define the perimeter of a region of
4571% pixels.
4572%
4573% o exception: return any errors or warnings in this structure.
4574%
4575*/
cristy4c08aed2011-07-01 19:47:50 +00004576MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004577 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004578 ExceptionInfo *exception)
4579{
4580 CacheInfo
4581 *cache_info;
4582
cristy2036f5c2010-09-19 21:18:17 +00004583 const int
4584 id = GetOpenMPThreadId();
4585
cristy4c08aed2011-07-01 19:47:50 +00004586 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004587 *q;
cristy4c08aed2011-07-01 19:47:50 +00004588
cristy3ed852e2009-09-05 21:47:34 +00004589 assert(image != (Image *) NULL);
4590 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004591 assert(image->cache != (Cache) NULL);
4592 cache_info=(CacheInfo *) image->cache;
4593 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004594 if (cache_info->methods.queue_authentic_pixels_handler !=
4595 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004596 {
cristyacd2ed22011-08-30 01:44:23 +00004597 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004598 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004599 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004600 }
cristy2036f5c2010-09-19 21:18:17 +00004601 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004602 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4603 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004604 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004605}
4606
4607/*
4608%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4609% %
4610% %
4611% %
cristy4c08aed2011-07-01 19:47:50 +00004612+ 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 +00004613% %
4614% %
4615% %
4616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4617%
cristy4c08aed2011-07-01 19:47:50 +00004618% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004619% the pixel cache.
4620%
cristy4c08aed2011-07-01 19:47:50 +00004621% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004622%
cristy4c08aed2011-07-01 19:47:50 +00004623% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004624% NexusInfo *nexus_info,ExceptionInfo *exception)
4625%
4626% A description of each parameter follows:
4627%
4628% o cache_info: the pixel cache.
4629%
cristy4c08aed2011-07-01 19:47:50 +00004630% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004631%
4632% o exception: return any errors or warnings in this structure.
4633%
4634*/
cristy4c08aed2011-07-01 19:47:50 +00004635static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004636 NexusInfo *nexus_info,ExceptionInfo *exception)
4637{
4638 MagickOffsetType
4639 count,
4640 offset;
4641
4642 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004643 extent,
4644 length;
cristy3ed852e2009-09-05 21:47:34 +00004645
cristybb503372010-05-27 20:51:26 +00004646 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004647 y;
4648
cristy4c08aed2011-07-01 19:47:50 +00004649 register unsigned char
4650 *restrict q;
4651
cristybb503372010-05-27 20:51:26 +00004652 size_t
cristy3ed852e2009-09-05 21:47:34 +00004653 rows;
4654
cristy4c08aed2011-07-01 19:47:50 +00004655 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004656 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004657 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004658 return(MagickTrue);
4659 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4660 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004661 length=(MagickSizeType) nexus_info->region.width*
4662 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004663 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004664 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004665 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004666 switch (cache_info->type)
4667 {
4668 case MemoryCache:
4669 case MapCache:
4670 {
cristy4c08aed2011-07-01 19:47:50 +00004671 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004672 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004673
4674 /*
cristy4c08aed2011-07-01 19:47:50 +00004675 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004676 */
cristydd341db2010-03-04 19:06:38 +00004677 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004678 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004679 {
cristy48078b12010-09-23 17:11:01 +00004680 length=extent;
cristydd341db2010-03-04 19:06:38 +00004681 rows=1UL;
4682 }
cristy4c08aed2011-07-01 19:47:50 +00004683 p=(unsigned char *) cache_info->metacontent+offset*
4684 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004685 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004686 {
cristy8f036fe2010-09-18 02:02:00 +00004687 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004688 p+=cache_info->metacontent_extent*cache_info->columns;
4689 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004690 }
4691 break;
4692 }
4693 case DiskCache:
4694 {
4695 /*
cristy4c08aed2011-07-01 19:47:50 +00004696 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004697 */
4698 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4699 {
4700 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4701 cache_info->cache_filename);
4702 return(MagickFalse);
4703 }
cristydd341db2010-03-04 19:06:38 +00004704 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004705 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004706 {
cristy48078b12010-09-23 17:11:01 +00004707 length=extent;
cristydd341db2010-03-04 19:06:38 +00004708 rows=1UL;
4709 }
cristy48078b12010-09-23 17:11:01 +00004710 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004711 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004712 {
cristy48078b12010-09-23 17:11:01 +00004713 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004714 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004715 cache_info->metacontent_extent,length,(unsigned char *) q);
4716 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004717 break;
4718 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004719 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004720 }
cristybb503372010-05-27 20:51:26 +00004721 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004722 {
4723 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4724 cache_info->cache_filename);
4725 return(MagickFalse);
4726 }
4727 break;
4728 }
4729 default:
4730 break;
4731 }
4732 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004733 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004734 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004735 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004736 nexus_info->region.width,(double) nexus_info->region.height,(double)
4737 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004738 return(MagickTrue);
4739}
4740
4741/*
4742%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4743% %
4744% %
4745% %
4746+ R e a d P i x e l C a c h e P i x e l s %
4747% %
4748% %
4749% %
4750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4751%
4752% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4753% cache.
4754%
4755% The format of the ReadPixelCachePixels() method is:
4756%
4757% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4758% NexusInfo *nexus_info,ExceptionInfo *exception)
4759%
4760% A description of each parameter follows:
4761%
4762% o cache_info: the pixel cache.
4763%
4764% o nexus_info: the cache nexus to read the pixels.
4765%
4766% o exception: return any errors or warnings in this structure.
4767%
4768*/
4769static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4770 NexusInfo *nexus_info,ExceptionInfo *exception)
4771{
4772 MagickOffsetType
4773 count,
4774 offset;
4775
4776 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004777 extent,
4778 length;
cristy3ed852e2009-09-05 21:47:34 +00004779
cristy4c08aed2011-07-01 19:47:50 +00004780 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004781 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004782
cristye076a6e2010-08-15 19:59:43 +00004783 register ssize_t
4784 y;
4785
cristybb503372010-05-27 20:51:26 +00004786 size_t
cristy3ed852e2009-09-05 21:47:34 +00004787 rows;
4788
cristy4c08aed2011-07-01 19:47:50 +00004789 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004790 return(MagickTrue);
4791 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4792 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004793 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004794 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004795 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004796 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004797 q=nexus_info->pixels;
4798 switch (cache_info->type)
4799 {
4800 case MemoryCache:
4801 case MapCache:
4802 {
cristy4c08aed2011-07-01 19:47:50 +00004803 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004804 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004805
4806 /*
4807 Read pixels from memory.
4808 */
cristydd341db2010-03-04 19:06:38 +00004809 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004810 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004811 {
cristy48078b12010-09-23 17:11:01 +00004812 length=extent;
cristydd341db2010-03-04 19:06:38 +00004813 rows=1UL;
4814 }
cristyed231572011-07-14 02:18:59 +00004815 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004816 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004817 {
cristy8f036fe2010-09-18 02:02:00 +00004818 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004819 p+=cache_info->number_channels*cache_info->columns;
4820 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004821 }
4822 break;
4823 }
4824 case DiskCache:
4825 {
4826 /*
4827 Read pixels from disk.
4828 */
4829 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4830 {
4831 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4832 cache_info->cache_filename);
4833 return(MagickFalse);
4834 }
cristydd341db2010-03-04 19:06:38 +00004835 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004836 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004837 {
cristy48078b12010-09-23 17:11:01 +00004838 length=extent;
cristydd341db2010-03-04 19:06:38 +00004839 rows=1UL;
4840 }
cristybb503372010-05-27 20:51:26 +00004841 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004842 {
4843 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004844 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004845 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004846 break;
4847 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004848 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004849 }
cristybb503372010-05-27 20:51:26 +00004850 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004851 {
4852 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4853 cache_info->cache_filename);
4854 return(MagickFalse);
4855 }
4856 break;
4857 }
4858 default:
4859 break;
4860 }
4861 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004862 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004863 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004864 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004865 nexus_info->region.width,(double) nexus_info->region.height,(double)
4866 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004867 return(MagickTrue);
4868}
4869
4870/*
4871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4872% %
4873% %
4874% %
4875+ R e f e r e n c e P i x e l C a c h e %
4876% %
4877% %
4878% %
4879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4880%
4881% ReferencePixelCache() increments the reference count associated with the
4882% pixel cache returning a pointer to the cache.
4883%
4884% The format of the ReferencePixelCache method is:
4885%
4886% Cache ReferencePixelCache(Cache cache_info)
4887%
4888% A description of each parameter follows:
4889%
4890% o cache_info: the pixel cache.
4891%
4892*/
cristya6577ff2011-09-02 19:54:26 +00004893MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004894{
4895 CacheInfo
4896 *cache_info;
4897
4898 assert(cache != (Cache *) NULL);
4899 cache_info=(CacheInfo *) cache;
4900 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004901 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004902 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004903 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004904 return(cache_info);
4905}
4906
4907/*
4908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4909% %
4910% %
4911% %
4912+ S e t P i x e l C a c h e M e t h o d s %
4913% %
4914% %
4915% %
4916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4917%
4918% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4919%
4920% The format of the SetPixelCacheMethods() method is:
4921%
4922% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4923%
4924% A description of each parameter follows:
4925%
4926% o cache: the pixel cache.
4927%
4928% o cache_methods: Specifies a pointer to a CacheMethods structure.
4929%
4930*/
cristya6577ff2011-09-02 19:54:26 +00004931MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004932{
4933 CacheInfo
4934 *cache_info;
4935
4936 GetOneAuthenticPixelFromHandler
4937 get_one_authentic_pixel_from_handler;
4938
4939 GetOneVirtualPixelFromHandler
4940 get_one_virtual_pixel_from_handler;
4941
4942 /*
4943 Set cache pixel methods.
4944 */
4945 assert(cache != (Cache) NULL);
4946 assert(cache_methods != (CacheMethods *) NULL);
4947 cache_info=(CacheInfo *) cache;
4948 assert(cache_info->signature == MagickSignature);
4949 if (cache_info->debug != MagickFalse)
4950 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4951 cache_info->filename);
4952 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4953 cache_info->methods.get_virtual_pixel_handler=
4954 cache_methods->get_virtual_pixel_handler;
4955 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4956 cache_info->methods.destroy_pixel_handler=
4957 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004958 if (cache_methods->get_virtual_metacontent_from_handler !=
4959 (GetVirtualMetacontentFromHandler) NULL)
4960 cache_info->methods.get_virtual_metacontent_from_handler=
4961 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004962 if (cache_methods->get_authentic_pixels_handler !=
4963 (GetAuthenticPixelsHandler) NULL)
4964 cache_info->methods.get_authentic_pixels_handler=
4965 cache_methods->get_authentic_pixels_handler;
4966 if (cache_methods->queue_authentic_pixels_handler !=
4967 (QueueAuthenticPixelsHandler) NULL)
4968 cache_info->methods.queue_authentic_pixels_handler=
4969 cache_methods->queue_authentic_pixels_handler;
4970 if (cache_methods->sync_authentic_pixels_handler !=
4971 (SyncAuthenticPixelsHandler) NULL)
4972 cache_info->methods.sync_authentic_pixels_handler=
4973 cache_methods->sync_authentic_pixels_handler;
4974 if (cache_methods->get_authentic_pixels_from_handler !=
4975 (GetAuthenticPixelsFromHandler) NULL)
4976 cache_info->methods.get_authentic_pixels_from_handler=
4977 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004978 if (cache_methods->get_authentic_metacontent_from_handler !=
4979 (GetAuthenticMetacontentFromHandler) NULL)
4980 cache_info->methods.get_authentic_metacontent_from_handler=
4981 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004982 get_one_virtual_pixel_from_handler=
4983 cache_info->methods.get_one_virtual_pixel_from_handler;
4984 if (get_one_virtual_pixel_from_handler !=
4985 (GetOneVirtualPixelFromHandler) NULL)
4986 cache_info->methods.get_one_virtual_pixel_from_handler=
4987 cache_methods->get_one_virtual_pixel_from_handler;
4988 get_one_authentic_pixel_from_handler=
4989 cache_methods->get_one_authentic_pixel_from_handler;
4990 if (get_one_authentic_pixel_from_handler !=
4991 (GetOneAuthenticPixelFromHandler) NULL)
4992 cache_info->methods.get_one_authentic_pixel_from_handler=
4993 cache_methods->get_one_authentic_pixel_from_handler;
4994}
4995
4996/*
4997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4998% %
4999% %
5000% %
5001+ S e t P i x e l C a c h e N e x u s P i x e l s %
5002% %
5003% %
5004% %
5005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5006%
5007% SetPixelCacheNexusPixels() defines the region of the cache for the
5008% specified cache nexus.
5009%
5010% The format of the SetPixelCacheNexusPixels() method is:
5011%
cristy4c08aed2011-07-01 19:47:50 +00005012% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005013% const RectangleInfo *region,NexusInfo *nexus_info,
5014% ExceptionInfo *exception)
5015%
5016% A description of each parameter follows:
5017%
5018% o image: the image.
5019%
5020% o region: A pointer to the RectangleInfo structure that defines the
5021% region of this particular cache nexus.
5022%
5023% o nexus_info: the cache nexus to set.
5024%
5025% o exception: return any errors or warnings in this structure.
5026%
5027*/
cristyabd6e372010-09-15 19:11:26 +00005028
5029static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5030 NexusInfo *nexus_info,ExceptionInfo *exception)
5031{
5032 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5033 return(MagickFalse);
5034 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005035 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005036 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005037 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005038 {
5039 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005040 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005041 nexus_info->length);
5042 }
cristy4c08aed2011-07-01 19:47:50 +00005043 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005044 {
5045 (void) ThrowMagickException(exception,GetMagickModule(),
5046 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5047 cache_info->filename);
5048 return(MagickFalse);
5049 }
5050 return(MagickTrue);
5051}
5052
cristy4c08aed2011-07-01 19:47:50 +00005053static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005054 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5055{
5056 CacheInfo
5057 *cache_info;
5058
5059 MagickBooleanType
5060 status;
5061
cristy3ed852e2009-09-05 21:47:34 +00005062 MagickSizeType
5063 length,
5064 number_pixels;
5065
cristy3ed852e2009-09-05 21:47:34 +00005066 cache_info=(CacheInfo *) image->cache;
5067 assert(cache_info->signature == MagickSignature);
5068 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005069 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005070 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005071 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5072 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005073 {
cristybb503372010-05-27 20:51:26 +00005074 ssize_t
cristybad067a2010-02-15 17:20:55 +00005075 x,
5076 y;
cristy3ed852e2009-09-05 21:47:34 +00005077
cristyeaedf062010-05-29 22:36:02 +00005078 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5079 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005080 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5081 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005082 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005083 ((nexus_info->region.width == cache_info->columns) ||
5084 ((nexus_info->region.width % cache_info->columns) == 0)))))
5085 {
5086 MagickOffsetType
5087 offset;
5088
5089 /*
5090 Pixels are accessed directly from memory.
5091 */
5092 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5093 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005094 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005095 offset;
5096 nexus_info->metacontent=(void *) NULL;
5097 if (cache_info->metacontent_extent != 0)
5098 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5099 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005100 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005101 }
5102 }
5103 /*
5104 Pixels are stored in a cache region until they are synced to the cache.
5105 */
5106 number_pixels=(MagickSizeType) nexus_info->region.width*
5107 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005108 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005109 if (cache_info->metacontent_extent != 0)
5110 length+=number_pixels*cache_info->metacontent_extent;
5111 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005112 {
5113 nexus_info->length=length;
5114 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5115 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005116 {
5117 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005118 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005119 }
cristy3ed852e2009-09-05 21:47:34 +00005120 }
5121 else
5122 if (nexus_info->length != length)
5123 {
5124 RelinquishCacheNexusPixels(nexus_info);
5125 nexus_info->length=length;
5126 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5127 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005128 {
5129 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005130 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005131 }
cristy3ed852e2009-09-05 21:47:34 +00005132 }
5133 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005134 nexus_info->metacontent=(void *) NULL;
5135 if (cache_info->metacontent_extent != 0)
5136 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005137 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005138 return(nexus_info->pixels);
5139}
5140
5141/*
5142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5143% %
5144% %
5145% %
5146% 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 %
5147% %
5148% %
5149% %
5150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151%
5152% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5153% pixel cache and returns the previous setting. A virtual pixel is any pixel
5154% access that is outside the boundaries of the image cache.
5155%
5156% The format of the SetPixelCacheVirtualMethod() method is:
5157%
5158% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5159% const VirtualPixelMethod virtual_pixel_method)
5160%
5161% A description of each parameter follows:
5162%
5163% o image: the image.
5164%
5165% o virtual_pixel_method: choose the type of virtual pixel.
5166%
5167*/
cristyd1dd6e42011-09-04 01:46:08 +00005168MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005169 const VirtualPixelMethod virtual_pixel_method)
5170{
5171 CacheInfo
5172 *cache_info;
5173
5174 VirtualPixelMethod
5175 method;
5176
5177 assert(image != (Image *) NULL);
5178 assert(image->signature == MagickSignature);
5179 if (image->debug != MagickFalse)
5180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5181 assert(image->cache != (Cache) NULL);
5182 cache_info=(CacheInfo *) image->cache;
5183 assert(cache_info->signature == MagickSignature);
5184 method=cache_info->virtual_pixel_method;
5185 cache_info->virtual_pixel_method=virtual_pixel_method;
5186 return(method);
5187}
5188
5189/*
5190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5191% %
5192% %
5193% %
5194+ 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 %
5195% %
5196% %
5197% %
5198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5199%
5200% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5201% in-memory or disk cache. The method returns MagickTrue if the pixel region
5202% is synced, otherwise MagickFalse.
5203%
5204% The format of the SyncAuthenticPixelCacheNexus() method is:
5205%
5206% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5207% NexusInfo *nexus_info,ExceptionInfo *exception)
5208%
5209% A description of each parameter follows:
5210%
5211% o image: the image.
5212%
5213% o nexus_info: the cache nexus to sync.
5214%
5215% o exception: return any errors or warnings in this structure.
5216%
5217*/
cristya6577ff2011-09-02 19:54:26 +00005218MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005219 NexusInfo *nexus_info,ExceptionInfo *exception)
5220{
5221 CacheInfo
5222 *cache_info;
5223
5224 MagickBooleanType
5225 status;
5226
5227 /*
5228 Transfer pixels to the cache.
5229 */
5230 assert(image != (Image *) NULL);
5231 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005232 if (image->cache == (Cache) NULL)
5233 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5234 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005235 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005236 if (cache_info->type == UndefinedCache)
5237 return(MagickFalse);
5238 if ((image->clip_mask != (Image *) NULL) &&
5239 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5240 return(MagickFalse);
5241 if ((image->mask != (Image *) NULL) &&
5242 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5243 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005244 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005245 return(MagickTrue);
5246 assert(cache_info->signature == MagickSignature);
5247 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005248 if ((cache_info->metacontent_extent != 0) &&
5249 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005250 return(MagickFalse);
5251 return(status);
5252}
5253
5254/*
5255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5256% %
5257% %
5258% %
5259+ S y n c A u t h e n t i c P i x e l C a c h e %
5260% %
5261% %
5262% %
5263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5264%
5265% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5266% or disk cache. The method returns MagickTrue if the pixel region is synced,
5267% otherwise MagickFalse.
5268%
5269% The format of the SyncAuthenticPixelsCache() method is:
5270%
5271% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5272% ExceptionInfo *exception)
5273%
5274% A description of each parameter follows:
5275%
5276% o image: the image.
5277%
5278% o exception: return any errors or warnings in this structure.
5279%
5280*/
5281static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5282 ExceptionInfo *exception)
5283{
5284 CacheInfo
5285 *cache_info;
5286
cristy5c9e6f22010-09-17 17:31:01 +00005287 const int
5288 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005289
cristy4c08aed2011-07-01 19:47:50 +00005290 MagickBooleanType
5291 status;
5292
cristye7cc7cf2010-09-21 13:26:47 +00005293 assert(image != (Image *) NULL);
5294 assert(image->signature == MagickSignature);
5295 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005296 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005297 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005298 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005299 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5300 exception);
5301 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005302}
5303
5304/*
5305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5306% %
5307% %
5308% %
5309% S y n c A u t h e n t i c P i x e l s %
5310% %
5311% %
5312% %
5313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5314%
5315% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5316% The method returns MagickTrue if the pixel region is flushed, otherwise
5317% MagickFalse.
5318%
5319% The format of the SyncAuthenticPixels() method is:
5320%
5321% MagickBooleanType SyncAuthenticPixels(Image *image,
5322% ExceptionInfo *exception)
5323%
5324% A description of each parameter follows:
5325%
5326% o image: the image.
5327%
5328% o exception: return any errors or warnings in this structure.
5329%
5330*/
5331MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5332 ExceptionInfo *exception)
5333{
5334 CacheInfo
5335 *cache_info;
5336
cristy2036f5c2010-09-19 21:18:17 +00005337 const int
5338 id = GetOpenMPThreadId();
5339
cristy4c08aed2011-07-01 19:47:50 +00005340 MagickBooleanType
5341 status;
5342
cristy3ed852e2009-09-05 21:47:34 +00005343 assert(image != (Image *) NULL);
5344 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005345 assert(image->cache != (Cache) NULL);
5346 cache_info=(CacheInfo *) image->cache;
5347 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005348 if (cache_info->methods.sync_authentic_pixels_handler !=
5349 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005350 {
5351 status=cache_info->methods.sync_authentic_pixels_handler(image,
5352 exception);
5353 return(status);
5354 }
cristy2036f5c2010-09-19 21:18:17 +00005355 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005356 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5357 exception);
5358 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005359}
5360
5361/*
5362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5363% %
5364% %
5365% %
cristyd1dd6e42011-09-04 01:46:08 +00005366+ 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 +00005367% %
5368% %
5369% %
5370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5371%
5372% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5373% The method returns MagickTrue if the pixel region is flushed, otherwise
5374% MagickFalse.
5375%
5376% The format of the SyncImagePixelCache() method is:
5377%
5378% MagickBooleanType SyncImagePixelCache(Image *image,
5379% ExceptionInfo *exception)
5380%
5381% A description of each parameter follows:
5382%
5383% o image: the image.
5384%
5385% o exception: return any errors or warnings in this structure.
5386%
5387*/
cristyd1dd6e42011-09-04 01:46:08 +00005388MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005389 ExceptionInfo *exception)
5390{
5391 CacheInfo
5392 *cache_info;
5393
5394 assert(image != (Image *) NULL);
5395 assert(exception != (ExceptionInfo *) NULL);
5396 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5397 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5398}
5399
5400/*
5401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5402% %
5403% %
5404% %
cristy4c08aed2011-07-01 19:47:50 +00005405+ 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 +00005406% %
5407% %
5408% %
5409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5410%
cristy4c08aed2011-07-01 19:47:50 +00005411% WritePixelCacheMetacontent() writes the meta-content to the specified region
5412% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005413%
cristy4c08aed2011-07-01 19:47:50 +00005414% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005415%
cristy4c08aed2011-07-01 19:47:50 +00005416% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005417% NexusInfo *nexus_info,ExceptionInfo *exception)
5418%
5419% A description of each parameter follows:
5420%
5421% o cache_info: the pixel cache.
5422%
cristy4c08aed2011-07-01 19:47:50 +00005423% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005424%
5425% o exception: return any errors or warnings in this structure.
5426%
5427*/
cristy4c08aed2011-07-01 19:47:50 +00005428static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005429 NexusInfo *nexus_info,ExceptionInfo *exception)
5430{
5431 MagickOffsetType
5432 count,
5433 offset;
5434
5435 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005436 extent,
5437 length;
cristy3ed852e2009-09-05 21:47:34 +00005438
cristy4c08aed2011-07-01 19:47:50 +00005439 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005440 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005441
cristybb503372010-05-27 20:51:26 +00005442 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005443 y;
5444
cristybb503372010-05-27 20:51:26 +00005445 size_t
cristy3ed852e2009-09-05 21:47:34 +00005446 rows;
5447
cristy4c08aed2011-07-01 19:47:50 +00005448 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005449 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005450 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005451 return(MagickTrue);
5452 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5453 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005454 length=(MagickSizeType) nexus_info->region.width*
5455 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005456 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005457 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005458 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005459 switch (cache_info->type)
5460 {
5461 case MemoryCache:
5462 case MapCache:
5463 {
cristy4c08aed2011-07-01 19:47:50 +00005464 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005465 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005466
5467 /*
cristy4c08aed2011-07-01 19:47:50 +00005468 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005469 */
cristydd341db2010-03-04 19:06:38 +00005470 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005471 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005472 {
cristy48078b12010-09-23 17:11:01 +00005473 length=extent;
cristydd341db2010-03-04 19:06:38 +00005474 rows=1UL;
5475 }
cristy4c08aed2011-07-01 19:47:50 +00005476 q=(unsigned char *) cache_info->metacontent+offset*
5477 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005478 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005479 {
cristy8f036fe2010-09-18 02:02:00 +00005480 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005481 p+=nexus_info->region.width*cache_info->metacontent_extent;
5482 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005483 }
5484 break;
5485 }
5486 case DiskCache:
5487 {
5488 /*
cristy4c08aed2011-07-01 19:47:50 +00005489 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005490 */
5491 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5492 {
5493 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5494 cache_info->cache_filename);
5495 return(MagickFalse);
5496 }
cristydd341db2010-03-04 19:06:38 +00005497 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005498 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005499 {
cristy48078b12010-09-23 17:11:01 +00005500 length=extent;
cristydd341db2010-03-04 19:06:38 +00005501 rows=1UL;
5502 }
cristy48078b12010-09-23 17:11:01 +00005503 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005504 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005505 {
cristy48078b12010-09-23 17:11:01 +00005506 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005507 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005508 cache_info->metacontent_extent,length,(const unsigned char *) p);
5509 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005510 break;
cristy4c08aed2011-07-01 19:47:50 +00005511 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005512 offset+=cache_info->columns;
5513 }
cristybb503372010-05-27 20:51:26 +00005514 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005515 {
5516 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5517 cache_info->cache_filename);
5518 return(MagickFalse);
5519 }
5520 break;
5521 }
5522 default:
5523 break;
5524 }
5525 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005526 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005527 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005528 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005529 nexus_info->region.width,(double) nexus_info->region.height,(double)
5530 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005531 return(MagickTrue);
5532}
5533
5534/*
5535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5536% %
5537% %
5538% %
5539+ W r i t e C a c h e P i x e l s %
5540% %
5541% %
5542% %
5543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5544%
5545% WritePixelCachePixels() writes image pixels to the specified region of the
5546% pixel cache.
5547%
5548% The format of the WritePixelCachePixels() method is:
5549%
5550% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5551% NexusInfo *nexus_info,ExceptionInfo *exception)
5552%
5553% A description of each parameter follows:
5554%
5555% o cache_info: the pixel cache.
5556%
5557% o nexus_info: the cache nexus to write the pixels.
5558%
5559% o exception: return any errors or warnings in this structure.
5560%
5561*/
5562static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5563 NexusInfo *nexus_info,ExceptionInfo *exception)
5564{
5565 MagickOffsetType
5566 count,
5567 offset;
5568
5569 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005570 extent,
5571 length;
cristy3ed852e2009-09-05 21:47:34 +00005572
cristy4c08aed2011-07-01 19:47:50 +00005573 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005574 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005575
cristybb503372010-05-27 20:51:26 +00005576 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005577 y;
5578
cristybb503372010-05-27 20:51:26 +00005579 size_t
cristy3ed852e2009-09-05 21:47:34 +00005580 rows;
5581
cristy4c08aed2011-07-01 19:47:50 +00005582 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005583 return(MagickTrue);
5584 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5585 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005586 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005587 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005588 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005589 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005590 p=nexus_info->pixels;
5591 switch (cache_info->type)
5592 {
5593 case MemoryCache:
5594 case MapCache:
5595 {
cristy4c08aed2011-07-01 19:47:50 +00005596 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005597 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005598
5599 /*
5600 Write pixels to memory.
5601 */
cristydd341db2010-03-04 19:06:38 +00005602 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005603 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005604 {
cristy48078b12010-09-23 17:11:01 +00005605 length=extent;
cristydd341db2010-03-04 19:06:38 +00005606 rows=1UL;
5607 }
cristyed231572011-07-14 02:18:59 +00005608 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005609 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005610 {
cristy8f036fe2010-09-18 02:02:00 +00005611 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005612 p+=nexus_info->region.width*cache_info->number_channels;
5613 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005614 }
5615 break;
5616 }
5617 case DiskCache:
5618 {
5619 /*
5620 Write pixels to disk.
5621 */
5622 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5623 {
5624 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5625 cache_info->cache_filename);
5626 return(MagickFalse);
5627 }
cristydd341db2010-03-04 19:06:38 +00005628 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005629 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005630 {
cristy48078b12010-09-23 17:11:01 +00005631 length=extent;
cristydd341db2010-03-04 19:06:38 +00005632 rows=1UL;
5633 }
cristybb503372010-05-27 20:51:26 +00005634 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005635 {
5636 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005637 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005638 p);
5639 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005640 break;
cristyed231572011-07-14 02:18:59 +00005641 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005642 offset+=cache_info->columns;
5643 }
cristybb503372010-05-27 20:51:26 +00005644 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005645 {
5646 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5647 cache_info->cache_filename);
5648 return(MagickFalse);
5649 }
5650 break;
5651 }
5652 default:
5653 break;
5654 }
5655 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005656 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005657 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005658 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005659 nexus_info->region.width,(double) nexus_info->region.height,(double)
5660 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005661 return(MagickTrue);
5662}