blob: 0c630bb70608cb1c54b4af8cf3872bfc542d6a20 [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
cristycacc77e2011-12-31 17:20:21 +0000922 Quantum
923 sans;
924
cristy4c08aed2011-07-01 19:47:50 +0000925 register ssize_t
926 x;
927
928 size_t
cristy3ed852e2009-09-05 21:47:34 +0000929 length;
930
cristy4c08aed2011-07-01 19:47:50 +0000931 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000932 y;
933
cristy4c08aed2011-07-01 19:47:50 +0000934 unsigned char
935 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000936
cristy4c08aed2011-07-01 19:47:50 +0000937 /*
938 Clone pixel cache (unoptimized).
939 */
cristy3ed852e2009-09-05 21:47:34 +0000940 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000941 {
cristy4c08aed2011-07-01 19:47:50 +0000942 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
943 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
944 else
945 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
947 else
948 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
949 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
950 else
951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
952 }
cristyed231572011-07-14 02:18:59 +0000953 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
954 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000955 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000956 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000957 if (blob == (unsigned char *) NULL)
958 {
959 (void) ThrowMagickException(exception,GetMagickModule(),
960 ResourceLimitError,"MemoryAllocationFailed","`%s'",
961 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000962 return(MagickFalse);
963 }
cristy4c08aed2011-07-01 19:47:50 +0000964 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
965 cache_offset=0;
966 clone_offset=0;
967 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000968 {
cristy4c08aed2011-07-01 19:47:50 +0000969 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000970 {
cristy4c08aed2011-07-01 19:47:50 +0000971 blob=(unsigned char *) RelinquishMagickMemory(blob);
972 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000973 cache_info->cache_filename);
974 return(MagickFalse);
975 }
cristy4c08aed2011-07-01 19:47:50 +0000976 cache_offset=cache_info->offset;
977 }
cristy4d9c1922011-12-31 18:37:34 +0000978 if ((cache_info->type != MemoryCache) && (clone_info->type != MemoryCache) &&
979 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
980 {
981 /*
982 Inplace cloning not reliable.
983 */
984 (void) ClosePixelCacheOnDisk(clone_info);
985 if (cache_info->type == MapCache)
986 {
987 clone_info->pixels=(Quantum *) UnmapBlob(clone_info->pixels,(size_t)
988 clone_info->length);
989 RelinquishMagickResource(MapResource,clone_info->length);
990 }
991 *clone_info->cache_filename='\0';
992 clone_info->type=DiskCache;
993 }
cristy4c08aed2011-07-01 19:47:50 +0000994 if (clone_info->type == DiskCache)
995 {
cristy4d9c1922011-12-31 18:37:34 +0000996 (void) ClosePixelCacheOnDisk(clone_info);
cristy3dedf062011-07-02 14:07:40 +0000997 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
cristy4c08aed2011-07-01 19:47:50 +0000999 if (cache_info->type == DiskCache)
1000 (void) ClosePixelCacheOnDisk(cache_info);
1001 blob=(unsigned char *) RelinquishMagickMemory(blob);
1002 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1003 clone_info->cache_filename);
1004 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001005 }
cristy4c08aed2011-07-01 19:47:50 +00001006 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +00001007 }
1008 /*
cristy4c08aed2011-07-01 19:47:50 +00001009 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001010 */
cristycacc77e2011-12-31 17:20:21 +00001011 sans=0;
cristy4c08aed2011-07-01 19:47:50 +00001012 status=MagickTrue;
1013 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001014 {
cristy4c08aed2011-07-01 19:47:50 +00001015 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001016 {
cristy9e0719b2011-12-29 03:45:45 +00001017 register ssize_t
1018 i;
1019
cristy3ed852e2009-09-05 21:47:34 +00001020 /*
cristy4c08aed2011-07-01 19:47:50 +00001021 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001022 */
cristyed231572011-07-14 02:18:59 +00001023 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001024 if (cache_info->type != DiskCache)
1025 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1026 length);
cristy3ed852e2009-09-05 21:47:34 +00001027 else
1028 {
cristy4c08aed2011-07-01 19:47:50 +00001029 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1030 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001031 {
cristy4c08aed2011-07-01 19:47:50 +00001032 status=MagickFalse;
1033 break;
cristy3ed852e2009-09-05 21:47:34 +00001034 }
1035 }
cristy4c08aed2011-07-01 19:47:50 +00001036 cache_offset+=length;
1037 if ((y < (ssize_t) clone_info->rows) &&
1038 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001039 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001040 {
cristy9e0719b2011-12-29 03:45:45 +00001041 PixelChannel
1042 channel;
1043
1044 PixelTrait
1045 traits;
1046
1047 ssize_t
1048 offset;
1049
cristy4c08aed2011-07-01 19:47:50 +00001050 /*
cristy3b8fe922011-12-29 18:56:23 +00001051 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001052 */
cristy9e0719b2011-12-29 03:45:45 +00001053 channel=clone_info->channel_map[i].channel;
1054 traits=cache_info->channel_map[channel].traits;
1055 if (traits == UndefinedPixelTrait)
1056 {
cristycacc77e2011-12-31 17:20:21 +00001057 if (clone_info->type != DiskCache)
1058 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1059 (unsigned char *) &sans,sizeof(Quantum));
1060 else
1061 {
1062 count=WritePixelCacheRegion(clone_info,clone_offset,
1063 sizeof(Quantum),(unsigned char *) &sans);
1064 if ((MagickSizeType) count != sizeof(Quantum))
1065 {
1066 status=MagickFalse;
1067 break;
1068 }
1069 }
cristy9e0719b2011-12-29 03:45:45 +00001070 }
cristy4c08aed2011-07-01 19:47:50 +00001071 else
1072 {
cristycacc77e2011-12-31 17:20:21 +00001073 offset=cache_info->channel_map[channel].offset;
1074 if (clone_info->type != DiskCache)
1075 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1076 blob+offset*sizeof(Quantum),sizeof(Quantum));
1077 else
cristy4c08aed2011-07-01 19:47:50 +00001078 {
cristycacc77e2011-12-31 17:20:21 +00001079 count=WritePixelCacheRegion(clone_info,clone_offset,
1080 sizeof(Quantum),blob+offset*sizeof(Quantum));
1081 if ((MagickSizeType) count != sizeof(Quantum))
1082 {
1083 status=MagickFalse;
1084 break;
1085 }
cristy4c08aed2011-07-01 19:47:50 +00001086 }
1087 }
cristy9e0719b2011-12-29 03:45:45 +00001088 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001089 }
1090 }
cristyed231572011-07-14 02:18:59 +00001091 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001092 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1093 for ( ; x < (ssize_t) clone_info->columns; x++)
1094 {
1095 /*
cristy9e0719b2011-12-29 03:45:45 +00001096 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001097 */
1098 if (clone_info->type != DiskCache)
1099 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1100 length);
1101 else
1102 {
1103 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1104 if ((MagickSizeType) count != length)
1105 {
1106 status=MagickFalse;
1107 break;
1108 }
1109 }
1110 clone_offset+=length;
1111 }
1112 }
cristyed231572011-07-14 02:18:59 +00001113 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001114 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1115 for ( ; y < (ssize_t) clone_info->rows; y++)
1116 {
1117 /*
cristy9e0719b2011-12-29 03:45:45 +00001118 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001119 */
1120 for (x=0; x < (ssize_t) clone_info->columns; x++)
1121 {
1122 if (clone_info->type != DiskCache)
1123 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1124 length);
1125 else
1126 {
1127 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1128 if ((MagickSizeType) count != length)
1129 {
1130 status=MagickFalse;
1131 break;
1132 }
1133 }
1134 clone_offset+=length;
1135 }
1136 }
cristy9e0719b2011-12-29 03:45:45 +00001137 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001138 (clone_info->metacontent_extent != 0))
1139 {
1140 /*
1141 Clone metacontent.
1142 */
1143 for (y=0; y < (ssize_t) cache_info->rows; y++)
1144 {
1145 for (x=0; x < (ssize_t) cache_info->columns; x++)
1146 {
1147 /*
1148 Read a set of metacontent.
1149 */
1150 length=cache_info->metacontent_extent;
1151 if (cache_info->type != DiskCache)
1152 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1153 cache_offset,length);
1154 else
1155 {
1156 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1157 if ((MagickSizeType) count != length)
1158 {
1159 status=MagickFalse;
1160 break;
1161 }
1162 }
1163 cache_offset+=length;
1164 if ((y < (ssize_t) clone_info->rows) &&
1165 (x < (ssize_t) clone_info->columns))
1166 {
1167 /*
1168 Write a set of metacontent.
1169 */
1170 length=clone_info->metacontent_extent;
1171 if (clone_info->type != DiskCache)
1172 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1173 blob,length);
1174 else
1175 {
1176 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1177 blob);
1178 if ((MagickSizeType) count != length)
1179 {
1180 status=MagickFalse;
1181 break;
1182 }
1183 }
1184 clone_offset+=length;
1185 }
1186 }
1187 length=clone_info->metacontent_extent;
1188 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1189 for ( ; x < (ssize_t) clone_info->columns; x++)
1190 {
1191 /*
cristy9e0719b2011-12-29 03:45:45 +00001192 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001193 */
1194 if (clone_info->type != DiskCache)
1195 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1196 blob,length);
1197 else
1198 {
cristy208b1002011-08-07 18:51:50 +00001199 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001200 if ((MagickSizeType) count != length)
1201 {
1202 status=MagickFalse;
1203 break;
1204 }
1205 }
1206 clone_offset+=length;
1207 }
1208 }
1209 length=clone_info->metacontent_extent;
1210 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1211 for ( ; y < (ssize_t) clone_info->rows; y++)
1212 {
1213 /*
cristy9e0719b2011-12-29 03:45:45 +00001214 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001215 */
1216 for (x=0; x < (ssize_t) clone_info->columns; x++)
1217 {
1218 if (clone_info->type != DiskCache)
1219 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1220 blob,length);
1221 else
1222 {
1223 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1224 if ((MagickSizeType) count != length)
1225 {
1226 status=MagickFalse;
1227 break;
1228 }
1229 }
1230 clone_offset+=length;
1231 }
1232 }
1233 }
1234 if (clone_info->type == DiskCache)
1235 (void) ClosePixelCacheOnDisk(clone_info);
1236 if (cache_info->type == DiskCache)
1237 (void) ClosePixelCacheOnDisk(cache_info);
1238 blob=(unsigned char *) RelinquishMagickMemory(blob);
1239 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001240}
1241
1242static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1243 CacheInfo *cache_info,ExceptionInfo *exception)
1244{
cristy3dfccb22011-12-28 21:47:20 +00001245 PixelChannelMap
1246 *p,
1247 *q;
1248
cristy5a7fbfb2010-11-06 16:10:59 +00001249 if (cache_info->type == PingCache)
1250 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001251 p=cache_info->channel_map;
1252 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001253 if ((cache_info->columns == clone_info->columns) &&
1254 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001255 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001256 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001257 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1258 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1259 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001260}
1261
1262/*
1263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264% %
1265% %
1266% %
1267+ C l o n e P i x e l C a c h e M e t h o d s %
1268% %
1269% %
1270% %
1271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1272%
1273% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1274% another.
1275%
1276% The format of the ClonePixelCacheMethods() method is:
1277%
1278% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1279%
1280% A description of each parameter follows:
1281%
1282% o clone: Specifies a pointer to a Cache structure.
1283%
1284% o cache: the pixel cache.
1285%
1286*/
cristya6577ff2011-09-02 19:54:26 +00001287MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001288{
1289 CacheInfo
1290 *cache_info,
1291 *source_info;
1292
1293 assert(clone != (Cache) NULL);
1294 source_info=(CacheInfo *) clone;
1295 assert(source_info->signature == MagickSignature);
1296 if (source_info->debug != MagickFalse)
1297 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1298 source_info->filename);
1299 assert(cache != (Cache) NULL);
1300 cache_info=(CacheInfo *) cache;
1301 assert(cache_info->signature == MagickSignature);
1302 source_info->methods=cache_info->methods;
1303}
1304
1305/*
1306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307% %
1308% %
1309% %
1310+ D e s t r o y I m a g e P i x e l C a c h e %
1311% %
1312% %
1313% %
1314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315%
1316% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1317%
1318% The format of the DestroyImagePixelCache() method is:
1319%
1320% void DestroyImagePixelCache(Image *image)
1321%
1322% A description of each parameter follows:
1323%
1324% o image: the image.
1325%
1326*/
1327static void DestroyImagePixelCache(Image *image)
1328{
1329 assert(image != (Image *) NULL);
1330 assert(image->signature == MagickSignature);
1331 if (image->debug != MagickFalse)
1332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1333 if (image->cache == (void *) NULL)
1334 return;
1335 image->cache=DestroyPixelCache(image->cache);
1336}
1337
1338/*
1339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340% %
1341% %
1342% %
1343+ D e s t r o y I m a g e P i x e l s %
1344% %
1345% %
1346% %
1347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348%
1349% DestroyImagePixels() deallocates memory associated with the pixel cache.
1350%
1351% The format of the DestroyImagePixels() method is:
1352%
1353% void DestroyImagePixels(Image *image)
1354%
1355% A description of each parameter follows:
1356%
1357% o image: the image.
1358%
1359*/
1360MagickExport void DestroyImagePixels(Image *image)
1361{
1362 CacheInfo
1363 *cache_info;
1364
1365 assert(image != (const Image *) NULL);
1366 assert(image->signature == MagickSignature);
1367 if (image->debug != MagickFalse)
1368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1369 assert(image->cache != (Cache) NULL);
1370 cache_info=(CacheInfo *) image->cache;
1371 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001372 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1373 {
1374 cache_info->methods.destroy_pixel_handler(image);
1375 return;
1376 }
cristy2036f5c2010-09-19 21:18:17 +00001377 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001378}
1379
1380/*
1381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1382% %
1383% %
1384% %
1385+ D e s t r o y P i x e l C a c h e %
1386% %
1387% %
1388% %
1389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1390%
1391% DestroyPixelCache() deallocates memory associated with the pixel cache.
1392%
1393% The format of the DestroyPixelCache() method is:
1394%
1395% Cache DestroyPixelCache(Cache cache)
1396%
1397% A description of each parameter follows:
1398%
1399% o cache: the pixel cache.
1400%
1401*/
1402
1403static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1404{
1405 switch (cache_info->type)
1406 {
1407 case MemoryCache:
1408 {
1409 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001410 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001411 cache_info->pixels);
1412 else
cristy4c08aed2011-07-01 19:47:50 +00001413 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001414 (size_t) cache_info->length);
1415 RelinquishMagickResource(MemoryResource,cache_info->length);
1416 break;
1417 }
1418 case MapCache:
1419 {
cristy4c08aed2011-07-01 19:47:50 +00001420 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001421 cache_info->length);
1422 RelinquishMagickResource(MapResource,cache_info->length);
1423 }
1424 case DiskCache:
1425 {
1426 if (cache_info->file != -1)
1427 (void) ClosePixelCacheOnDisk(cache_info);
1428 RelinquishMagickResource(DiskResource,cache_info->length);
1429 break;
1430 }
1431 default:
1432 break;
1433 }
1434 cache_info->type=UndefinedCache;
1435 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001436 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001437}
1438
cristya6577ff2011-09-02 19:54:26 +00001439MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001440{
1441 CacheInfo
1442 *cache_info;
1443
cristy3ed852e2009-09-05 21:47:34 +00001444 assert(cache != (Cache) NULL);
1445 cache_info=(CacheInfo *) cache;
1446 assert(cache_info->signature == MagickSignature);
1447 if (cache_info->debug != MagickFalse)
1448 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1449 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001450 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001451 cache_info->reference_count--;
1452 if (cache_info->reference_count != 0)
1453 {
cristyf84a1932010-01-03 18:00:18 +00001454 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001455 return((Cache) NULL);
1456 }
cristyf84a1932010-01-03 18:00:18 +00001457 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001458 if (cache_resources != (SplayTreeInfo *) NULL)
1459 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001460 if (cache_info->debug != MagickFalse)
1461 {
1462 char
1463 message[MaxTextExtent];
1464
cristyb51dff52011-05-19 16:55:47 +00001465 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001466 cache_info->filename);
1467 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1468 }
cristyc2e1bdd2009-09-10 23:43:34 +00001469 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1470 (cache_info->type != DiskCache)))
1471 RelinquishPixelCachePixels(cache_info);
1472 else
1473 {
1474 RelinquishPixelCachePixels(cache_info);
1475 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1476 }
cristy3ed852e2009-09-05 21:47:34 +00001477 *cache_info->cache_filename='\0';
1478 if (cache_info->nexus_info != (NexusInfo **) NULL)
1479 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1480 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001481 if (cache_info->random_info != (RandomInfo *) NULL)
1482 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001483 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1484 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1485 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1486 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001487 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001488 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001489 cache=(Cache) NULL;
1490 return(cache);
1491}
1492
1493/*
1494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495% %
1496% %
1497% %
1498+ D e s t r o y P i x e l C a c h e N e x u s %
1499% %
1500% %
1501% %
1502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503%
1504% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1505%
1506% The format of the DestroyPixelCacheNexus() method is:
1507%
1508% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001509% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001510%
1511% A description of each parameter follows:
1512%
1513% o nexus_info: the nexus to destroy.
1514%
1515% o number_threads: the number of nexus threads.
1516%
1517*/
1518
1519static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1520{
1521 if (nexus_info->mapped == MagickFalse)
1522 (void) RelinquishMagickMemory(nexus_info->cache);
1523 else
1524 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001525 nexus_info->cache=(Quantum *) NULL;
1526 nexus_info->pixels=(Quantum *) NULL;
1527 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001528 nexus_info->length=0;
1529 nexus_info->mapped=MagickFalse;
1530}
1531
cristya6577ff2011-09-02 19:54:26 +00001532MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001533 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001534{
cristybb503372010-05-27 20:51:26 +00001535 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001536 i;
1537
1538 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001539 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001540 {
cristy4c08aed2011-07-01 19:47:50 +00001541 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001542 RelinquishCacheNexusPixels(nexus_info[i]);
1543 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001544 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001545 }
cristyb41ee102010-10-04 16:46:15 +00001546 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001547 return(nexus_info);
1548}
1549
1550/*
1551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552% %
1553% %
1554% %
cristy4c08aed2011-07-01 19:47:50 +00001555% 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 +00001556% %
1557% %
1558% %
1559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560%
cristy4c08aed2011-07-01 19:47:50 +00001561% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1562% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1563% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001564%
cristy4c08aed2011-07-01 19:47:50 +00001565% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001566%
cristy4c08aed2011-07-01 19:47:50 +00001567% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001568%
1569% A description of each parameter follows:
1570%
1571% o image: the image.
1572%
1573*/
cristy4c08aed2011-07-01 19:47:50 +00001574MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001575{
1576 CacheInfo
1577 *cache_info;
1578
cristy5c9e6f22010-09-17 17:31:01 +00001579 const int
1580 id = GetOpenMPThreadId();
1581
cristy4c08aed2011-07-01 19:47:50 +00001582 void
1583 *metacontent;
1584
cristye7cc7cf2010-09-21 13:26:47 +00001585 assert(image != (const Image *) NULL);
1586 assert(image->signature == MagickSignature);
1587 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001588 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001589 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001590 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1591 (GetAuthenticMetacontentFromHandler) NULL)
1592 {
1593 metacontent=cache_info->methods.
1594 get_authentic_metacontent_from_handler(image);
1595 return(metacontent);
1596 }
cristy6ebe97c2010-07-03 01:17:28 +00001597 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001598 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1599 cache_info->nexus_info[id]);
1600 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001601}
1602
1603/*
1604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1605% %
1606% %
1607% %
cristy4c08aed2011-07-01 19:47:50 +00001608+ 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 +00001609% %
1610% %
1611% %
1612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1613%
cristy4c08aed2011-07-01 19:47:50 +00001614% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1615% with the last call to QueueAuthenticPixelsCache() or
1616% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001617%
cristy4c08aed2011-07-01 19:47:50 +00001618% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001619%
cristy4c08aed2011-07-01 19:47:50 +00001620% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001621%
1622% A description of each parameter follows:
1623%
1624% o image: the image.
1625%
1626*/
cristy4c08aed2011-07-01 19:47:50 +00001627static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001628{
1629 CacheInfo
1630 *cache_info;
1631
cristy2036f5c2010-09-19 21:18:17 +00001632 const int
1633 id = GetOpenMPThreadId();
1634
cristy4c08aed2011-07-01 19:47:50 +00001635 void
1636 *metacontent;
1637
cristy3ed852e2009-09-05 21:47:34 +00001638 assert(image != (const Image *) NULL);
1639 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001640 assert(image->cache != (Cache) NULL);
1641 cache_info=(CacheInfo *) image->cache;
1642 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001643 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001644 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1645 cache_info->nexus_info[id]);
1646 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001647}
1648
1649/*
1650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1651% %
1652% %
1653% %
1654+ 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 %
1655% %
1656% %
1657% %
1658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1659%
1660% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1661% disk pixel cache as defined by the geometry parameters. A pointer to the
1662% pixels is returned if the pixels are transferred, otherwise a NULL is
1663% returned.
1664%
1665% The format of the GetAuthenticPixelCacheNexus() method is:
1666%
cristy4c08aed2011-07-01 19:47:50 +00001667% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001668% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001669% NexusInfo *nexus_info,ExceptionInfo *exception)
1670%
1671% A description of each parameter follows:
1672%
1673% o image: the image.
1674%
1675% o x,y,columns,rows: These values define the perimeter of a region of
1676% pixels.
1677%
1678% o nexus_info: the cache nexus to return.
1679%
1680% o exception: return any errors or warnings in this structure.
1681%
1682*/
1683
cristy4c08aed2011-07-01 19:47:50 +00001684static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001685 NexusInfo *nexus_info)
1686{
cristy4c08aed2011-07-01 19:47:50 +00001687 MagickBooleanType
1688 status;
1689
cristy3ed852e2009-09-05 21:47:34 +00001690 MagickOffsetType
1691 offset;
1692
cristy73724512010-04-12 14:43:14 +00001693 if (cache_info->type == PingCache)
1694 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001695 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1696 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001697 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001698 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001699 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001700}
1701
cristya6577ff2011-09-02 19:54:26 +00001702MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001703 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001704 NexusInfo *nexus_info,ExceptionInfo *exception)
1705{
1706 CacheInfo
1707 *cache_info;
1708
cristy4c08aed2011-07-01 19:47:50 +00001709 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001710 *q;
cristy3ed852e2009-09-05 21:47:34 +00001711
1712 /*
1713 Transfer pixels from the cache.
1714 */
1715 assert(image != (Image *) NULL);
1716 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001717 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001718 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001719 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001720 cache_info=(CacheInfo *) image->cache;
1721 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001722 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001723 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001724 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001725 return((Quantum *) NULL);
1726 if (cache_info->metacontent_extent != 0)
1727 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1728 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001729 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001730}
1731
1732/*
1733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734% %
1735% %
1736% %
1737+ 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 %
1738% %
1739% %
1740% %
1741%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1742%
1743% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1744% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1745%
1746% The format of the GetAuthenticPixelsFromCache() method is:
1747%
cristy4c08aed2011-07-01 19:47:50 +00001748% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001749%
1750% A description of each parameter follows:
1751%
1752% o image: the image.
1753%
1754*/
cristy4c08aed2011-07-01 19:47:50 +00001755static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001756{
1757 CacheInfo
1758 *cache_info;
1759
cristy5c9e6f22010-09-17 17:31:01 +00001760 const int
1761 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001762
cristye7cc7cf2010-09-21 13:26:47 +00001763 assert(image != (const Image *) NULL);
1764 assert(image->signature == MagickSignature);
1765 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001766 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001767 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001768 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001769 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001770}
1771
1772/*
1773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1774% %
1775% %
1776% %
1777% G e t A u t h e n t i c P i x e l Q u e u e %
1778% %
1779% %
1780% %
1781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1782%
cristy4c08aed2011-07-01 19:47:50 +00001783% GetAuthenticPixelQueue() returns the authentic pixels associated
1784% corresponding with the last call to QueueAuthenticPixels() or
1785% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001786%
1787% The format of the GetAuthenticPixelQueue() method is:
1788%
cristy4c08aed2011-07-01 19:47:50 +00001789% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001790%
1791% A description of each parameter follows:
1792%
1793% o image: the image.
1794%
1795*/
cristy4c08aed2011-07-01 19:47:50 +00001796MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001797{
1798 CacheInfo
1799 *cache_info;
1800
cristy2036f5c2010-09-19 21:18:17 +00001801 const int
1802 id = GetOpenMPThreadId();
1803
cristy3ed852e2009-09-05 21:47:34 +00001804 assert(image != (const Image *) NULL);
1805 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001806 assert(image->cache != (Cache) NULL);
1807 cache_info=(CacheInfo *) image->cache;
1808 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001809 if (cache_info->methods.get_authentic_pixels_from_handler !=
1810 (GetAuthenticPixelsFromHandler) NULL)
1811 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001812 assert(id < (int) cache_info->number_threads);
1813 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001814}
1815
1816/*
1817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1818% %
1819% %
1820% %
1821% G e t A u t h e n t i c P i x e l s %
1822% %
1823% %
cristy4c08aed2011-07-01 19:47:50 +00001824% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001825%
1826% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001827% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001828% representing the region is returned, otherwise NULL is returned.
1829%
1830% The returned pointer may point to a temporary working copy of the pixels
1831% or it may point to the original pixels in memory. Performance is maximized
1832% if the selected region is part of one row, or one or more full rows, since
1833% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001834% if the image is in memory, or in a memory-mapped file. The returned pointer
1835% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001836%
1837% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001838% Quantum. If the image has corresponding metacontent,call
1839% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1840% meta-content corresponding to the region. Once the Quantum array has
1841% been updated, the changes must be saved back to the underlying image using
1842% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001843%
1844% The format of the GetAuthenticPixels() method is:
1845%
cristy4c08aed2011-07-01 19:47:50 +00001846% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001847% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001848% ExceptionInfo *exception)
1849%
1850% A description of each parameter follows:
1851%
1852% o image: the image.
1853%
1854% o x,y,columns,rows: These values define the perimeter of a region of
1855% pixels.
1856%
1857% o exception: return any errors or warnings in this structure.
1858%
1859*/
cristy4c08aed2011-07-01 19:47:50 +00001860MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001861 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001862 ExceptionInfo *exception)
1863{
1864 CacheInfo
1865 *cache_info;
1866
cristy2036f5c2010-09-19 21:18:17 +00001867 const int
1868 id = GetOpenMPThreadId();
1869
cristy4c08aed2011-07-01 19:47:50 +00001870 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001871 *q;
cristy4c08aed2011-07-01 19:47:50 +00001872
cristy3ed852e2009-09-05 21:47:34 +00001873 assert(image != (Image *) NULL);
1874 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001875 assert(image->cache != (Cache) NULL);
1876 cache_info=(CacheInfo *) image->cache;
1877 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001878 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001879 (GetAuthenticPixelsHandler) NULL)
1880 {
cristyacd2ed22011-08-30 01:44:23 +00001881 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1882 exception);
1883 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001884 }
cristy2036f5c2010-09-19 21:18:17 +00001885 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001886 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001887 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001888 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001889}
1890
1891/*
1892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1893% %
1894% %
1895% %
1896+ G e t A u t h e n t i c P i x e l s C a c h e %
1897% %
1898% %
1899% %
1900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901%
1902% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1903% as defined by the geometry parameters. A pointer to the pixels is returned
1904% if the pixels are transferred, otherwise a NULL is returned.
1905%
1906% The format of the GetAuthenticPixelsCache() method is:
1907%
cristy4c08aed2011-07-01 19:47:50 +00001908% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001909% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001910% ExceptionInfo *exception)
1911%
1912% A description of each parameter follows:
1913%
1914% o image: the image.
1915%
1916% o x,y,columns,rows: These values define the perimeter of a region of
1917% pixels.
1918%
1919% o exception: return any errors or warnings in this structure.
1920%
1921*/
cristy4c08aed2011-07-01 19:47:50 +00001922static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001923 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001924 ExceptionInfo *exception)
1925{
1926 CacheInfo
1927 *cache_info;
1928
cristy5c9e6f22010-09-17 17:31:01 +00001929 const int
1930 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001931
cristy4c08aed2011-07-01 19:47:50 +00001932 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001933 *q;
cristy4c08aed2011-07-01 19:47:50 +00001934
cristye7cc7cf2010-09-21 13:26:47 +00001935 assert(image != (const Image *) NULL);
1936 assert(image->signature == MagickSignature);
1937 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001938 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001939 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001940 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001941 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001942 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001943 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001944 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001945 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001946}
1947
1948/*
1949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1950% %
1951% %
1952% %
1953+ G e t I m a g e E x t e n t %
1954% %
1955% %
1956% %
1957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958%
cristy4c08aed2011-07-01 19:47:50 +00001959% GetImageExtent() returns the extent of the pixels associated corresponding
1960% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001961%
1962% The format of the GetImageExtent() method is:
1963%
1964% MagickSizeType GetImageExtent(const Image *image)
1965%
1966% A description of each parameter follows:
1967%
1968% o image: the image.
1969%
1970*/
1971MagickExport MagickSizeType GetImageExtent(const Image *image)
1972{
1973 CacheInfo
1974 *cache_info;
1975
cristy5c9e6f22010-09-17 17:31:01 +00001976 const int
1977 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001978
cristy3ed852e2009-09-05 21:47:34 +00001979 assert(image != (Image *) NULL);
1980 assert(image->signature == MagickSignature);
1981 if (image->debug != MagickFalse)
1982 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1983 assert(image->cache != (Cache) NULL);
1984 cache_info=(CacheInfo *) image->cache;
1985 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001986 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001987 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001988}
1989
1990/*
1991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992% %
1993% %
1994% %
1995+ G e t I m a g e P i x e l C a c h e %
1996% %
1997% %
1998% %
1999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000%
2001% GetImagePixelCache() ensures that there is only a single reference to the
2002% pixel cache to be modified, updating the provided cache pointer to point to
2003% a clone of the original pixel cache if necessary.
2004%
2005% The format of the GetImagePixelCache method is:
2006%
2007% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2008% ExceptionInfo *exception)
2009%
2010% A description of each parameter follows:
2011%
2012% o image: the image.
2013%
2014% o clone: any value other than MagickFalse clones the cache pixels.
2015%
2016% o exception: return any errors or warnings in this structure.
2017%
2018*/
cristyaf894d72011-08-06 23:03:10 +00002019
cristy3ed852e2009-09-05 21:47:34 +00002020static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2021{
2022 CacheInfo
2023 *cache_info;
2024
cristy9e0719b2011-12-29 03:45:45 +00002025 PixelChannelMap
2026 *p,
2027 *q;
2028
cristy3ed852e2009-09-05 21:47:34 +00002029 /*
2030 Does the image match the pixel cache morphology?
2031 */
2032 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00002033 p=image->channel_map;
2034 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00002035 if ((image->storage_class != cache_info->storage_class) ||
2036 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002037 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002038 (image->columns != cache_info->columns) ||
2039 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002040 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002041 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002042 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002043 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2044 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2045 return(MagickFalse);
2046 return(MagickTrue);
2047}
2048
cristycd01fae2011-08-06 23:52:42 +00002049static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2050 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002051{
2052 CacheInfo
2053 *cache_info;
2054
cristy3ed852e2009-09-05 21:47:34 +00002055 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002056 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002057 status;
2058
cristy50a10922010-02-15 18:35:25 +00002059 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002060 cpu_throttle = 0,
2061 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002062 time_limit = 0;
2063
cristy1ea34962010-07-01 19:49:21 +00002064 static time_t
cristy208b1002011-08-07 18:51:50 +00002065 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002066
cristyc4f9f132010-03-04 18:50:01 +00002067 status=MagickTrue;
2068 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002069 if (cpu_throttle == 0)
2070 {
2071 char
2072 *limit;
2073
2074 /*
2075 Set CPU throttle in milleseconds.
2076 */
2077 cpu_throttle=MagickResourceInfinity;
2078 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2079 if (limit == (char *) NULL)
2080 limit=GetPolicyValue("throttle");
2081 if (limit != (char *) NULL)
2082 {
2083 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2084 limit=DestroyString(limit);
2085 }
2086 }
2087 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2088 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002089 if (time_limit == 0)
2090 {
cristy6ebe97c2010-07-03 01:17:28 +00002091 /*
2092 Set the exire time in seconds.
2093 */
cristy1ea34962010-07-01 19:49:21 +00002094 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002095 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002096 }
2097 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002098 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002099 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002100 assert(image->cache != (Cache) NULL);
2101 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002102 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002103 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002104 {
cristyceb55ee2010-11-06 16:05:49 +00002105 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002106 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002107 {
cristyceb55ee2010-11-06 16:05:49 +00002108 Image
2109 clone_image;
2110
2111 CacheInfo
2112 *clone_info;
2113
2114 /*
2115 Clone pixel cache.
2116 */
2117 clone_image=(*image);
2118 clone_image.semaphore=AllocateSemaphoreInfo();
2119 clone_image.reference_count=1;
2120 clone_image.cache=ClonePixelCache(cache_info);
2121 clone_info=(CacheInfo *) clone_image.cache;
2122 status=OpenPixelCache(&clone_image,IOMode,exception);
2123 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002124 {
cristy5a7fbfb2010-11-06 16:10:59 +00002125 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002126 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002127 if (status != MagickFalse)
2128 {
cristy979bf772011-08-08 00:04:15 +00002129 if (cache_info->mode == ReadMode)
2130 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002131 destroy=MagickTrue;
2132 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002133 }
2134 }
cristyceb55ee2010-11-06 16:05:49 +00002135 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002136 }
cristyceb55ee2010-11-06 16:05:49 +00002137 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002138 }
cristy4320e0e2009-09-10 15:00:08 +00002139 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002140 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002141 if (status != MagickFalse)
2142 {
2143 /*
2144 Ensure the image matches the pixel cache morphology.
2145 */
2146 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002147 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002148 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2149 status=OpenPixelCache(image,IOMode,exception);
2150 }
cristyf84a1932010-01-03 18:00:18 +00002151 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002152 if (status == MagickFalse)
2153 return((Cache) NULL);
2154 return(image->cache);
2155}
2156
2157/*
2158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2159% %
2160% %
2161% %
2162% G e t O n e A u t h e n t i c P i x e l %
2163% %
2164% %
2165% %
2166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167%
2168% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2169% location. The image background color is returned if an error occurs.
2170%
2171% The format of the GetOneAuthenticPixel() method is:
2172%
cristybb503372010-05-27 20:51:26 +00002173% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002174% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002175%
2176% A description of each parameter follows:
2177%
2178% o image: the image.
2179%
2180% o x,y: These values define the location of the pixel to return.
2181%
2182% o pixel: return a pixel at the specified (x,y) location.
2183%
2184% o exception: return any errors or warnings in this structure.
2185%
2186*/
cristyacbbb7c2010-06-30 18:56:48 +00002187MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002188 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002189{
2190 CacheInfo
2191 *cache_info;
2192
cristy4c08aed2011-07-01 19:47:50 +00002193 register Quantum
2194 *q;
cristy2036f5c2010-09-19 21:18:17 +00002195
cristy2ed42f62011-10-02 19:49:57 +00002196 register ssize_t
2197 i;
2198
cristy3ed852e2009-09-05 21:47:34 +00002199 assert(image != (Image *) NULL);
2200 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002201 assert(image->cache != (Cache) NULL);
2202 cache_info=(CacheInfo *) image->cache;
2203 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002204 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002205 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2206 (GetOneAuthenticPixelFromHandler) NULL)
2207 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2208 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002209 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2210 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002211 {
cristy9e0719b2011-12-29 03:45:45 +00002212 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2213 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2214 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2215 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2216 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002217 return(MagickFalse);
2218 }
2219 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2220 {
2221 PixelChannel
2222 channel;
2223
cristye2a912b2011-12-05 20:02:07 +00002224 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002225 pixel[channel]=q[i];
2226 }
cristy2036f5c2010-09-19 21:18:17 +00002227 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002228}
2229
2230/*
2231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2232% %
2233% %
2234% %
2235+ 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 %
2236% %
2237% %
2238% %
2239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240%
2241% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2242% location. The image background color is returned if an error occurs.
2243%
2244% The format of the GetOneAuthenticPixelFromCache() method is:
2245%
2246% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002247% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002248% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002249%
2250% A description of each parameter follows:
2251%
2252% o image: the image.
2253%
2254% o x,y: These values define the location of the pixel to return.
2255%
2256% o pixel: return a pixel at the specified (x,y) location.
2257%
2258% o exception: return any errors or warnings in this structure.
2259%
2260*/
2261static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002262 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002263{
cristy098f78c2010-09-23 17:28:44 +00002264 CacheInfo
2265 *cache_info;
2266
2267 const int
2268 id = GetOpenMPThreadId();
2269
cristy4c08aed2011-07-01 19:47:50 +00002270 register Quantum
2271 *q;
cristy3ed852e2009-09-05 21:47:34 +00002272
cristy2ed42f62011-10-02 19:49:57 +00002273 register ssize_t
2274 i;
2275
cristy0158a4b2010-09-20 13:59:45 +00002276 assert(image != (const Image *) NULL);
2277 assert(image->signature == MagickSignature);
2278 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002279 cache_info=(CacheInfo *) image->cache;
2280 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002281 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002282 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002283 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2284 exception);
2285 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002286 {
cristy9e0719b2011-12-29 03:45:45 +00002287 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2288 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2289 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2290 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2291 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002292 return(MagickFalse);
2293 }
2294 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2295 {
2296 PixelChannel
2297 channel;
2298
cristye2a912b2011-12-05 20:02:07 +00002299 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002300 pixel[channel]=q[i];
2301 }
cristy3ed852e2009-09-05 21:47:34 +00002302 return(MagickTrue);
2303}
2304
2305/*
2306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2307% %
2308% %
2309% %
cristy3ed852e2009-09-05 21:47:34 +00002310% G e t O n e V i r t u a l P i x e l %
2311% %
2312% %
2313% %
2314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315%
2316% GetOneVirtualPixel() returns a single virtual pixel at the specified
2317% (x,y) location. The image background color is returned if an error occurs.
2318% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2319%
2320% The format of the GetOneVirtualPixel() method is:
2321%
cristybb503372010-05-27 20:51:26 +00002322% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002323% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002324%
2325% A description of each parameter follows:
2326%
2327% o image: the image.
2328%
2329% o x,y: These values define the location of the pixel to return.
2330%
2331% o pixel: return a pixel at the specified (x,y) location.
2332%
2333% o exception: return any errors or warnings in this structure.
2334%
2335*/
2336MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002337 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002338{
cristy3ed852e2009-09-05 21:47:34 +00002339 CacheInfo
2340 *cache_info;
2341
cristy0158a4b2010-09-20 13:59:45 +00002342 const int
2343 id = GetOpenMPThreadId();
2344
cristy4c08aed2011-07-01 19:47:50 +00002345 const Quantum
2346 *p;
cristy2036f5c2010-09-19 21:18:17 +00002347
cristy2ed42f62011-10-02 19:49:57 +00002348 register ssize_t
2349 i;
2350
cristy3ed852e2009-09-05 21:47:34 +00002351 assert(image != (const Image *) NULL);
2352 assert(image->signature == MagickSignature);
2353 assert(image->cache != (Cache) NULL);
2354 cache_info=(CacheInfo *) image->cache;
2355 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002356 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002357 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2358 (GetOneVirtualPixelFromHandler) NULL)
2359 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2360 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002361 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002362 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002363 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002364 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002365 {
cristy9e0719b2011-12-29 03:45:45 +00002366 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2367 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2368 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2369 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2370 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002371 return(MagickFalse);
2372 }
2373 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2374 {
2375 PixelChannel
2376 channel;
2377
cristye2a912b2011-12-05 20:02:07 +00002378 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002379 pixel[channel]=p[i];
2380 }
cristy2036f5c2010-09-19 21:18:17 +00002381 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002382}
2383
2384/*
2385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2386% %
2387% %
2388% %
2389+ 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 %
2390% %
2391% %
2392% %
2393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2394%
2395% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2396% specified (x,y) location. The image background color is returned if an
2397% error occurs.
2398%
2399% The format of the GetOneVirtualPixelFromCache() method is:
2400%
2401% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002402% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002403% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002404%
2405% A description of each parameter follows:
2406%
2407% o image: the image.
2408%
2409% o virtual_pixel_method: the virtual pixel method.
2410%
2411% o x,y: These values define the location of the pixel to return.
2412%
2413% o pixel: return a pixel at the specified (x,y) location.
2414%
2415% o exception: return any errors or warnings in this structure.
2416%
2417*/
2418static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002419 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002420 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002421{
cristy0158a4b2010-09-20 13:59:45 +00002422 CacheInfo
2423 *cache_info;
2424
2425 const int
2426 id = GetOpenMPThreadId();
2427
cristy4c08aed2011-07-01 19:47:50 +00002428 const Quantum
2429 *p;
cristy3ed852e2009-09-05 21:47:34 +00002430
cristy2ed42f62011-10-02 19:49:57 +00002431 register ssize_t
2432 i;
2433
cristye7cc7cf2010-09-21 13:26:47 +00002434 assert(image != (const Image *) NULL);
2435 assert(image->signature == MagickSignature);
2436 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002437 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002438 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002439 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002440 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002441 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002442 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002443 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002444 {
cristy9e0719b2011-12-29 03:45:45 +00002445 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2446 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2447 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2448 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2449 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002450 return(MagickFalse);
2451 }
2452 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2453 {
2454 PixelChannel
2455 channel;
2456
cristye2a912b2011-12-05 20:02:07 +00002457 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002458 pixel[channel]=p[i];
2459 }
cristy3ed852e2009-09-05 21:47:34 +00002460 return(MagickTrue);
2461}
2462
2463/*
2464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465% %
2466% %
2467% %
cristy3aa93752011-12-18 15:54:24 +00002468% G e t O n e V i r t u a l P i x e l I n f o %
2469% %
2470% %
2471% %
2472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473%
2474% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2475% location. The image background color is returned if an error occurs. If
2476% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2477%
2478% The format of the GetOneVirtualPixelInfo() method is:
2479%
2480% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2481% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2482% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2483%
2484% A description of each parameter follows:
2485%
2486% o image: the image.
2487%
2488% o virtual_pixel_method: the virtual pixel method.
2489%
2490% o x,y: these values define the location of the pixel to return.
2491%
2492% o pixel: return a pixel at the specified (x,y) location.
2493%
2494% o exception: return any errors or warnings in this structure.
2495%
2496*/
2497MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2498 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2499 PixelInfo *pixel,ExceptionInfo *exception)
2500{
2501 CacheInfo
2502 *cache_info;
2503
2504 const int
2505 id = GetOpenMPThreadId();
2506
2507 register const Quantum
2508 *p;
2509
2510 assert(image != (const Image *) NULL);
2511 assert(image->signature == MagickSignature);
2512 assert(image->cache != (Cache) NULL);
2513 cache_info=(CacheInfo *) image->cache;
2514 assert(cache_info->signature == MagickSignature);
2515 assert(id < (int) cache_info->number_threads);
2516 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2517 cache_info->nexus_info[id],exception);
2518 GetPixelInfo(image,pixel);
2519 if (p == (const Quantum *) NULL)
2520 return(MagickFalse);
2521 GetPixelInfoPixel(image,p,pixel);
2522 return(MagickTrue);
2523}
2524
2525/*
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527% %
2528% %
2529% %
cristy3ed852e2009-09-05 21:47:34 +00002530+ G e t P i x e l C a c h e C o l o r s p a c e %
2531% %
2532% %
2533% %
2534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535%
2536% GetPixelCacheColorspace() returns the class type of the pixel cache.
2537%
2538% The format of the GetPixelCacheColorspace() method is:
2539%
2540% Colorspace GetPixelCacheColorspace(Cache cache)
2541%
2542% A description of each parameter follows:
2543%
2544% o cache: the pixel cache.
2545%
2546*/
cristya6577ff2011-09-02 19:54:26 +00002547MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002548{
2549 CacheInfo
2550 *cache_info;
2551
2552 assert(cache != (Cache) NULL);
2553 cache_info=(CacheInfo *) cache;
2554 assert(cache_info->signature == MagickSignature);
2555 if (cache_info->debug != MagickFalse)
2556 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2557 cache_info->filename);
2558 return(cache_info->colorspace);
2559}
2560
2561/*
2562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2563% %
2564% %
2565% %
2566+ G e t P i x e l C a c h e M e t h o d s %
2567% %
2568% %
2569% %
2570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2571%
2572% GetPixelCacheMethods() initializes the CacheMethods structure.
2573%
2574% The format of the GetPixelCacheMethods() method is:
2575%
2576% void GetPixelCacheMethods(CacheMethods *cache_methods)
2577%
2578% A description of each parameter follows:
2579%
2580% o cache_methods: Specifies a pointer to a CacheMethods structure.
2581%
2582*/
cristya6577ff2011-09-02 19:54:26 +00002583MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002584{
2585 assert(cache_methods != (CacheMethods *) NULL);
2586 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2587 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2588 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002589 cache_methods->get_virtual_metacontent_from_handler=
2590 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002591 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2592 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002593 cache_methods->get_authentic_metacontent_from_handler=
2594 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002595 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2596 cache_methods->get_one_authentic_pixel_from_handler=
2597 GetOneAuthenticPixelFromCache;
2598 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2599 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2600 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2601}
2602
2603/*
2604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605% %
2606% %
2607% %
2608+ G e t P i x e l C a c h e N e x u s E x t e n t %
2609% %
2610% %
2611% %
2612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2613%
cristy4c08aed2011-07-01 19:47:50 +00002614% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2615% corresponding with the last call to SetPixelCacheNexusPixels() or
2616% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002617%
2618% The format of the GetPixelCacheNexusExtent() method is:
2619%
2620% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2621% NexusInfo *nexus_info)
2622%
2623% A description of each parameter follows:
2624%
2625% o nexus_info: the nexus info.
2626%
2627*/
cristya6577ff2011-09-02 19:54:26 +00002628MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002629 NexusInfo *nexus_info)
2630{
2631 CacheInfo
2632 *cache_info;
2633
2634 MagickSizeType
2635 extent;
2636
cristy9f027d12011-09-21 01:17:17 +00002637 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002638 cache_info=(CacheInfo *) cache;
2639 assert(cache_info->signature == MagickSignature);
2640 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2641 if (extent == 0)
2642 return((MagickSizeType) cache_info->columns*cache_info->rows);
2643 return(extent);
2644}
2645
2646/*
2647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2648% %
2649% %
2650% %
cristy4c08aed2011-07-01 19:47:50 +00002651+ 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 +00002652% %
2653% %
2654% %
2655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2656%
cristy4c08aed2011-07-01 19:47:50 +00002657% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2658% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002659%
cristy4c08aed2011-07-01 19:47:50 +00002660% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002661%
cristy4c08aed2011-07-01 19:47:50 +00002662% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002663% NexusInfo *nexus_info)
2664%
2665% A description of each parameter follows:
2666%
2667% o cache: the pixel cache.
2668%
cristy4c08aed2011-07-01 19:47:50 +00002669% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002670%
2671*/
cristya6577ff2011-09-02 19:54:26 +00002672MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002673 NexusInfo *nexus_info)
2674{
2675 CacheInfo
2676 *cache_info;
2677
cristy9f027d12011-09-21 01:17:17 +00002678 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002679 cache_info=(CacheInfo *) cache;
2680 assert(cache_info->signature == MagickSignature);
2681 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002682 return((void *) NULL);
2683 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002684}
2685
2686/*
2687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2688% %
2689% %
2690% %
2691+ G e t P i x e l C a c h e N e x u s P i x e l s %
2692% %
2693% %
2694% %
2695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2696%
2697% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2698% cache nexus.
2699%
2700% The format of the GetPixelCacheNexusPixels() method is:
2701%
cristy4c08aed2011-07-01 19:47:50 +00002702% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002703% NexusInfo *nexus_info)
2704%
2705% A description of each parameter follows:
2706%
2707% o cache: the pixel cache.
2708%
2709% o nexus_info: the cache nexus to return the pixels.
2710%
2711*/
cristya6577ff2011-09-02 19:54:26 +00002712MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002713 NexusInfo *nexus_info)
2714{
2715 CacheInfo
2716 *cache_info;
2717
cristy9f027d12011-09-21 01:17:17 +00002718 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002719 cache_info=(CacheInfo *) cache;
2720 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002721 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002722 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002723 return(nexus_info->pixels);
2724}
2725
2726/*
2727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2728% %
2729% %
2730% %
cristy056ba772010-01-02 23:33:54 +00002731+ G e t P i x e l C a c h e P i x e l s %
2732% %
2733% %
2734% %
2735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736%
2737% GetPixelCachePixels() returns the pixels associated with the specified image.
2738%
2739% The format of the GetPixelCachePixels() method is:
2740%
cristyf84a1932010-01-03 18:00:18 +00002741% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2742% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002743%
2744% A description of each parameter follows:
2745%
2746% o image: the image.
2747%
2748% o length: the pixel cache length.
2749%
cristyf84a1932010-01-03 18:00:18 +00002750% o exception: return any errors or warnings in this structure.
2751%
cristy056ba772010-01-02 23:33:54 +00002752*/
cristyd1dd6e42011-09-04 01:46:08 +00002753MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002754 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002755{
2756 CacheInfo
2757 *cache_info;
2758
2759 assert(image != (const Image *) NULL);
2760 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002761 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002762 assert(length != (MagickSizeType *) NULL);
2763 assert(exception != (ExceptionInfo *) NULL);
2764 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002765 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002766 assert(cache_info->signature == MagickSignature);
2767 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002768 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002769 return((void *) NULL);
2770 *length=cache_info->length;
2771 return((void *) cache_info->pixels);
2772}
2773
2774/*
2775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776% %
2777% %
2778% %
cristyb32b90a2009-09-07 21:45:48 +00002779+ 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 +00002780% %
2781% %
2782% %
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784%
2785% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2786%
2787% The format of the GetPixelCacheStorageClass() method is:
2788%
2789% ClassType GetPixelCacheStorageClass(Cache cache)
2790%
2791% A description of each parameter follows:
2792%
2793% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2794%
2795% o cache: the pixel cache.
2796%
2797*/
cristya6577ff2011-09-02 19:54:26 +00002798MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002799{
2800 CacheInfo
2801 *cache_info;
2802
2803 assert(cache != (Cache) NULL);
2804 cache_info=(CacheInfo *) cache;
2805 assert(cache_info->signature == MagickSignature);
2806 if (cache_info->debug != MagickFalse)
2807 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2808 cache_info->filename);
2809 return(cache_info->storage_class);
2810}
2811
2812/*
2813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2814% %
2815% %
2816% %
cristyb32b90a2009-09-07 21:45:48 +00002817+ G e t P i x e l C a c h e T i l e S i z e %
2818% %
2819% %
2820% %
2821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2822%
2823% GetPixelCacheTileSize() returns the pixel cache tile size.
2824%
2825% The format of the GetPixelCacheTileSize() method is:
2826%
cristybb503372010-05-27 20:51:26 +00002827% void GetPixelCacheTileSize(const Image *image,size_t *width,
2828% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002829%
2830% A description of each parameter follows:
2831%
2832% o image: the image.
2833%
2834% o width: the optimize cache tile width in pixels.
2835%
2836% o height: the optimize cache tile height in pixels.
2837%
2838*/
cristya6577ff2011-09-02 19:54:26 +00002839MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002840 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002841{
cristy4c08aed2011-07-01 19:47:50 +00002842 CacheInfo
2843 *cache_info;
2844
cristyb32b90a2009-09-07 21:45:48 +00002845 assert(image != (Image *) NULL);
2846 assert(image->signature == MagickSignature);
2847 if (image->debug != MagickFalse)
2848 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002849 cache_info=(CacheInfo *) image->cache;
2850 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002851 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002852 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002853 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002854 *height=(*width);
2855}
2856
2857/*
2858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2859% %
2860% %
2861% %
2862+ G e t P i x e l C a c h e T y p e %
2863% %
2864% %
2865% %
2866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2867%
2868% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2869%
2870% The format of the GetPixelCacheType() method is:
2871%
2872% CacheType GetPixelCacheType(const Image *image)
2873%
2874% A description of each parameter follows:
2875%
2876% o image: the image.
2877%
2878*/
cristya6577ff2011-09-02 19:54:26 +00002879MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002880{
2881 CacheInfo
2882 *cache_info;
2883
2884 assert(image != (Image *) NULL);
2885 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002886 assert(image->cache != (Cache) NULL);
2887 cache_info=(CacheInfo *) image->cache;
2888 assert(cache_info->signature == MagickSignature);
2889 return(cache_info->type);
2890}
2891
2892/*
2893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2894% %
2895% %
2896% %
cristy3ed852e2009-09-05 21:47:34 +00002897+ 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 %
2898% %
2899% %
2900% %
2901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2902%
2903% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2904% pixel cache. A virtual pixel is any pixel access that is outside the
2905% boundaries of the image cache.
2906%
2907% The format of the GetPixelCacheVirtualMethod() method is:
2908%
2909% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2910%
2911% A description of each parameter follows:
2912%
2913% o image: the image.
2914%
2915*/
cristyd1dd6e42011-09-04 01:46:08 +00002916MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002917{
2918 CacheInfo
2919 *cache_info;
2920
2921 assert(image != (Image *) NULL);
2922 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002923 assert(image->cache != (Cache) NULL);
2924 cache_info=(CacheInfo *) image->cache;
2925 assert(cache_info->signature == MagickSignature);
2926 return(cache_info->virtual_pixel_method);
2927}
2928
2929/*
2930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2931% %
2932% %
2933% %
cristy4c08aed2011-07-01 19:47:50 +00002934+ 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 +00002935% %
2936% %
2937% %
2938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2939%
cristy4c08aed2011-07-01 19:47:50 +00002940% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2941% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002942%
cristy4c08aed2011-07-01 19:47:50 +00002943% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002944%
cristy4c08aed2011-07-01 19:47:50 +00002945% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002946%
2947% A description of each parameter follows:
2948%
2949% o image: the image.
2950%
2951*/
cristy4c08aed2011-07-01 19:47:50 +00002952static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002953{
2954 CacheInfo
2955 *cache_info;
2956
cristy5c9e6f22010-09-17 17:31:01 +00002957 const int
2958 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002959
cristy4c08aed2011-07-01 19:47:50 +00002960 const void
2961 *metacontent;
2962
cristye7cc7cf2010-09-21 13:26:47 +00002963 assert(image != (const Image *) NULL);
2964 assert(image->signature == MagickSignature);
2965 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002966 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002967 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002968 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002969 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2970 cache_info->nexus_info[id]);
2971 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002972}
2973
2974/*
2975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2976% %
2977% %
2978% %
cristy4c08aed2011-07-01 19:47:50 +00002979+ 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 +00002980% %
2981% %
2982% %
2983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2984%
cristy4c08aed2011-07-01 19:47:50 +00002985% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2986% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002987%
cristy4c08aed2011-07-01 19:47:50 +00002988% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002989%
cristy4c08aed2011-07-01 19:47:50 +00002990% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002991% NexusInfo *nexus_info)
2992%
2993% A description of each parameter follows:
2994%
2995% o cache: the pixel cache.
2996%
cristy4c08aed2011-07-01 19:47:50 +00002997% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002998%
2999*/
cristya6577ff2011-09-02 19:54:26 +00003000MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00003001 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00003002{
3003 CacheInfo
3004 *cache_info;
3005
cristye7cc7cf2010-09-21 13:26:47 +00003006 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003007 cache_info=(CacheInfo *) cache;
3008 assert(cache_info->signature == MagickSignature);
3009 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003010 return((void *) NULL);
3011 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003012}
3013
3014/*
3015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3016% %
3017% %
3018% %
cristy4c08aed2011-07-01 19:47:50 +00003019% 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 +00003020% %
3021% %
3022% %
3023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3024%
cristy4c08aed2011-07-01 19:47:50 +00003025% GetVirtualMetacontent() returns the virtual metacontent corresponding with
3026% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3027% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003028%
cristy4c08aed2011-07-01 19:47:50 +00003029% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003030%
cristy4c08aed2011-07-01 19:47:50 +00003031% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003032%
3033% A description of each parameter follows:
3034%
3035% o image: the image.
3036%
3037*/
cristy4c08aed2011-07-01 19:47:50 +00003038MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003039{
3040 CacheInfo
3041 *cache_info;
3042
cristy2036f5c2010-09-19 21:18:17 +00003043 const int
3044 id = GetOpenMPThreadId();
3045
cristy4c08aed2011-07-01 19:47:50 +00003046 const void
3047 *metacontent;
3048
cristy3ed852e2009-09-05 21:47:34 +00003049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003051 assert(image->cache != (Cache) NULL);
3052 cache_info=(CacheInfo *) image->cache;
3053 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003054 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3055 (GetVirtualMetacontentFromHandler) NULL)
3056 {
3057 metacontent=cache_info->methods.
3058 get_virtual_metacontent_from_handler(image);
3059 return(metacontent);
3060 }
cristy2036f5c2010-09-19 21:18:17 +00003061 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003062 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3063 cache_info->nexus_info[id]);
3064 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003065}
3066
3067/*
3068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3069% %
3070% %
3071% %
3072+ 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 %
3073% %
3074% %
3075% %
3076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3077%
3078% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3079% pixel cache as defined by the geometry parameters. A pointer to the pixels
3080% is returned if the pixels are transferred, otherwise a NULL is returned.
3081%
3082% The format of the GetVirtualPixelsFromNexus() method is:
3083%
cristy4c08aed2011-07-01 19:47:50 +00003084% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003085% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003086% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3087% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003088%
3089% A description of each parameter follows:
3090%
3091% o image: the image.
3092%
3093% o virtual_pixel_method: the virtual pixel method.
3094%
3095% o x,y,columns,rows: These values define the perimeter of a region of
3096% pixels.
3097%
3098% o nexus_info: the cache nexus to acquire.
3099%
3100% o exception: return any errors or warnings in this structure.
3101%
3102*/
3103
cristybb503372010-05-27 20:51:26 +00003104static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003105 DitherMatrix[64] =
3106 {
3107 0, 48, 12, 60, 3, 51, 15, 63,
3108 32, 16, 44, 28, 35, 19, 47, 31,
3109 8, 56, 4, 52, 11, 59, 7, 55,
3110 40, 24, 36, 20, 43, 27, 39, 23,
3111 2, 50, 14, 62, 1, 49, 13, 61,
3112 34, 18, 46, 30, 33, 17, 45, 29,
3113 10, 58, 6, 54, 9, 57, 5, 53,
3114 42, 26, 38, 22, 41, 25, 37, 21
3115 };
3116
cristybb503372010-05-27 20:51:26 +00003117static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003118{
cristybb503372010-05-27 20:51:26 +00003119 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003120 index;
3121
3122 index=x+DitherMatrix[x & 0x07]-32L;
3123 if (index < 0L)
3124 return(0L);
cristybb503372010-05-27 20:51:26 +00003125 if (index >= (ssize_t) columns)
3126 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003127 return(index);
3128}
3129
cristybb503372010-05-27 20:51:26 +00003130static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003131{
cristybb503372010-05-27 20:51:26 +00003132 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003133 index;
3134
3135 index=y+DitherMatrix[y & 0x07]-32L;
3136 if (index < 0L)
3137 return(0L);
cristybb503372010-05-27 20:51:26 +00003138 if (index >= (ssize_t) rows)
3139 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003140 return(index);
3141}
3142
cristybb503372010-05-27 20:51:26 +00003143static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003144{
3145 if (x < 0L)
3146 return(0L);
cristybb503372010-05-27 20:51:26 +00003147 if (x >= (ssize_t) columns)
3148 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003149 return(x);
3150}
3151
cristybb503372010-05-27 20:51:26 +00003152static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003153{
3154 if (y < 0L)
3155 return(0L);
cristybb503372010-05-27 20:51:26 +00003156 if (y >= (ssize_t) rows)
3157 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003158 return(y);
3159}
3160
cristybb503372010-05-27 20:51:26 +00003161static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003162{
cristybb503372010-05-27 20:51:26 +00003163 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003164}
3165
cristybb503372010-05-27 20:51:26 +00003166static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003167{
cristybb503372010-05-27 20:51:26 +00003168 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003169}
3170
cristybb503372010-05-27 20:51:26 +00003171static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3172 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003173{
3174 MagickModulo
3175 modulo;
3176
cristy6162bb42011-07-18 11:34:09 +00003177 /*
3178 Compute the remainder of dividing offset by extent. It returns not only
3179 the quotient (tile the offset falls in) but also the positive remainer
3180 within that tile such that 0 <= remainder < extent. This method is
3181 essentially a ldiv() using a floored modulo division rather than the
3182 normal default truncated modulo division.
3183 */
cristybb503372010-05-27 20:51:26 +00003184 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003185 if (offset < 0L)
3186 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003187 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003188 return(modulo);
3189}
3190
cristya6577ff2011-09-02 19:54:26 +00003191MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003192 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3193 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003194 ExceptionInfo *exception)
3195{
3196 CacheInfo
3197 *cache_info;
3198
3199 MagickOffsetType
3200 offset;
3201
3202 MagickSizeType
3203 length,
3204 number_pixels;
3205
3206 NexusInfo
3207 **virtual_nexus;
3208
cristy4c08aed2011-07-01 19:47:50 +00003209 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003210 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003211 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003212
3213 RectangleInfo
3214 region;
3215
cristy4c08aed2011-07-01 19:47:50 +00003216 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003217 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003218
cristy4c08aed2011-07-01 19:47:50 +00003219 register const void
3220 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003221
cristy4c08aed2011-07-01 19:47:50 +00003222 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003223 *restrict q;
3224
cristybb503372010-05-27 20:51:26 +00003225 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003226 i,
3227 u;
cristy3ed852e2009-09-05 21:47:34 +00003228
cristy4c08aed2011-07-01 19:47:50 +00003229 register unsigned char
3230 *restrict s;
3231
cristy105ba3c2011-07-18 02:28:38 +00003232 ssize_t
3233 v;
3234
cristy4c08aed2011-07-01 19:47:50 +00003235 void
cristy105ba3c2011-07-18 02:28:38 +00003236 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003237
cristy3ed852e2009-09-05 21:47:34 +00003238 /*
3239 Acquire pixels.
3240 */
cristye7cc7cf2010-09-21 13:26:47 +00003241 assert(image != (const Image *) NULL);
3242 assert(image->signature == MagickSignature);
3243 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003244 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003245 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003246 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003247 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003248 region.x=x;
3249 region.y=y;
3250 region.width=columns;
3251 region.height=rows;
3252 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003253 if (pixels == (Quantum *) NULL)
3254 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003255 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003256 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3257 nexus_info->region.x;
3258 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3259 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003260 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3261 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003262 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3263 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003264 {
3265 MagickBooleanType
3266 status;
3267
3268 /*
3269 Pixel request is inside cache extents.
3270 */
cristy4c08aed2011-07-01 19:47:50 +00003271 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003272 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003273 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3274 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003275 return((const Quantum *) NULL);
3276 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003277 {
cristy4c08aed2011-07-01 19:47:50 +00003278 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003279 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003280 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003281 }
cristyacd2ed22011-08-30 01:44:23 +00003282 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003283 }
3284 /*
3285 Pixel request is outside cache extents.
3286 */
cristy4c08aed2011-07-01 19:47:50 +00003287 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003288 virtual_nexus=AcquirePixelCacheNexus(1);
3289 if (virtual_nexus == (NexusInfo **) NULL)
3290 {
cristy4c08aed2011-07-01 19:47:50 +00003291 if (virtual_nexus != (NexusInfo **) NULL)
3292 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003293 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3294 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003295 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003296 }
cristy105ba3c2011-07-18 02:28:38 +00003297 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3298 sizeof(*virtual_pixel));
3299 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003300 switch (virtual_pixel_method)
3301 {
cristy4c08aed2011-07-01 19:47:50 +00003302 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003303 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003304 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003305 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003306 case MaskVirtualPixelMethod:
3307 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003308 case EdgeVirtualPixelMethod:
3309 case CheckerTileVirtualPixelMethod:
3310 case HorizontalTileVirtualPixelMethod:
3311 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003312 {
cristy4c08aed2011-07-01 19:47:50 +00003313 if (cache_info->metacontent_extent != 0)
3314 {
cristy6162bb42011-07-18 11:34:09 +00003315 /*
3316 Acquire a metacontent buffer.
3317 */
cristya64b85d2011-09-14 01:02:31 +00003318 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003319 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003320 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003321 {
cristy4c08aed2011-07-01 19:47:50 +00003322 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3323 (void) ThrowMagickException(exception,GetMagickModule(),
3324 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3325 return((const Quantum *) NULL);
3326 }
cristy105ba3c2011-07-18 02:28:38 +00003327 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003328 cache_info->metacontent_extent);
3329 }
3330 switch (virtual_pixel_method)
3331 {
3332 case BlackVirtualPixelMethod:
3333 {
cristy30301712011-07-18 15:06:51 +00003334 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3335 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003336 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3337 break;
3338 }
3339 case GrayVirtualPixelMethod:
3340 {
cristy30301712011-07-18 15:06:51 +00003341 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003342 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3343 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003344 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3345 break;
3346 }
3347 case TransparentVirtualPixelMethod:
3348 {
cristy30301712011-07-18 15:06:51 +00003349 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3350 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003351 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3352 break;
3353 }
3354 case MaskVirtualPixelMethod:
3355 case WhiteVirtualPixelMethod:
3356 {
cristy30301712011-07-18 15:06:51 +00003357 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3358 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003359 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3360 break;
3361 }
3362 default:
3363 {
cristy9e0719b2011-12-29 03:45:45 +00003364 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3365 virtual_pixel);
3366 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3367 virtual_pixel);
3368 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3369 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003370 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003371 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3372 virtual_pixel);
3373 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3374 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003375 break;
3376 }
3377 }
cristy3ed852e2009-09-05 21:47:34 +00003378 break;
3379 }
3380 default:
cristy3ed852e2009-09-05 21:47:34 +00003381 break;
cristy3ed852e2009-09-05 21:47:34 +00003382 }
cristybb503372010-05-27 20:51:26 +00003383 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003384 {
cristybb503372010-05-27 20:51:26 +00003385 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003386 {
3387 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003388 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003389 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3390 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003391 {
3392 MagickModulo
3393 x_modulo,
3394 y_modulo;
3395
3396 /*
3397 Transfer a single pixel.
3398 */
3399 length=(MagickSizeType) 1;
3400 switch (virtual_pixel_method)
3401 {
cristy3ed852e2009-09-05 21:47:34 +00003402 default:
3403 {
3404 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003405 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003406 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003407 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003408 break;
3409 }
3410 case RandomVirtualPixelMethod:
3411 {
3412 if (cache_info->random_info == (RandomInfo *) NULL)
3413 cache_info->random_info=AcquireRandomInfo();
3414 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003415 RandomX(cache_info->random_info,cache_info->columns),
3416 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003417 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003418 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003419 break;
3420 }
3421 case DitherVirtualPixelMethod:
3422 {
3423 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003424 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003425 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003426 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003427 break;
3428 }
3429 case TileVirtualPixelMethod:
3430 {
3431 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3432 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3433 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003434 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003435 exception);
cristy4c08aed2011-07-01 19:47:50 +00003436 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003437 break;
3438 }
3439 case MirrorVirtualPixelMethod:
3440 {
3441 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3442 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003443 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003444 x_modulo.remainder-1L;
3445 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3446 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003447 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003448 y_modulo.remainder-1L;
3449 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003450 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003451 exception);
cristy4c08aed2011-07-01 19:47:50 +00003452 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003453 break;
3454 }
3455 case HorizontalTileEdgeVirtualPixelMethod:
3456 {
3457 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3458 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003459 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003460 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003461 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003462 break;
3463 }
3464 case VerticalTileEdgeVirtualPixelMethod:
3465 {
3466 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003468 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003469 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003470 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3471 break;
3472 }
3473 case BackgroundVirtualPixelMethod:
3474 case BlackVirtualPixelMethod:
3475 case GrayVirtualPixelMethod:
3476 case TransparentVirtualPixelMethod:
3477 case MaskVirtualPixelMethod:
3478 case WhiteVirtualPixelMethod:
3479 {
3480 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003481 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003482 break;
3483 }
3484 case EdgeVirtualPixelMethod:
3485 case CheckerTileVirtualPixelMethod:
3486 {
3487 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3488 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3489 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3490 {
3491 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003492 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003493 break;
3494 }
3495 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3496 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3497 exception);
3498 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3499 break;
3500 }
3501 case HorizontalTileVirtualPixelMethod:
3502 {
3503 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3504 {
3505 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003506 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003507 break;
3508 }
3509 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3510 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3511 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3512 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3513 exception);
3514 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3515 break;
3516 }
3517 case VerticalTileVirtualPixelMethod:
3518 {
3519 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3520 {
3521 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003522 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003523 break;
3524 }
3525 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3526 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3527 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3528 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3529 exception);
3530 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003531 break;
3532 }
3533 }
cristy4c08aed2011-07-01 19:47:50 +00003534 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003535 break;
cristyed231572011-07-14 02:18:59 +00003536 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003537 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003538 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003539 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003540 {
3541 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3542 s+=cache_info->metacontent_extent;
3543 }
cristy3ed852e2009-09-05 21:47:34 +00003544 continue;
3545 }
3546 /*
3547 Transfer a run of pixels.
3548 */
cristy4c08aed2011-07-01 19:47:50 +00003549 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3550 length,1UL,*virtual_nexus,exception);
3551 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003552 break;
cristy4c08aed2011-07-01 19:47:50 +00003553 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003554 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3555 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003556 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003557 {
cristy4c08aed2011-07-01 19:47:50 +00003558 (void) memcpy(s,r,(size_t) length);
3559 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003560 }
3561 }
3562 }
cristy4c08aed2011-07-01 19:47:50 +00003563 /*
3564 Free resources.
3565 */
cristy105ba3c2011-07-18 02:28:38 +00003566 if (virtual_metacontent != (void *) NULL)
3567 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003568 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3569 return(pixels);
3570}
3571
3572/*
3573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3574% %
3575% %
3576% %
3577+ G e t V i r t u a l P i x e l C a c h e %
3578% %
3579% %
3580% %
3581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582%
3583% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3584% cache as defined by the geometry parameters. A pointer to the pixels
3585% is returned if the pixels are transferred, otherwise a NULL is returned.
3586%
3587% The format of the GetVirtualPixelCache() method is:
3588%
cristy4c08aed2011-07-01 19:47:50 +00003589% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003590% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3591% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003592% ExceptionInfo *exception)
3593%
3594% A description of each parameter follows:
3595%
3596% o image: the image.
3597%
3598% o virtual_pixel_method: the virtual pixel method.
3599%
3600% o x,y,columns,rows: These values define the perimeter of a region of
3601% pixels.
3602%
3603% o exception: return any errors or warnings in this structure.
3604%
3605*/
cristy4c08aed2011-07-01 19:47:50 +00003606static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003607 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3608 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003609{
3610 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003611 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003612
cristy5c9e6f22010-09-17 17:31:01 +00003613 const int
3614 id = GetOpenMPThreadId();
3615
cristy4c08aed2011-07-01 19:47:50 +00003616 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003617 *p;
cristy4c08aed2011-07-01 19:47:50 +00003618
cristye7cc7cf2010-09-21 13:26:47 +00003619 assert(image != (const Image *) NULL);
3620 assert(image->signature == MagickSignature);
3621 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003622 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003623 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003624 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003625 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003626 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003627 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003628}
3629
3630/*
3631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3632% %
3633% %
3634% %
3635% G e t V i r t u a l P i x e l Q u e u e %
3636% %
3637% %
3638% %
3639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3640%
cristy4c08aed2011-07-01 19:47:50 +00003641% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3642% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003643%
3644% The format of the GetVirtualPixelQueue() method is:
3645%
cristy4c08aed2011-07-01 19:47:50 +00003646% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003647%
3648% A description of each parameter follows:
3649%
3650% o image: the image.
3651%
3652*/
cristy4c08aed2011-07-01 19:47:50 +00003653MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003654{
3655 CacheInfo
3656 *cache_info;
3657
cristy2036f5c2010-09-19 21:18:17 +00003658 const int
3659 id = GetOpenMPThreadId();
3660
cristy3ed852e2009-09-05 21:47:34 +00003661 assert(image != (const Image *) NULL);
3662 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003663 assert(image->cache != (Cache) NULL);
3664 cache_info=(CacheInfo *) image->cache;
3665 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003666 if (cache_info->methods.get_virtual_pixels_handler !=
3667 (GetVirtualPixelsHandler) NULL)
3668 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003669 assert(id < (int) cache_info->number_threads);
3670 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003671}
3672
3673/*
3674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3675% %
3676% %
3677% %
3678% G e t V i r t u a l P i x e l s %
3679% %
3680% %
3681% %
3682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3683%
3684% GetVirtualPixels() returns an immutable pixel region. If the
3685% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003686% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003687% copy of the pixels or it may point to the original pixels in memory.
3688% Performance is maximized if the selected region is part of one row, or one
3689% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003690% (without a copy) if the image is in memory, or in a memory-mapped file. The
3691% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003692%
3693% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003694% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3695% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3696% access the meta-content (of type void) corresponding to the the
3697% region.
cristy3ed852e2009-09-05 21:47:34 +00003698%
3699% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3700%
3701% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3702% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3703% GetCacheViewAuthenticPixels() instead.
3704%
3705% The format of the GetVirtualPixels() method is:
3706%
cristy4c08aed2011-07-01 19:47:50 +00003707% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003708% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003709% ExceptionInfo *exception)
3710%
3711% A description of each parameter follows:
3712%
3713% o image: the image.
3714%
3715% o x,y,columns,rows: These values define the perimeter of a region of
3716% pixels.
3717%
3718% o exception: return any errors or warnings in this structure.
3719%
3720*/
cristy4c08aed2011-07-01 19:47:50 +00003721MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003722 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3723 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003724{
3725 CacheInfo
3726 *cache_info;
3727
cristy2036f5c2010-09-19 21:18:17 +00003728 const int
3729 id = GetOpenMPThreadId();
3730
cristy4c08aed2011-07-01 19:47:50 +00003731 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003732 *p;
cristy4c08aed2011-07-01 19:47:50 +00003733
cristy3ed852e2009-09-05 21:47:34 +00003734 assert(image != (const Image *) NULL);
3735 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003736 assert(image->cache != (Cache) NULL);
3737 cache_info=(CacheInfo *) image->cache;
3738 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003739 if (cache_info->methods.get_virtual_pixel_handler !=
3740 (GetVirtualPixelHandler) NULL)
3741 return(cache_info->methods.get_virtual_pixel_handler(image,
3742 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003743 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003744 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003745 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003746 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003747}
3748
3749/*
3750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3751% %
3752% %
3753% %
3754+ 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 %
3755% %
3756% %
3757% %
3758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3759%
cristy4c08aed2011-07-01 19:47:50 +00003760% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3761% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003762%
3763% The format of the GetVirtualPixelsCache() method is:
3764%
cristy4c08aed2011-07-01 19:47:50 +00003765% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003766%
3767% A description of each parameter follows:
3768%
3769% o image: the image.
3770%
3771*/
cristy4c08aed2011-07-01 19:47:50 +00003772static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003773{
3774 CacheInfo
3775 *cache_info;
3776
cristy5c9e6f22010-09-17 17:31:01 +00003777 const int
3778 id = GetOpenMPThreadId();
3779
cristye7cc7cf2010-09-21 13:26:47 +00003780 assert(image != (const Image *) NULL);
3781 assert(image->signature == MagickSignature);
3782 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003783 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003784 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003785 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003786 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003787}
3788
3789/*
3790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3791% %
3792% %
3793% %
3794+ G e t V i r t u a l P i x e l s N e x u s %
3795% %
3796% %
3797% %
3798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3799%
3800% GetVirtualPixelsNexus() returns the pixels associated with the specified
3801% cache nexus.
3802%
3803% The format of the GetVirtualPixelsNexus() method is:
3804%
cristy4c08aed2011-07-01 19:47:50 +00003805% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003806% NexusInfo *nexus_info)
3807%
3808% A description of each parameter follows:
3809%
3810% o cache: the pixel cache.
3811%
3812% o nexus_info: the cache nexus to return the colormap pixels.
3813%
3814*/
cristya6577ff2011-09-02 19:54:26 +00003815MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003816 NexusInfo *nexus_info)
3817{
3818 CacheInfo
3819 *cache_info;
3820
cristye7cc7cf2010-09-21 13:26:47 +00003821 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003822 cache_info=(CacheInfo *) cache;
3823 assert(cache_info->signature == MagickSignature);
3824 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003825 return((Quantum *) NULL);
3826 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003827}
3828
3829/*
3830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3831% %
3832% %
3833% %
3834+ M a s k P i x e l C a c h e N e x u s %
3835% %
3836% %
3837% %
3838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3839%
3840% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3841% The method returns MagickTrue if the pixel region is masked, otherwise
3842% MagickFalse.
3843%
3844% The format of the MaskPixelCacheNexus() method is:
3845%
3846% MagickBooleanType MaskPixelCacheNexus(Image *image,
3847% NexusInfo *nexus_info,ExceptionInfo *exception)
3848%
3849% A description of each parameter follows:
3850%
3851% o image: the image.
3852%
3853% o nexus_info: the cache nexus to clip.
3854%
3855% o exception: return any errors or warnings in this structure.
3856%
3857*/
3858
cristy3aa93752011-12-18 15:54:24 +00003859static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3860 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003861{
3862 MagickRealType
3863 gamma;
3864
cristyaa83c2c2011-09-21 13:36:25 +00003865 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003866 {
3867 *composite=(*q);
3868 return;
3869 }
3870 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3871 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003872 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3873 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3874 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003875 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003876 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003877}
3878
3879static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3880 ExceptionInfo *exception)
3881{
3882 CacheInfo
3883 *cache_info;
3884
cristy4c08aed2011-07-01 19:47:50 +00003885 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003886 alpha,
3887 beta;
3888
3889 MagickSizeType
3890 number_pixels;
3891
3892 NexusInfo
3893 **clip_nexus,
3894 **image_nexus;
3895
cristy4c08aed2011-07-01 19:47:50 +00003896 register const Quantum
3897 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003898 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003899
cristy4c08aed2011-07-01 19:47:50 +00003900 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003901 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003902
cristye076a6e2010-08-15 19:59:43 +00003903 register ssize_t
3904 i;
3905
cristy3ed852e2009-09-05 21:47:34 +00003906 /*
3907 Apply clip mask.
3908 */
3909 if (image->debug != MagickFalse)
3910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3911 if (image->mask == (Image *) NULL)
3912 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003913 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003914 if (cache_info == (Cache) NULL)
3915 return(MagickFalse);
3916 image_nexus=AcquirePixelCacheNexus(1);
3917 clip_nexus=AcquirePixelCacheNexus(1);
3918 if ((image_nexus == (NexusInfo **) NULL) ||
3919 (clip_nexus == (NexusInfo **) NULL))
3920 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003921 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3922 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3923 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003924 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003925 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3926 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003927 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003928 GetPixelInfo(image,&alpha);
3929 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003930 number_pixels=(MagickSizeType) nexus_info->region.width*
3931 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003932 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003933 {
cristy4c08aed2011-07-01 19:47:50 +00003934 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003935 break;
cristy803640d2011-11-17 02:11:32 +00003936 GetPixelInfoPixel(image,p,&alpha);
3937 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003938 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003939 &alpha,alpha.alpha,&beta);
3940 SetPixelRed(image,ClampToQuantum(beta.red),q);
3941 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3942 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3943 if (cache_info->colorspace == CMYKColorspace)
3944 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3945 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003946 p++;
3947 q++;
3948 r++;
3949 }
3950 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3951 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003952 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003953 return(MagickFalse);
3954 return(MagickTrue);
3955}
3956
3957/*
3958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3959% %
3960% %
3961% %
3962+ O p e n P i x e l C a c h e %
3963% %
3964% %
3965% %
3966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967%
3968% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3969% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003970% metacontent, and memory mapping the cache if it is disk based. The cache
3971% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003972%
3973% The format of the OpenPixelCache() method is:
3974%
3975% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3976% ExceptionInfo *exception)
3977%
3978% A description of each parameter follows:
3979%
3980% o image: the image.
3981%
3982% o mode: ReadMode, WriteMode, or IOMode.
3983%
3984% o exception: return any errors or warnings in this structure.
3985%
3986*/
3987
cristyd43a46b2010-01-21 02:13:41 +00003988static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003989{
3990 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003991 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003992 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003993 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003994 {
3995 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003996 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003997 cache_info->length);
3998 }
3999}
4000
4001static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4002{
4003 CacheInfo
4004 *cache_info;
4005
4006 MagickOffsetType
4007 count,
4008 extent,
4009 offset;
4010
4011 cache_info=(CacheInfo *) image->cache;
4012 if (image->debug != MagickFalse)
4013 {
4014 char
4015 format[MaxTextExtent],
4016 message[MaxTextExtent];
4017
cristyb9080c92009-12-01 20:13:26 +00004018 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004019 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004020 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004021 cache_info->cache_filename,cache_info->file,format);
4022 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4023 }
4024 if (length != (MagickSizeType) ((MagickOffsetType) length))
4025 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004026 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004027 if (extent < 0)
4028 return(MagickFalse);
4029 if ((MagickSizeType) extent >= length)
4030 return(MagickTrue);
4031 offset=(MagickOffsetType) length-1;
4032 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4033 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4034}
4035
4036static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4037 ExceptionInfo *exception)
4038{
cristy3ed852e2009-09-05 21:47:34 +00004039 CacheInfo
4040 *cache_info,
4041 source_info;
4042
cristyf3a6a9d2010-11-07 21:02:56 +00004043 char
4044 format[MaxTextExtent],
4045 message[MaxTextExtent];
4046
cristy4c08aed2011-07-01 19:47:50 +00004047 MagickBooleanType
4048 status;
4049
cristy3ed852e2009-09-05 21:47:34 +00004050 MagickSizeType
4051 length,
4052 number_pixels;
4053
cristy3b8fe922011-12-29 18:56:23 +00004054 PixelChannelMap
4055 *p,
4056 *q;
4057
cristy3ed852e2009-09-05 21:47:34 +00004058 size_t
cristye076a6e2010-08-15 19:59:43 +00004059 columns,
cristy3ed852e2009-09-05 21:47:34 +00004060 packet_size;
4061
cristye7cc7cf2010-09-21 13:26:47 +00004062 assert(image != (const Image *) NULL);
4063 assert(image->signature == MagickSignature);
4064 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004065 if (image->debug != MagickFalse)
4066 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4067 if ((image->columns == 0) || (image->rows == 0))
4068 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4069 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004070 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004071 source_info=(*cache_info);
4072 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004073 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004074 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004075 cache_info->storage_class=image->storage_class;
4076 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004077 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004078 cache_info->rows=image->rows;
4079 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004080 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004081 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004082 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4083 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004084 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004085 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004086 if (image->ping != MagickFalse)
4087 {
cristy73724512010-04-12 14:43:14 +00004088 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004089 cache_info->pixels=(Quantum *) NULL;
4090 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004091 cache_info->length=0;
4092 return(MagickTrue);
4093 }
cristy3ed852e2009-09-05 21:47:34 +00004094 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004095 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004096 if (image->metacontent_extent != 0)
4097 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004098 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004099 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004100 if (cache_info->columns != columns)
4101 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4102 image->filename);
4103 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004104 p=cache_info->channel_map;
4105 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004106 if ((cache_info->type != UndefinedCache) &&
4107 (cache_info->columns <= source_info.columns) &&
4108 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004109 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004110 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004111 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4112 {
4113 /*
4114 Inline pixel cache clone optimization.
4115 */
4116 if ((cache_info->columns == source_info.columns) &&
4117 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004118 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004119 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004120 (cache_info->metacontent_extent == source_info.metacontent_extent))
4121 return(MagickTrue);
4122 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4123 }
cristy3ed852e2009-09-05 21:47:34 +00004124 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004125 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004126 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004127 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4128 {
4129 status=AcquireMagickResource(MemoryResource,cache_info->length);
4130 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4131 (cache_info->type == MemoryCache))
4132 {
cristyd43a46b2010-01-21 02:13:41 +00004133 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004134 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004135 cache_info->pixels=source_info.pixels;
4136 else
4137 {
4138 /*
4139 Create memory pixel cache.
4140 */
cristy4c08aed2011-07-01 19:47:50 +00004141 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004142 if (image->debug != MagickFalse)
4143 {
cristy32cacff2011-12-31 03:36:27 +00004144 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004145 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004146 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4147 cache_info->filename,cache_info->mapped != MagickFalse ?
4148 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004149 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004150 format);
cristy3ed852e2009-09-05 21:47:34 +00004151 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4152 message);
4153 }
cristy3ed852e2009-09-05 21:47:34 +00004154 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004155 cache_info->metacontent=(void *) NULL;
4156 if (cache_info->metacontent_extent != 0)
4157 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004158 number_pixels*cache_info->number_channels);
cristy4d9c1922011-12-31 18:37:34 +00004159 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004160 {
cristy4c08aed2011-07-01 19:47:50 +00004161 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004162 exception);
4163 RelinquishPixelCachePixels(&source_info);
4164 }
cristy4c08aed2011-07-01 19:47:50 +00004165 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004166 }
4167 }
4168 RelinquishMagickResource(MemoryResource,cache_info->length);
4169 }
4170 /*
4171 Create pixel cache on disk.
4172 */
4173 status=AcquireMagickResource(DiskResource,cache_info->length);
4174 if (status == MagickFalse)
4175 {
4176 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4177 "CacheResourcesExhausted","`%s'",image->filename);
4178 return(MagickFalse);
4179 }
4180 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4181 {
4182 RelinquishMagickResource(DiskResource,cache_info->length);
4183 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4184 image->filename);
4185 return(MagickFalse);
4186 }
4187 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4188 cache_info->length);
4189 if (status == MagickFalse)
4190 {
4191 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4192 image->filename);
4193 return(MagickFalse);
4194 }
cristyed231572011-07-14 02:18:59 +00004195 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004196 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004197 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004198 cache_info->type=DiskCache;
4199 else
4200 {
4201 status=AcquireMagickResource(MapResource,cache_info->length);
4202 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4203 (cache_info->type != MemoryCache))
4204 cache_info->type=DiskCache;
4205 else
4206 {
cristy4c08aed2011-07-01 19:47:50 +00004207 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004208 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004209 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004210 {
cristy3ed852e2009-09-05 21:47:34 +00004211 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004212 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004213 }
4214 else
4215 {
4216 /*
4217 Create file-backed memory-mapped pixel cache.
4218 */
cristy4c08aed2011-07-01 19:47:50 +00004219 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004220 (void) ClosePixelCacheOnDisk(cache_info);
4221 cache_info->type=MapCache;
4222 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004223 cache_info->metacontent=(void *) NULL;
4224 if (cache_info->metacontent_extent != 0)
4225 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004226 number_pixels*cache_info->number_channels);
cristy4d9c1922011-12-31 18:37:34 +00004227 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004228 {
4229 status=ClonePixelCachePixels(cache_info,&source_info,
4230 exception);
4231 RelinquishPixelCachePixels(&source_info);
4232 }
4233 if (image->debug != MagickFalse)
4234 {
cristy97e7a572009-12-05 15:07:53 +00004235 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004236 format);
cristyb51dff52011-05-19 16:55:47 +00004237 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004238 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004239 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004240 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004241 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004242 format);
cristy3ed852e2009-09-05 21:47:34 +00004243 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4244 message);
4245 }
cristy4c08aed2011-07-01 19:47:50 +00004246 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004247 }
4248 }
4249 RelinquishMagickResource(MapResource,cache_info->length);
4250 }
cristy4c08aed2011-07-01 19:47:50 +00004251 status=MagickTrue;
cristy4d9c1922011-12-31 18:37:34 +00004252 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004253 {
4254 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4255 RelinquishPixelCachePixels(&source_info);
4256 }
4257 if (image->debug != MagickFalse)
4258 {
cristyb9080c92009-12-01 20:13:26 +00004259 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004260 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004261 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004262 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004263 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004264 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004265 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4266 }
cristy4c08aed2011-07-01 19:47:50 +00004267 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004268}
4269
4270/*
4271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4272% %
4273% %
4274% %
4275+ P e r s i s t P i x e l C a c h e %
4276% %
4277% %
4278% %
4279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4280%
4281% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4282% persistent pixel cache is one that resides on disk and is not destroyed
4283% when the program exits.
4284%
4285% The format of the PersistPixelCache() method is:
4286%
4287% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4288% const MagickBooleanType attach,MagickOffsetType *offset,
4289% ExceptionInfo *exception)
4290%
4291% A description of each parameter follows:
4292%
4293% o image: the image.
4294%
4295% o filename: the persistent pixel cache filename.
4296%
cristyf3a6a9d2010-11-07 21:02:56 +00004297% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004298%
cristy3ed852e2009-09-05 21:47:34 +00004299% o initialize: A value other than zero initializes the persistent pixel
4300% cache.
4301%
4302% o offset: the offset in the persistent cache to store pixels.
4303%
4304% o exception: return any errors or warnings in this structure.
4305%
4306*/
4307MagickExport MagickBooleanType PersistPixelCache(Image *image,
4308 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4309 ExceptionInfo *exception)
4310{
4311 CacheInfo
4312 *cache_info,
4313 *clone_info;
4314
4315 Image
4316 clone_image;
4317
cristy3ed852e2009-09-05 21:47:34 +00004318 MagickBooleanType
4319 status;
4320
cristye076a6e2010-08-15 19:59:43 +00004321 ssize_t
4322 page_size;
4323
cristy3ed852e2009-09-05 21:47:34 +00004324 assert(image != (Image *) NULL);
4325 assert(image->signature == MagickSignature);
4326 if (image->debug != MagickFalse)
4327 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4328 assert(image->cache != (void *) NULL);
4329 assert(filename != (const char *) NULL);
4330 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004331 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004332 cache_info=(CacheInfo *) image->cache;
4333 assert(cache_info->signature == MagickSignature);
4334 if (attach != MagickFalse)
4335 {
4336 /*
cristy01b7eb02009-09-10 23:10:14 +00004337 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004338 */
4339 if (image->debug != MagickFalse)
4340 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004341 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004342 (void) CopyMagickString(cache_info->cache_filename,filename,
4343 MaxTextExtent);
4344 cache_info->type=DiskCache;
4345 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004346 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004347 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004348 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004349 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004350 }
cristy01b7eb02009-09-10 23:10:14 +00004351 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4352 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004353 {
cristyf84a1932010-01-03 18:00:18 +00004354 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004355 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004356 (cache_info->reference_count == 1))
4357 {
4358 int
4359 status;
4360
4361 /*
cristy01b7eb02009-09-10 23:10:14 +00004362 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004363 */
cristy320684d2011-09-23 14:55:47 +00004364 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004365 if (status == 0)
4366 {
4367 (void) CopyMagickString(cache_info->cache_filename,filename,
4368 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004369 *offset+=cache_info->length+page_size-(cache_info->length %
4370 page_size);
cristyf84a1932010-01-03 18:00:18 +00004371 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004372 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004373 if (image->debug != MagickFalse)
4374 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4375 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004376 return(MagickTrue);
4377 }
4378 }
cristyf84a1932010-01-03 18:00:18 +00004379 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004380 }
4381 /*
cristy01b7eb02009-09-10 23:10:14 +00004382 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004383 */
4384 clone_image=(*image);
4385 clone_info=(CacheInfo *) clone_image.cache;
4386 image->cache=ClonePixelCache(cache_info);
4387 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4388 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4389 cache_info->type=DiskCache;
4390 cache_info->offset=(*offset);
4391 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004392 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004393 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004394 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004395 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004396 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4397 return(status);
4398}
4399
4400/*
4401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4402% %
4403% %
4404% %
4405+ Q u e u e A u t h e n t i c N e x u s %
4406% %
4407% %
4408% %
4409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4410%
4411% QueueAuthenticNexus() allocates an region to store image pixels as defined
4412% by the region rectangle and returns a pointer to the region. This region is
4413% subsequently transferred from the pixel cache with
4414% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4415% pixels are transferred, otherwise a NULL is returned.
4416%
4417% The format of the QueueAuthenticNexus() method is:
4418%
cristy4c08aed2011-07-01 19:47:50 +00004419% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004420% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004421% const MagickBooleanType clone,NexusInfo *nexus_info,
4422% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004423%
4424% A description of each parameter follows:
4425%
4426% o image: the image.
4427%
4428% o x,y,columns,rows: These values define the perimeter of a region of
4429% pixels.
4430%
4431% o nexus_info: the cache nexus to set.
4432%
cristy65dbf172011-10-06 17:32:04 +00004433% o clone: clone the pixel cache.
4434%
cristy3ed852e2009-09-05 21:47:34 +00004435% o exception: return any errors or warnings in this structure.
4436%
4437*/
cristya6577ff2011-09-02 19:54:26 +00004438MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004439 const ssize_t y,const size_t columns,const size_t rows,
4440 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004441{
4442 CacheInfo
4443 *cache_info;
4444
4445 MagickOffsetType
4446 offset;
4447
4448 MagickSizeType
4449 number_pixels;
4450
4451 RectangleInfo
4452 region;
4453
4454 /*
4455 Validate pixel cache geometry.
4456 */
cristye7cc7cf2010-09-21 13:26:47 +00004457 assert(image != (const Image *) NULL);
4458 assert(image->signature == MagickSignature);
4459 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004460 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004461 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004462 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004463 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004464 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4465 {
4466 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4467 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004468 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004469 }
cristybb503372010-05-27 20:51:26 +00004470 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4471 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004472 {
4473 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4474 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004475 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004476 }
4477 offset=(MagickOffsetType) y*cache_info->columns+x;
4478 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004479 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004480 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4481 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4482 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004483 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004484 /*
4485 Return pixel cache.
4486 */
4487 region.x=x;
4488 region.y=y;
4489 region.width=columns;
4490 region.height=rows;
4491 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4492}
4493
4494/*
4495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4496% %
4497% %
4498% %
4499+ 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 %
4500% %
4501% %
4502% %
4503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4504%
4505% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4506% defined by the region rectangle and returns a pointer to the region. This
4507% region is subsequently transferred from the pixel cache with
4508% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4509% pixels are transferred, otherwise a NULL is returned.
4510%
4511% The format of the QueueAuthenticPixelsCache() method is:
4512%
cristy4c08aed2011-07-01 19:47:50 +00004513% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004514% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004515% ExceptionInfo *exception)
4516%
4517% A description of each parameter follows:
4518%
4519% o image: the image.
4520%
4521% o x,y,columns,rows: These values define the perimeter of a region of
4522% pixels.
4523%
4524% o exception: return any errors or warnings in this structure.
4525%
4526*/
cristy4c08aed2011-07-01 19:47:50 +00004527static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004528 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004529 ExceptionInfo *exception)
4530{
4531 CacheInfo
4532 *cache_info;
4533
cristy5c9e6f22010-09-17 17:31:01 +00004534 const int
4535 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004536
cristy4c08aed2011-07-01 19:47:50 +00004537 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004538 *q;
cristy4c08aed2011-07-01 19:47:50 +00004539
cristye7cc7cf2010-09-21 13:26:47 +00004540 assert(image != (const Image *) NULL);
4541 assert(image->signature == MagickSignature);
4542 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004543 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004544 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004545 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004546 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4547 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004548 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004549}
4550
4551/*
4552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4553% %
4554% %
4555% %
4556% Q u e u e A u t h e n t i c P i x e l s %
4557% %
4558% %
4559% %
4560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561%
4562% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004563% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004564% region is returned, otherwise NULL is returned. The returned pointer may
4565% point to a temporary working buffer for the pixels or it may point to the
4566% final location of the pixels in memory.
4567%
4568% Write-only access means that any existing pixel values corresponding to
4569% the region are ignored. This is useful if the initial image is being
4570% created from scratch, or if the existing pixel values are to be
4571% completely replaced without need to refer to their pre-existing values.
4572% The application is free to read and write the pixel buffer returned by
4573% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4574% initialize the pixel array values. Initializing pixel array values is the
4575% application's responsibility.
4576%
4577% Performance is maximized if the selected region is part of one row, or
4578% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004579% pixels in-place (without a copy) if the image is in memory, or in a
4580% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004581% by the user.
4582%
4583% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004584% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4585% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4586% obtain the meta-content (of type void) corresponding to the region.
4587% Once the Quantum (and/or Quantum) array has been updated, the
4588% changes must be saved back to the underlying image using
4589% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004590%
4591% The format of the QueueAuthenticPixels() method is:
4592%
cristy4c08aed2011-07-01 19:47:50 +00004593% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004594% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004595% ExceptionInfo *exception)
4596%
4597% A description of each parameter follows:
4598%
4599% o image: the image.
4600%
4601% o x,y,columns,rows: These values define the perimeter of a region of
4602% pixels.
4603%
4604% o exception: return any errors or warnings in this structure.
4605%
4606*/
cristy4c08aed2011-07-01 19:47:50 +00004607MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004608 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004609 ExceptionInfo *exception)
4610{
4611 CacheInfo
4612 *cache_info;
4613
cristy2036f5c2010-09-19 21:18:17 +00004614 const int
4615 id = GetOpenMPThreadId();
4616
cristy4c08aed2011-07-01 19:47:50 +00004617 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004618 *q;
cristy4c08aed2011-07-01 19:47:50 +00004619
cristy3ed852e2009-09-05 21:47:34 +00004620 assert(image != (Image *) NULL);
4621 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004622 assert(image->cache != (Cache) NULL);
4623 cache_info=(CacheInfo *) image->cache;
4624 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004625 if (cache_info->methods.queue_authentic_pixels_handler !=
4626 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004627 {
cristyacd2ed22011-08-30 01:44:23 +00004628 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004629 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004630 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004631 }
cristy2036f5c2010-09-19 21:18:17 +00004632 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004633 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4634 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004635 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004636}
4637
4638/*
4639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4640% %
4641% %
4642% %
cristy4c08aed2011-07-01 19:47:50 +00004643+ 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 +00004644% %
4645% %
4646% %
4647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4648%
cristy4c08aed2011-07-01 19:47:50 +00004649% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004650% the pixel cache.
4651%
cristy4c08aed2011-07-01 19:47:50 +00004652% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004653%
cristy4c08aed2011-07-01 19:47:50 +00004654% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004655% NexusInfo *nexus_info,ExceptionInfo *exception)
4656%
4657% A description of each parameter follows:
4658%
4659% o cache_info: the pixel cache.
4660%
cristy4c08aed2011-07-01 19:47:50 +00004661% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004662%
4663% o exception: return any errors or warnings in this structure.
4664%
4665*/
cristy4c08aed2011-07-01 19:47:50 +00004666static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004667 NexusInfo *nexus_info,ExceptionInfo *exception)
4668{
4669 MagickOffsetType
4670 count,
4671 offset;
4672
4673 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004674 extent,
4675 length;
cristy3ed852e2009-09-05 21:47:34 +00004676
cristybb503372010-05-27 20:51:26 +00004677 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004678 y;
4679
cristy4c08aed2011-07-01 19:47:50 +00004680 register unsigned char
4681 *restrict q;
4682
cristybb503372010-05-27 20:51:26 +00004683 size_t
cristy3ed852e2009-09-05 21:47:34 +00004684 rows;
4685
cristy4c08aed2011-07-01 19:47:50 +00004686 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004687 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004688 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004689 return(MagickTrue);
4690 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4691 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004692 length=(MagickSizeType) nexus_info->region.width*
4693 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004694 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004695 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004696 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004697 switch (cache_info->type)
4698 {
4699 case MemoryCache:
4700 case MapCache:
4701 {
cristy4c08aed2011-07-01 19:47:50 +00004702 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004703 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004704
4705 /*
cristy4c08aed2011-07-01 19:47:50 +00004706 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004707 */
cristydd341db2010-03-04 19:06:38 +00004708 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004709 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004710 {
cristy48078b12010-09-23 17:11:01 +00004711 length=extent;
cristydd341db2010-03-04 19:06:38 +00004712 rows=1UL;
4713 }
cristy4c08aed2011-07-01 19:47:50 +00004714 p=(unsigned char *) cache_info->metacontent+offset*
4715 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004716 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004717 {
cristy8f036fe2010-09-18 02:02:00 +00004718 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004719 p+=cache_info->metacontent_extent*cache_info->columns;
4720 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004721 }
4722 break;
4723 }
4724 case DiskCache:
4725 {
4726 /*
cristy4c08aed2011-07-01 19:47:50 +00004727 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004728 */
4729 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4730 {
4731 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4732 cache_info->cache_filename);
4733 return(MagickFalse);
4734 }
cristydd341db2010-03-04 19:06:38 +00004735 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004736 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004737 {
cristy48078b12010-09-23 17:11:01 +00004738 length=extent;
cristydd341db2010-03-04 19:06:38 +00004739 rows=1UL;
4740 }
cristy48078b12010-09-23 17:11:01 +00004741 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004742 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004743 {
cristy48078b12010-09-23 17:11:01 +00004744 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004745 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004746 cache_info->metacontent_extent,length,(unsigned char *) q);
4747 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004748 break;
4749 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004750 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004751 }
cristybb503372010-05-27 20:51:26 +00004752 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004753 {
4754 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4755 cache_info->cache_filename);
4756 return(MagickFalse);
4757 }
4758 break;
4759 }
4760 default:
4761 break;
4762 }
4763 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004764 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004765 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004766 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004767 nexus_info->region.width,(double) nexus_info->region.height,(double)
4768 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004769 return(MagickTrue);
4770}
4771
4772/*
4773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4774% %
4775% %
4776% %
4777+ R e a d P i x e l C a c h e P i x e l s %
4778% %
4779% %
4780% %
4781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4782%
4783% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4784% cache.
4785%
4786% The format of the ReadPixelCachePixels() method is:
4787%
4788% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4789% NexusInfo *nexus_info,ExceptionInfo *exception)
4790%
4791% A description of each parameter follows:
4792%
4793% o cache_info: the pixel cache.
4794%
4795% o nexus_info: the cache nexus to read the pixels.
4796%
4797% o exception: return any errors or warnings in this structure.
4798%
4799*/
4800static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4801 NexusInfo *nexus_info,ExceptionInfo *exception)
4802{
4803 MagickOffsetType
4804 count,
4805 offset;
4806
4807 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004808 extent,
4809 length;
cristy3ed852e2009-09-05 21:47:34 +00004810
cristy4c08aed2011-07-01 19:47:50 +00004811 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004812 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004813
cristye076a6e2010-08-15 19:59:43 +00004814 register ssize_t
4815 y;
4816
cristybb503372010-05-27 20:51:26 +00004817 size_t
cristy3ed852e2009-09-05 21:47:34 +00004818 rows;
4819
cristy4c08aed2011-07-01 19:47:50 +00004820 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004821 return(MagickTrue);
4822 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4823 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004824 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004825 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004826 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004827 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004828 q=nexus_info->pixels;
4829 switch (cache_info->type)
4830 {
4831 case MemoryCache:
4832 case MapCache:
4833 {
cristy4c08aed2011-07-01 19:47:50 +00004834 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004835 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004836
4837 /*
4838 Read pixels from memory.
4839 */
cristydd341db2010-03-04 19:06:38 +00004840 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004841 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004842 {
cristy48078b12010-09-23 17:11:01 +00004843 length=extent;
cristydd341db2010-03-04 19:06:38 +00004844 rows=1UL;
4845 }
cristyed231572011-07-14 02:18:59 +00004846 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004847 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004848 {
cristy8f036fe2010-09-18 02:02:00 +00004849 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004850 p+=cache_info->number_channels*cache_info->columns;
4851 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004852 }
4853 break;
4854 }
4855 case DiskCache:
4856 {
4857 /*
4858 Read pixels from disk.
4859 */
4860 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4861 {
4862 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4863 cache_info->cache_filename);
4864 return(MagickFalse);
4865 }
cristydd341db2010-03-04 19:06:38 +00004866 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004867 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004868 {
cristy48078b12010-09-23 17:11:01 +00004869 length=extent;
cristydd341db2010-03-04 19:06:38 +00004870 rows=1UL;
4871 }
cristybb503372010-05-27 20:51:26 +00004872 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004873 {
4874 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004875 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004876 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004877 break;
4878 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004879 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004880 }
cristybb503372010-05-27 20:51:26 +00004881 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004882 {
4883 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4884 cache_info->cache_filename);
4885 return(MagickFalse);
4886 }
4887 break;
4888 }
4889 default:
4890 break;
4891 }
4892 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004893 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004894 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004895 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004896 nexus_info->region.width,(double) nexus_info->region.height,(double)
4897 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004898 return(MagickTrue);
4899}
4900
4901/*
4902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4903% %
4904% %
4905% %
4906+ R e f e r e n c e P i x e l C a c h e %
4907% %
4908% %
4909% %
4910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4911%
4912% ReferencePixelCache() increments the reference count associated with the
4913% pixel cache returning a pointer to the cache.
4914%
4915% The format of the ReferencePixelCache method is:
4916%
4917% Cache ReferencePixelCache(Cache cache_info)
4918%
4919% A description of each parameter follows:
4920%
4921% o cache_info: the pixel cache.
4922%
4923*/
cristya6577ff2011-09-02 19:54:26 +00004924MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004925{
4926 CacheInfo
4927 *cache_info;
4928
4929 assert(cache != (Cache *) NULL);
4930 cache_info=(CacheInfo *) cache;
4931 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004932 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004933 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004934 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004935 return(cache_info);
4936}
4937
4938/*
4939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4940% %
4941% %
4942% %
4943+ S e t P i x e l C a c h e M e t h o d s %
4944% %
4945% %
4946% %
4947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4948%
4949% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4950%
4951% The format of the SetPixelCacheMethods() method is:
4952%
4953% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4954%
4955% A description of each parameter follows:
4956%
4957% o cache: the pixel cache.
4958%
4959% o cache_methods: Specifies a pointer to a CacheMethods structure.
4960%
4961*/
cristya6577ff2011-09-02 19:54:26 +00004962MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004963{
4964 CacheInfo
4965 *cache_info;
4966
4967 GetOneAuthenticPixelFromHandler
4968 get_one_authentic_pixel_from_handler;
4969
4970 GetOneVirtualPixelFromHandler
4971 get_one_virtual_pixel_from_handler;
4972
4973 /*
4974 Set cache pixel methods.
4975 */
4976 assert(cache != (Cache) NULL);
4977 assert(cache_methods != (CacheMethods *) NULL);
4978 cache_info=(CacheInfo *) cache;
4979 assert(cache_info->signature == MagickSignature);
4980 if (cache_info->debug != MagickFalse)
4981 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4982 cache_info->filename);
4983 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4984 cache_info->methods.get_virtual_pixel_handler=
4985 cache_methods->get_virtual_pixel_handler;
4986 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4987 cache_info->methods.destroy_pixel_handler=
4988 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004989 if (cache_methods->get_virtual_metacontent_from_handler !=
4990 (GetVirtualMetacontentFromHandler) NULL)
4991 cache_info->methods.get_virtual_metacontent_from_handler=
4992 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004993 if (cache_methods->get_authentic_pixels_handler !=
4994 (GetAuthenticPixelsHandler) NULL)
4995 cache_info->methods.get_authentic_pixels_handler=
4996 cache_methods->get_authentic_pixels_handler;
4997 if (cache_methods->queue_authentic_pixels_handler !=
4998 (QueueAuthenticPixelsHandler) NULL)
4999 cache_info->methods.queue_authentic_pixels_handler=
5000 cache_methods->queue_authentic_pixels_handler;
5001 if (cache_methods->sync_authentic_pixels_handler !=
5002 (SyncAuthenticPixelsHandler) NULL)
5003 cache_info->methods.sync_authentic_pixels_handler=
5004 cache_methods->sync_authentic_pixels_handler;
5005 if (cache_methods->get_authentic_pixels_from_handler !=
5006 (GetAuthenticPixelsFromHandler) NULL)
5007 cache_info->methods.get_authentic_pixels_from_handler=
5008 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00005009 if (cache_methods->get_authentic_metacontent_from_handler !=
5010 (GetAuthenticMetacontentFromHandler) NULL)
5011 cache_info->methods.get_authentic_metacontent_from_handler=
5012 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00005013 get_one_virtual_pixel_from_handler=
5014 cache_info->methods.get_one_virtual_pixel_from_handler;
5015 if (get_one_virtual_pixel_from_handler !=
5016 (GetOneVirtualPixelFromHandler) NULL)
5017 cache_info->methods.get_one_virtual_pixel_from_handler=
5018 cache_methods->get_one_virtual_pixel_from_handler;
5019 get_one_authentic_pixel_from_handler=
5020 cache_methods->get_one_authentic_pixel_from_handler;
5021 if (get_one_authentic_pixel_from_handler !=
5022 (GetOneAuthenticPixelFromHandler) NULL)
5023 cache_info->methods.get_one_authentic_pixel_from_handler=
5024 cache_methods->get_one_authentic_pixel_from_handler;
5025}
5026
5027/*
5028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5029% %
5030% %
5031% %
5032+ S e t P i x e l C a c h e N e x u s P i x e l s %
5033% %
5034% %
5035% %
5036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5037%
5038% SetPixelCacheNexusPixels() defines the region of the cache for the
5039% specified cache nexus.
5040%
5041% The format of the SetPixelCacheNexusPixels() method is:
5042%
cristy4c08aed2011-07-01 19:47:50 +00005043% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005044% const RectangleInfo *region,NexusInfo *nexus_info,
5045% ExceptionInfo *exception)
5046%
5047% A description of each parameter follows:
5048%
5049% o image: the image.
5050%
5051% o region: A pointer to the RectangleInfo structure that defines the
5052% region of this particular cache nexus.
5053%
5054% o nexus_info: the cache nexus to set.
5055%
5056% o exception: return any errors or warnings in this structure.
5057%
5058*/
cristyabd6e372010-09-15 19:11:26 +00005059
5060static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5061 NexusInfo *nexus_info,ExceptionInfo *exception)
5062{
5063 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5064 return(MagickFalse);
5065 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005066 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005067 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005068 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005069 {
5070 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005071 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005072 nexus_info->length);
5073 }
cristy4c08aed2011-07-01 19:47:50 +00005074 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005075 {
5076 (void) ThrowMagickException(exception,GetMagickModule(),
5077 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5078 cache_info->filename);
5079 return(MagickFalse);
5080 }
5081 return(MagickTrue);
5082}
5083
cristy4c08aed2011-07-01 19:47:50 +00005084static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005085 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5086{
5087 CacheInfo
5088 *cache_info;
5089
5090 MagickBooleanType
5091 status;
5092
cristy3ed852e2009-09-05 21:47:34 +00005093 MagickSizeType
5094 length,
5095 number_pixels;
5096
cristy3ed852e2009-09-05 21:47:34 +00005097 cache_info=(CacheInfo *) image->cache;
5098 assert(cache_info->signature == MagickSignature);
5099 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005100 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005101 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005102 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5103 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005104 {
cristybb503372010-05-27 20:51:26 +00005105 ssize_t
cristybad067a2010-02-15 17:20:55 +00005106 x,
5107 y;
cristy3ed852e2009-09-05 21:47:34 +00005108
cristyeaedf062010-05-29 22:36:02 +00005109 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5110 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005111 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5112 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005113 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005114 ((nexus_info->region.width == cache_info->columns) ||
5115 ((nexus_info->region.width % cache_info->columns) == 0)))))
5116 {
5117 MagickOffsetType
5118 offset;
5119
5120 /*
5121 Pixels are accessed directly from memory.
5122 */
5123 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5124 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005125 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005126 offset;
5127 nexus_info->metacontent=(void *) NULL;
5128 if (cache_info->metacontent_extent != 0)
5129 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5130 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005131 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005132 }
5133 }
5134 /*
5135 Pixels are stored in a cache region until they are synced to the cache.
5136 */
5137 number_pixels=(MagickSizeType) nexus_info->region.width*
5138 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005139 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005140 if (cache_info->metacontent_extent != 0)
5141 length+=number_pixels*cache_info->metacontent_extent;
5142 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005143 {
5144 nexus_info->length=length;
5145 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5146 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005147 {
5148 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005149 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005150 }
cristy3ed852e2009-09-05 21:47:34 +00005151 }
5152 else
5153 if (nexus_info->length != length)
5154 {
5155 RelinquishCacheNexusPixels(nexus_info);
5156 nexus_info->length=length;
5157 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5158 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005159 {
5160 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005161 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005162 }
cristy3ed852e2009-09-05 21:47:34 +00005163 }
5164 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005165 nexus_info->metacontent=(void *) NULL;
5166 if (cache_info->metacontent_extent != 0)
5167 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005168 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005169 return(nexus_info->pixels);
5170}
5171
5172/*
5173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5174% %
5175% %
5176% %
5177% 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 %
5178% %
5179% %
5180% %
5181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5182%
5183% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5184% pixel cache and returns the previous setting. A virtual pixel is any pixel
5185% access that is outside the boundaries of the image cache.
5186%
5187% The format of the SetPixelCacheVirtualMethod() method is:
5188%
5189% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5190% const VirtualPixelMethod virtual_pixel_method)
5191%
5192% A description of each parameter follows:
5193%
5194% o image: the image.
5195%
5196% o virtual_pixel_method: choose the type of virtual pixel.
5197%
5198*/
cristyd1dd6e42011-09-04 01:46:08 +00005199MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005200 const VirtualPixelMethod virtual_pixel_method)
5201{
5202 CacheInfo
5203 *cache_info;
5204
5205 VirtualPixelMethod
5206 method;
5207
5208 assert(image != (Image *) NULL);
5209 assert(image->signature == MagickSignature);
5210 if (image->debug != MagickFalse)
5211 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5212 assert(image->cache != (Cache) NULL);
5213 cache_info=(CacheInfo *) image->cache;
5214 assert(cache_info->signature == MagickSignature);
5215 method=cache_info->virtual_pixel_method;
5216 cache_info->virtual_pixel_method=virtual_pixel_method;
5217 return(method);
5218}
5219
5220/*
5221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222% %
5223% %
5224% %
5225+ 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 %
5226% %
5227% %
5228% %
5229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230%
5231% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5232% in-memory or disk cache. The method returns MagickTrue if the pixel region
5233% is synced, otherwise MagickFalse.
5234%
5235% The format of the SyncAuthenticPixelCacheNexus() method is:
5236%
5237% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5238% NexusInfo *nexus_info,ExceptionInfo *exception)
5239%
5240% A description of each parameter follows:
5241%
5242% o image: the image.
5243%
5244% o nexus_info: the cache nexus to sync.
5245%
5246% o exception: return any errors or warnings in this structure.
5247%
5248*/
cristya6577ff2011-09-02 19:54:26 +00005249MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005250 NexusInfo *nexus_info,ExceptionInfo *exception)
5251{
5252 CacheInfo
5253 *cache_info;
5254
5255 MagickBooleanType
5256 status;
5257
5258 /*
5259 Transfer pixels to the cache.
5260 */
5261 assert(image != (Image *) NULL);
5262 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005263 if (image->cache == (Cache) NULL)
5264 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5265 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005266 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005267 if (cache_info->type == UndefinedCache)
5268 return(MagickFalse);
5269 if ((image->clip_mask != (Image *) NULL) &&
5270 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5271 return(MagickFalse);
5272 if ((image->mask != (Image *) NULL) &&
5273 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5274 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005275 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005276 return(MagickTrue);
5277 assert(cache_info->signature == MagickSignature);
5278 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005279 if ((cache_info->metacontent_extent != 0) &&
5280 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005281 return(MagickFalse);
5282 return(status);
5283}
5284
5285/*
5286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5287% %
5288% %
5289% %
5290+ S y n c A u t h e n t i c P i x e l C a c h e %
5291% %
5292% %
5293% %
5294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5295%
5296% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5297% or disk cache. The method returns MagickTrue if the pixel region is synced,
5298% otherwise MagickFalse.
5299%
5300% The format of the SyncAuthenticPixelsCache() method is:
5301%
5302% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5303% ExceptionInfo *exception)
5304%
5305% A description of each parameter follows:
5306%
5307% o image: the image.
5308%
5309% o exception: return any errors or warnings in this structure.
5310%
5311*/
5312static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5313 ExceptionInfo *exception)
5314{
5315 CacheInfo
5316 *cache_info;
5317
cristy5c9e6f22010-09-17 17:31:01 +00005318 const int
5319 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005320
cristy4c08aed2011-07-01 19:47:50 +00005321 MagickBooleanType
5322 status;
5323
cristye7cc7cf2010-09-21 13:26:47 +00005324 assert(image != (Image *) NULL);
5325 assert(image->signature == MagickSignature);
5326 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005327 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005328 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005329 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005330 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5331 exception);
5332 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005333}
5334
5335/*
5336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5337% %
5338% %
5339% %
5340% S y n c A u t h e n t i c P i x e l s %
5341% %
5342% %
5343% %
5344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5345%
5346% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5347% The method returns MagickTrue if the pixel region is flushed, otherwise
5348% MagickFalse.
5349%
5350% The format of the SyncAuthenticPixels() method is:
5351%
5352% MagickBooleanType SyncAuthenticPixels(Image *image,
5353% ExceptionInfo *exception)
5354%
5355% A description of each parameter follows:
5356%
5357% o image: the image.
5358%
5359% o exception: return any errors or warnings in this structure.
5360%
5361*/
5362MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5363 ExceptionInfo *exception)
5364{
5365 CacheInfo
5366 *cache_info;
5367
cristy2036f5c2010-09-19 21:18:17 +00005368 const int
5369 id = GetOpenMPThreadId();
5370
cristy4c08aed2011-07-01 19:47:50 +00005371 MagickBooleanType
5372 status;
5373
cristy3ed852e2009-09-05 21:47:34 +00005374 assert(image != (Image *) NULL);
5375 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005376 assert(image->cache != (Cache) NULL);
5377 cache_info=(CacheInfo *) image->cache;
5378 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005379 if (cache_info->methods.sync_authentic_pixels_handler !=
5380 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005381 {
5382 status=cache_info->methods.sync_authentic_pixels_handler(image,
5383 exception);
5384 return(status);
5385 }
cristy2036f5c2010-09-19 21:18:17 +00005386 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005387 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5388 exception);
5389 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005390}
5391
5392/*
5393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5394% %
5395% %
5396% %
cristyd1dd6e42011-09-04 01:46:08 +00005397+ 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 +00005398% %
5399% %
5400% %
5401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5402%
5403% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5404% The method returns MagickTrue if the pixel region is flushed, otherwise
5405% MagickFalse.
5406%
5407% The format of the SyncImagePixelCache() method is:
5408%
5409% MagickBooleanType SyncImagePixelCache(Image *image,
5410% ExceptionInfo *exception)
5411%
5412% A description of each parameter follows:
5413%
5414% o image: the image.
5415%
5416% o exception: return any errors or warnings in this structure.
5417%
5418*/
cristyd1dd6e42011-09-04 01:46:08 +00005419MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005420 ExceptionInfo *exception)
5421{
5422 CacheInfo
5423 *cache_info;
5424
5425 assert(image != (Image *) NULL);
5426 assert(exception != (ExceptionInfo *) NULL);
5427 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5428 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5429}
5430
5431/*
5432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5433% %
5434% %
5435% %
cristy4c08aed2011-07-01 19:47:50 +00005436+ 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 +00005437% %
5438% %
5439% %
5440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5441%
cristy4c08aed2011-07-01 19:47:50 +00005442% WritePixelCacheMetacontent() writes the meta-content to the specified region
5443% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005444%
cristy4c08aed2011-07-01 19:47:50 +00005445% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005446%
cristy4c08aed2011-07-01 19:47:50 +00005447% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005448% NexusInfo *nexus_info,ExceptionInfo *exception)
5449%
5450% A description of each parameter follows:
5451%
5452% o cache_info: the pixel cache.
5453%
cristy4c08aed2011-07-01 19:47:50 +00005454% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005455%
5456% o exception: return any errors or warnings in this structure.
5457%
5458*/
cristy4c08aed2011-07-01 19:47:50 +00005459static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005460 NexusInfo *nexus_info,ExceptionInfo *exception)
5461{
5462 MagickOffsetType
5463 count,
5464 offset;
5465
5466 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005467 extent,
5468 length;
cristy3ed852e2009-09-05 21:47:34 +00005469
cristy4c08aed2011-07-01 19:47:50 +00005470 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005471 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005472
cristybb503372010-05-27 20:51:26 +00005473 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005474 y;
5475
cristybb503372010-05-27 20:51:26 +00005476 size_t
cristy3ed852e2009-09-05 21:47:34 +00005477 rows;
5478
cristy4c08aed2011-07-01 19:47:50 +00005479 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005480 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005481 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005482 return(MagickTrue);
5483 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5484 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005485 length=(MagickSizeType) nexus_info->region.width*
5486 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005487 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005488 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005489 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005490 switch (cache_info->type)
5491 {
5492 case MemoryCache:
5493 case MapCache:
5494 {
cristy4c08aed2011-07-01 19:47:50 +00005495 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005496 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005497
5498 /*
cristy4c08aed2011-07-01 19:47:50 +00005499 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005500 */
cristydd341db2010-03-04 19:06:38 +00005501 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005502 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005503 {
cristy48078b12010-09-23 17:11:01 +00005504 length=extent;
cristydd341db2010-03-04 19:06:38 +00005505 rows=1UL;
5506 }
cristy4c08aed2011-07-01 19:47:50 +00005507 q=(unsigned char *) cache_info->metacontent+offset*
5508 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005509 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005510 {
cristy8f036fe2010-09-18 02:02:00 +00005511 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005512 p+=nexus_info->region.width*cache_info->metacontent_extent;
5513 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005514 }
5515 break;
5516 }
5517 case DiskCache:
5518 {
5519 /*
cristy4c08aed2011-07-01 19:47:50 +00005520 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005521 */
5522 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5523 {
5524 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5525 cache_info->cache_filename);
5526 return(MagickFalse);
5527 }
cristydd341db2010-03-04 19:06:38 +00005528 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005529 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005530 {
cristy48078b12010-09-23 17:11:01 +00005531 length=extent;
cristydd341db2010-03-04 19:06:38 +00005532 rows=1UL;
5533 }
cristy48078b12010-09-23 17:11:01 +00005534 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005535 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005536 {
cristy48078b12010-09-23 17:11:01 +00005537 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005538 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005539 cache_info->metacontent_extent,length,(const unsigned char *) p);
5540 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005541 break;
cristy4c08aed2011-07-01 19:47:50 +00005542 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005543 offset+=cache_info->columns;
5544 }
cristybb503372010-05-27 20:51:26 +00005545 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005546 {
5547 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5548 cache_info->cache_filename);
5549 return(MagickFalse);
5550 }
5551 break;
5552 }
5553 default:
5554 break;
5555 }
5556 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005557 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005558 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005559 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005560 nexus_info->region.width,(double) nexus_info->region.height,(double)
5561 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005562 return(MagickTrue);
5563}
5564
5565/*
5566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5567% %
5568% %
5569% %
5570+ W r i t e C a c h e P i x e l s %
5571% %
5572% %
5573% %
5574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5575%
5576% WritePixelCachePixels() writes image pixels to the specified region of the
5577% pixel cache.
5578%
5579% The format of the WritePixelCachePixels() method is:
5580%
5581% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5582% NexusInfo *nexus_info,ExceptionInfo *exception)
5583%
5584% A description of each parameter follows:
5585%
5586% o cache_info: the pixel cache.
5587%
5588% o nexus_info: the cache nexus to write the pixels.
5589%
5590% o exception: return any errors or warnings in this structure.
5591%
5592*/
5593static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5594 NexusInfo *nexus_info,ExceptionInfo *exception)
5595{
5596 MagickOffsetType
5597 count,
5598 offset;
5599
5600 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005601 extent,
5602 length;
cristy3ed852e2009-09-05 21:47:34 +00005603
cristy4c08aed2011-07-01 19:47:50 +00005604 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005605 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005606
cristybb503372010-05-27 20:51:26 +00005607 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005608 y;
5609
cristybb503372010-05-27 20:51:26 +00005610 size_t
cristy3ed852e2009-09-05 21:47:34 +00005611 rows;
5612
cristy4c08aed2011-07-01 19:47:50 +00005613 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005614 return(MagickTrue);
5615 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5616 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005617 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005618 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005619 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005620 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005621 p=nexus_info->pixels;
5622 switch (cache_info->type)
5623 {
5624 case MemoryCache:
5625 case MapCache:
5626 {
cristy4c08aed2011-07-01 19:47:50 +00005627 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005628 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005629
5630 /*
5631 Write pixels to memory.
5632 */
cristydd341db2010-03-04 19:06:38 +00005633 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005634 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005635 {
cristy48078b12010-09-23 17:11:01 +00005636 length=extent;
cristydd341db2010-03-04 19:06:38 +00005637 rows=1UL;
5638 }
cristyed231572011-07-14 02:18:59 +00005639 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005640 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005641 {
cristy8f036fe2010-09-18 02:02:00 +00005642 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005643 p+=nexus_info->region.width*cache_info->number_channels;
5644 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005645 }
5646 break;
5647 }
5648 case DiskCache:
5649 {
5650 /*
5651 Write pixels to disk.
5652 */
5653 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5654 {
5655 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5656 cache_info->cache_filename);
5657 return(MagickFalse);
5658 }
cristydd341db2010-03-04 19:06:38 +00005659 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005660 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005661 {
cristy48078b12010-09-23 17:11:01 +00005662 length=extent;
cristydd341db2010-03-04 19:06:38 +00005663 rows=1UL;
5664 }
cristybb503372010-05-27 20:51:26 +00005665 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005666 {
5667 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005668 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005669 p);
5670 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005671 break;
cristyed231572011-07-14 02:18:59 +00005672 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005673 offset+=cache_info->columns;
5674 }
cristybb503372010-05-27 20:51:26 +00005675 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005676 {
5677 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5678 cache_info->cache_filename);
5679 return(MagickFalse);
5680 }
5681 break;
5682 }
5683 default:
5684 break;
5685 }
5686 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005687 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005688 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005689 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005690 nexus_info->region.width,(double) nexus_info->region.height,(double)
5691 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005692 return(MagickTrue);
5693}