blob: 8dda3b95997fa9d904bdba535d96e32e1eeec722 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78
79/*
cristy3ed852e2009-09-05 21:47:34 +000080 Typedef declarations.
81*/
82typedef struct _MagickModulo
83{
cristybb503372010-05-27 20:51:26 +000084 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000085 quotient,
86 remainder;
87} MagickModulo;
88
89struct _NexusInfo
90{
91 MagickBooleanType
92 mapped;
93
94 RectangleInfo
95 region;
96
97 MagickSizeType
98 length;
99
cristy4c08aed2011-07-01 19:47:50 +0000100 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000101 *cache,
102 *pixels;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 void
105 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000106
cristybb503372010-05-27 20:51:26 +0000107 size_t
cristy3ed852e2009-09-05 21:47:34 +0000108 signature;
109};
110
111/*
112 Forward declarations.
113*/
114#if defined(__cplusplus) || defined(c_plusplus)
115extern "C" {
116#endif
117
cristy4c08aed2011-07-01 19:47:50 +0000118static const Quantum
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
cristy4c08aed2011-07-01 19:47:50 +0000123static const void
124 *GetVirtualMetacontentFromCache(const Image *);
125
cristy3ed852e2009-09-05 21:47:34 +0000126static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000128 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
137
cristy4c08aed2011-07-01 19:47:50 +0000138static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000144 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146#if defined(__cplusplus) || defined(c_plusplus)
147}
148#endif
149
150/*
151 Global declarations.
152*/
153static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
155
156static SemaphoreInfo
157 *cache_semaphore = (SemaphoreInfo *) NULL;
158
159static SplayTreeInfo
160 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167+ A c q u i r e P i x e l C a c h e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquirePixelCache() acquires a pixel cache.
174%
175% The format of the AcquirePixelCache() method is:
176%
cristybb503372010-05-27 20:51:26 +0000177% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178%
179% A description of each parameter follows:
180%
181% o number_threads: the number of nexus threads.
182%
183*/
cristya6577ff2011-09-02 19:54:26 +0000184MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000185{
186 CacheInfo
187 *cache_info;
188
cristya64b85d2011-09-14 01:02:31 +0000189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000194 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristya6577ff2011-09-02 19:54:26 +0000250MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristya64b85d2011-09-14 01:02:31 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
cristyd1dd6e42011-09-04 01:46:08 +0000301MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
cristy5ff4eaf2011-09-03 01:38:02 +0000339MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
cristy5ff4eaf2011-09-03 01:38:02 +0000363MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000387% mask. It returns MagickTrue if the pixel region is clipped, otherwise
388% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
cristy4c08aed2011-07-01 19:47:50 +0000417 register const Quantum
418 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristy4c08aed2011-07-01 19:47:50 +0000421 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristye076a6e2010-08-15 19:59:43 +0000424 register ssize_t
425 i;
426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
428 Apply clip mask.
429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000434 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000445 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000451 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy4c08aed2011-07-01 19:47:50 +0000453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000454 break;
cristy4c08aed2011-07-01 19:47:50 +0000455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000456 {
cristy4c08aed2011-07-01 19:47:50 +0000457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000463 }
cristyed231572011-07-14 02:18:59 +0000464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000467 }
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000470 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000471 return(MagickFalse);
472 return(MagickTrue);
473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
480+ C l o n e P i x e l C a c h e %
481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
486% ClonePixelCache() clones a pixel cache.
487%
488% The format of the ClonePixelCache() method is:
489%
490% Cache ClonePixelCache(const Cache cache)
491%
492% A description of each parameter follows:
493%
494% o cache: the pixel cache.
495%
496*/
cristya6577ff2011-09-02 19:54:26 +0000497MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000498{
499 CacheInfo
500 *clone_info;
501
502 const CacheInfo
503 *cache_info;
504
cristy9f027d12011-09-21 01:17:17 +0000505 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
516}
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520% %
521% %
522% %
cristy60c44a82009-10-07 00:58:49 +0000523+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000524% %
525% %
526% %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528% ClonePixelCachePixels() clones the source pixel cache to the destination
529% cache.
530%
531% The format of the ClonePixelCachePixels() method is:
532%
533% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534% CacheInfo *source_info,ExceptionInfo *exception)
535%
536% A description of each parameter follows:
537%
538% o cache_info: the pixel cache.
539%
540% o source_info: the source pixel cache.
541%
542% o exception: return any errors or warnings in this structure.
543%
544*/
545
546static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
547{
548 int
549 status;
550
cristy5ee247a2010-02-12 15:42:34 +0000551 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000552 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000553 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000554 {
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
558 }
cristyf84a1932010-01-03 18:00:18 +0000559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000560 return(status == -1 ? MagickFalse : MagickTrue);
561}
562
563static void LimitPixelCacheDescriptors(void)
564{
565 register CacheInfo
566 *p,
567 *q;
568
569 /*
570 Limit # of open file descriptors.
571 */
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
573 return;
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (cache_resources == (SplayTreeInfo *) NULL)
576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return;
579 }
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
583 {
584 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000585 break;
cristy3ed852e2009-09-05 21:47:34 +0000586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 }
588 for (q=p; p != (CacheInfo *) NULL; )
589 {
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000592 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
594 }
595 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000596 {
597 /*
598 Close least recently used cache.
599 */
600 (void) close(q->file);
601 q->file=(-1);
602 }
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604}
605
606static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
608{
609 if (x > y)
610 return(x);
611 return(y);
612}
613
614static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x < y)
618 return(x);
619 return(y);
620}
621
622static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
623 const MapMode mode)
624{
625 int
626 file;
627
628 /*
629 Open pixel cache on disk.
630 */
cristyf84a1932010-01-03 18:00:18 +0000631 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000632 if (cache_info->file != -1)
633 {
cristyf84a1932010-01-03 18:00:18 +0000634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 return(MagickTrue); /* cache already open */
636 }
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
640 else
641 switch (mode)
642 {
643 case ReadMode:
644 {
cristy18c6c272011-09-23 14:40:37 +0000645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 case WriteMode:
649 {
cristy18c6c272011-09-23 14:40:37 +0000650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000652 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case IOMode:
657 default:
658 {
cristy18c6c272011-09-23 14:40:37 +0000659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000660 O_EXCL,S_MODE);
661 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
664 }
665 }
666 if (file == -1)
667 {
cristyf84a1932010-01-03 18:00:18 +0000668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000669 return(MagickFalse);
670 }
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000673 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000674 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000675 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000676 return(MagickTrue);
677}
678
679static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
680 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000681 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000682{
683 register MagickOffsetType
684 i;
685
686 ssize_t
687 count;
688
cristy08a88202010-03-04 19:18:05 +0000689 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000690#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000691 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000692 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000693 {
cristyf84a1932010-01-03 18:00:18 +0000694 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000695 return((MagickOffsetType) -1);
696 }
697#endif
698 count=0;
699 for (i=0; i < (MagickOffsetType) length; i+=count)
700 {
701#if !defined(MAGICKCORE_HAVE_PREAD)
702 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
703 (MagickSizeType) SSIZE_MAX));
704#else
705 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000706 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000707#endif
708 if (count > 0)
709 continue;
710 count=0;
711 if (errno != EINTR)
712 {
713 i=(-1);
714 break;
715 }
716 }
717#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000718 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000719#endif
720 return(i);
721}
722
723static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
724 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000725 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000726{
727 register MagickOffsetType
728 i;
729
730 ssize_t
731 count;
732
cristy08a88202010-03-04 19:18:05 +0000733 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000734#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000735 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000736 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000737 {
cristyf84a1932010-01-03 18:00:18 +0000738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 return((MagickOffsetType) -1);
740 }
741#endif
742 count=0;
743 for (i=0; i < (MagickOffsetType) length; i+=count)
744 {
745#if !defined(MAGICKCORE_HAVE_PWRITE)
746 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
747 (MagickSizeType) SSIZE_MAX));
748#else
749 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000750 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000751#endif
752 if (count > 0)
753 continue;
754 count=0;
755 if (errno != EINTR)
756 {
757 i=(-1);
758 break;
759 }
760 }
761#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000762 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000763#endif
764 return(i);
765}
766
cristy4c08aed2011-07-01 19:47:50 +0000767static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000768 CacheInfo *cache_info,ExceptionInfo *exception)
769{
770 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000771 count;
cristy3ed852e2009-09-05 21:47:34 +0000772
cristy4c08aed2011-07-01 19:47:50 +0000773 register MagickOffsetType
774 i;
cristye076a6e2010-08-15 19:59:43 +0000775
cristybb503372010-05-27 20:51:26 +0000776 size_t
cristy4c08aed2011-07-01 19:47:50 +0000777 length;
cristy3ed852e2009-09-05 21:47:34 +0000778
cristy4c08aed2011-07-01 19:47:50 +0000779 unsigned char
780 *blob;
781
782 /*
783 Clone pixel cache (both caches on disk).
784 */
cristy3ed852e2009-09-05 21:47:34 +0000785 if (cache_info->debug != MagickFalse)
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000787 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000788 sizeof(*blob));
789 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000790 {
cristy4c08aed2011-07-01 19:47:50 +0000791 (void) ThrowMagickException(exception,GetMagickModule(),
792 ResourceLimitError,"MemoryAllocationFailed","`%s'",
793 cache_info->filename);
794 return(MagickFalse);
795 }
cristy3dedf062011-07-02 14:07:40 +0000796 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000797 {
798 blob=(unsigned char *) RelinquishMagickMemory(blob);
799 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
800 cache_info->cache_filename);
801 return(MagickFalse);
802 }
cristy3dedf062011-07-02 14:07:40 +0000803 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000804 {
805 (void) ClosePixelCacheOnDisk(cache_info);
806 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000807 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
808 clone_info->cache_filename);
809 return(MagickFalse);
810 }
cristy4c08aed2011-07-01 19:47:50 +0000811 count=0;
812 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
815 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
816 blob);
817 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000818 {
cristy4c08aed2011-07-01 19:47:50 +0000819 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
820 cache_info->cache_filename);
821 break;
cristy3ed852e2009-09-05 21:47:34 +0000822 }
cristy4c08aed2011-07-01 19:47:50 +0000823 length=(size_t) count;
824 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
825 if ((MagickSizeType) count != length)
826 {
827 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
828 clone_info->cache_filename);
829 break;
830 }
831 }
832 (void) ClosePixelCacheOnDisk(clone_info);
833 (void) ClosePixelCacheOnDisk(cache_info);
834 blob=(unsigned char *) RelinquishMagickMemory(blob);
835 if (i < (MagickOffsetType) cache_info->length)
836 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000837 return(MagickTrue);
838}
839
cristy4c08aed2011-07-01 19:47:50 +0000840static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000841 CacheInfo *cache_info,ExceptionInfo *exception)
842{
843 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000844 count;
cristy3ed852e2009-09-05 21:47:34 +0000845
cristy4c08aed2011-07-01 19:47:50 +0000846 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000847 {
cristy3ed852e2009-09-05 21:47:34 +0000848 /*
cristy4c08aed2011-07-01 19:47:50 +0000849 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000850 */
cristy4c08aed2011-07-01 19:47:50 +0000851 if (cache_info->debug != MagickFalse)
852 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
853 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
854 cache_info->length);
855 return(MagickTrue);
856 }
857 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
858 {
859 /*
860 Clone pixel cache (one cache on disk, one in memory).
861 */
862 if (cache_info->debug != MagickFalse)
863 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
864 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
cristy4c08aed2011-07-01 19:47:50 +0000866 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000867 cache_info->cache_filename);
868 return(MagickFalse);
869 }
cristy4c08aed2011-07-01 19:47:50 +0000870 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
871 cache_info->length,(unsigned char *) clone_info->pixels);
872 (void) ClosePixelCacheOnDisk(cache_info);
873 if ((MagickSizeType) count != cache_info->length)
874 {
875 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
876 cache_info->cache_filename);
877 return(MagickFalse);
878 }
879 return(MagickTrue);
880 }
881 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
882 {
883 /*
884 Clone pixel cache (one cache on disk, one in memory).
885 */
886 if (clone_info->debug != MagickFalse)
887 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
888 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
889 {
890 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
891 clone_info->cache_filename);
892 return(MagickFalse);
893 }
894 count=WritePixelCacheRegion(clone_info,clone_info->offset,
895 clone_info->length,(unsigned char *) cache_info->pixels);
896 (void) ClosePixelCacheOnDisk(clone_info);
897 if ((MagickSizeType) count != clone_info->length)
898 {
899 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
900 clone_info->cache_filename);
901 return(MagickFalse);
902 }
903 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000904 }
905 /*
cristy4c08aed2011-07-01 19:47:50 +0000906 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000907 */
cristy4c08aed2011-07-01 19:47:50 +0000908 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000909}
910
cristy4c08aed2011-07-01 19:47:50 +0000911static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000912 CacheInfo *cache_info,ExceptionInfo *exception)
913{
cristy4c08aed2011-07-01 19:47:50 +0000914 MagickBooleanType
915 status;
cristy3ed852e2009-09-05 21:47:34 +0000916
cristy4c08aed2011-07-01 19:47:50 +0000917 MagickOffsetType
918 cache_offset,
919 clone_offset,
920 count;
921
922 register ssize_t
923 x;
924
925 size_t
cristy3ed852e2009-09-05 21:47:34 +0000926 length;
927
cristy4c08aed2011-07-01 19:47:50 +0000928 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000929 y;
930
cristy4c08aed2011-07-01 19:47:50 +0000931 unsigned char
932 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000933
cristy4c08aed2011-07-01 19:47:50 +0000934 /*
935 Clone pixel cache (unoptimized).
936 */
cristy3ed852e2009-09-05 21:47:34 +0000937 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000938 {
cristy4c08aed2011-07-01 19:47:50 +0000939 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
940 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
941 else
942 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
943 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
944 else
945 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
947 else
948 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
949 }
cristyed231572011-07-14 02:18:59 +0000950 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
951 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000952 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000953 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000954 if (blob == (unsigned char *) NULL)
955 {
956 (void) ThrowMagickException(exception,GetMagickModule(),
957 ResourceLimitError,"MemoryAllocationFailed","`%s'",
958 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000959 return(MagickFalse);
960 }
cristy4c08aed2011-07-01 19:47:50 +0000961 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
962 cache_offset=0;
963 clone_offset=0;
964 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000965 {
cristy4c08aed2011-07-01 19:47:50 +0000966 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000967 {
cristy4c08aed2011-07-01 19:47:50 +0000968 blob=(unsigned char *) RelinquishMagickMemory(blob);
969 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000970 cache_info->cache_filename);
971 return(MagickFalse);
972 }
cristy4c08aed2011-07-01 19:47:50 +0000973 cache_offset=cache_info->offset;
974 }
cristy4d9c1922011-12-31 18:37:34 +0000975 if ((cache_info->type != MemoryCache) && (clone_info->type != MemoryCache) &&
976 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
977 {
978 /*
979 Inplace cloning not reliable.
980 */
981 (void) ClosePixelCacheOnDisk(clone_info);
982 if (cache_info->type == MapCache)
983 {
984 clone_info->pixels=(Quantum *) UnmapBlob(clone_info->pixels,(size_t)
985 clone_info->length);
986 RelinquishMagickResource(MapResource,clone_info->length);
987 }
988 *clone_info->cache_filename='\0';
989 clone_info->type=DiskCache;
990 }
cristy4c08aed2011-07-01 19:47:50 +0000991 if (clone_info->type == DiskCache)
992 {
cristy3dedf062011-07-02 14:07:40 +0000993 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000994 {
cristy4c08aed2011-07-01 19:47:50 +0000995 if (cache_info->type == DiskCache)
996 (void) ClosePixelCacheOnDisk(cache_info);
997 blob=(unsigned char *) RelinquishMagickMemory(blob);
998 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
999 clone_info->cache_filename);
1000 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001001 }
cristy4c08aed2011-07-01 19:47:50 +00001002 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +00001003 }
1004 /*
cristy4c08aed2011-07-01 19:47:50 +00001005 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001006 */
cristy4c08aed2011-07-01 19:47:50 +00001007 status=MagickTrue;
1008 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001009 {
cristy4c08aed2011-07-01 19:47:50 +00001010 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001011 {
cristy9e0719b2011-12-29 03:45:45 +00001012 register ssize_t
1013 i;
1014
cristy3ed852e2009-09-05 21:47:34 +00001015 /*
cristy4c08aed2011-07-01 19:47:50 +00001016 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001017 */
cristyed231572011-07-14 02:18:59 +00001018 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001019 if (cache_info->type != DiskCache)
1020 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1021 length);
cristy3ed852e2009-09-05 21:47:34 +00001022 else
1023 {
cristy4c08aed2011-07-01 19:47:50 +00001024 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1025 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001026 {
cristy4c08aed2011-07-01 19:47:50 +00001027 status=MagickFalse;
1028 break;
cristy3ed852e2009-09-05 21:47:34 +00001029 }
1030 }
cristy4c08aed2011-07-01 19:47:50 +00001031 cache_offset+=length;
1032 if ((y < (ssize_t) clone_info->rows) &&
1033 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001034 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001035 {
cristy9e0719b2011-12-29 03:45:45 +00001036 PixelChannel
1037 channel;
1038
1039 PixelTrait
1040 traits;
1041
1042 ssize_t
1043 offset;
1044
cristy4c08aed2011-07-01 19:47:50 +00001045 /*
cristy3b8fe922011-12-29 18:56:23 +00001046 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001047 */
cristy9e0719b2011-12-29 03:45:45 +00001048 channel=clone_info->channel_map[i].channel;
1049 traits=cache_info->channel_map[channel].traits;
1050 if (traits == UndefinedPixelTrait)
1051 {
cristy0f4425e2011-12-31 20:33:02 +00001052 clone_offset+=sizeof(Quantum);
1053 continue;
cristy9e0719b2011-12-29 03:45:45 +00001054 }
cristy0f4425e2011-12-31 20:33:02 +00001055 offset=cache_info->channel_map[channel].offset;
1056 if (clone_info->type != DiskCache)
1057 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1058 blob+offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +00001059 else
1060 {
cristy0f4425e2011-12-31 20:33:02 +00001061 count=WritePixelCacheRegion(clone_info,clone_offset,
1062 sizeof(Quantum),blob+offset*sizeof(Quantum));
1063 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +00001064 {
cristy0f4425e2011-12-31 20:33:02 +00001065 status=MagickFalse;
1066 break;
cristy4c08aed2011-07-01 19:47:50 +00001067 }
1068 }
cristy9e0719b2011-12-29 03:45:45 +00001069 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001070 }
1071 }
cristyed231572011-07-14 02:18:59 +00001072 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001073 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1074 for ( ; x < (ssize_t) clone_info->columns; x++)
1075 {
1076 /*
cristy9e0719b2011-12-29 03:45:45 +00001077 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001078 */
1079 if (clone_info->type != DiskCache)
1080 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1081 length);
1082 else
1083 {
1084 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1085 if ((MagickSizeType) count != length)
1086 {
1087 status=MagickFalse;
1088 break;
1089 }
1090 }
1091 clone_offset+=length;
1092 }
1093 }
cristyed231572011-07-14 02:18:59 +00001094 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001095 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1096 for ( ; y < (ssize_t) clone_info->rows; y++)
1097 {
1098 /*
cristy9e0719b2011-12-29 03:45:45 +00001099 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001100 */
1101 for (x=0; x < (ssize_t) clone_info->columns; x++)
1102 {
1103 if (clone_info->type != DiskCache)
1104 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1105 length);
1106 else
1107 {
1108 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1109 if ((MagickSizeType) count != length)
1110 {
1111 status=MagickFalse;
1112 break;
1113 }
1114 }
1115 clone_offset+=length;
1116 }
1117 }
cristy9e0719b2011-12-29 03:45:45 +00001118 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001119 (clone_info->metacontent_extent != 0))
1120 {
1121 /*
1122 Clone metacontent.
1123 */
1124 for (y=0; y < (ssize_t) cache_info->rows; y++)
1125 {
1126 for (x=0; x < (ssize_t) cache_info->columns; x++)
1127 {
1128 /*
1129 Read a set of metacontent.
1130 */
1131 length=cache_info->metacontent_extent;
1132 if (cache_info->type != DiskCache)
1133 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1134 cache_offset,length);
1135 else
1136 {
1137 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1138 if ((MagickSizeType) count != length)
1139 {
1140 status=MagickFalse;
1141 break;
1142 }
1143 }
1144 cache_offset+=length;
1145 if ((y < (ssize_t) clone_info->rows) &&
1146 (x < (ssize_t) clone_info->columns))
1147 {
1148 /*
1149 Write a set of metacontent.
1150 */
1151 length=clone_info->metacontent_extent;
1152 if (clone_info->type != DiskCache)
1153 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1154 blob,length);
1155 else
1156 {
1157 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1158 blob);
1159 if ((MagickSizeType) count != length)
1160 {
1161 status=MagickFalse;
1162 break;
1163 }
1164 }
1165 clone_offset+=length;
1166 }
1167 }
1168 length=clone_info->metacontent_extent;
1169 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1170 for ( ; x < (ssize_t) clone_info->columns; x++)
1171 {
1172 /*
cristy9e0719b2011-12-29 03:45:45 +00001173 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001174 */
1175 if (clone_info->type != DiskCache)
1176 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1177 blob,length);
1178 else
1179 {
cristy208b1002011-08-07 18:51:50 +00001180 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001181 if ((MagickSizeType) count != length)
1182 {
1183 status=MagickFalse;
1184 break;
1185 }
1186 }
1187 clone_offset+=length;
1188 }
1189 }
1190 length=clone_info->metacontent_extent;
1191 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1192 for ( ; y < (ssize_t) clone_info->rows; y++)
1193 {
1194 /*
cristy9e0719b2011-12-29 03:45:45 +00001195 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001196 */
1197 for (x=0; x < (ssize_t) clone_info->columns; x++)
1198 {
1199 if (clone_info->type != DiskCache)
1200 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1201 blob,length);
1202 else
1203 {
1204 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1205 if ((MagickSizeType) count != length)
1206 {
1207 status=MagickFalse;
1208 break;
1209 }
1210 }
1211 clone_offset+=length;
1212 }
1213 }
1214 }
1215 if (clone_info->type == DiskCache)
1216 (void) ClosePixelCacheOnDisk(clone_info);
1217 if (cache_info->type == DiskCache)
1218 (void) ClosePixelCacheOnDisk(cache_info);
1219 blob=(unsigned char *) RelinquishMagickMemory(blob);
1220 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001221}
1222
1223static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1224 CacheInfo *cache_info,ExceptionInfo *exception)
1225{
cristy3dfccb22011-12-28 21:47:20 +00001226 PixelChannelMap
1227 *p,
1228 *q;
1229
cristy5a7fbfb2010-11-06 16:10:59 +00001230 if (cache_info->type == PingCache)
1231 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001232 p=cache_info->channel_map;
1233 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001234 if ((cache_info->columns == clone_info->columns) &&
1235 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001236 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001237 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001238 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1239 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1240 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001241}
1242
1243/*
1244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1245% %
1246% %
1247% %
1248+ C l o n e P i x e l C a c h e M e t h o d s %
1249% %
1250% %
1251% %
1252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1253%
1254% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1255% another.
1256%
1257% The format of the ClonePixelCacheMethods() method is:
1258%
1259% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1260%
1261% A description of each parameter follows:
1262%
1263% o clone: Specifies a pointer to a Cache structure.
1264%
1265% o cache: the pixel cache.
1266%
1267*/
cristya6577ff2011-09-02 19:54:26 +00001268MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001269{
1270 CacheInfo
1271 *cache_info,
1272 *source_info;
1273
1274 assert(clone != (Cache) NULL);
1275 source_info=(CacheInfo *) clone;
1276 assert(source_info->signature == MagickSignature);
1277 if (source_info->debug != MagickFalse)
1278 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1279 source_info->filename);
1280 assert(cache != (Cache) NULL);
1281 cache_info=(CacheInfo *) cache;
1282 assert(cache_info->signature == MagickSignature);
1283 source_info->methods=cache_info->methods;
1284}
1285
1286/*
1287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288% %
1289% %
1290% %
1291+ D e s t r o y I m a g e P i x e l C a c h e %
1292% %
1293% %
1294% %
1295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1296%
1297% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1298%
1299% The format of the DestroyImagePixelCache() method is:
1300%
1301% void DestroyImagePixelCache(Image *image)
1302%
1303% A description of each parameter follows:
1304%
1305% o image: the image.
1306%
1307*/
1308static void DestroyImagePixelCache(Image *image)
1309{
1310 assert(image != (Image *) NULL);
1311 assert(image->signature == MagickSignature);
1312 if (image->debug != MagickFalse)
1313 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1314 if (image->cache == (void *) NULL)
1315 return;
1316 image->cache=DestroyPixelCache(image->cache);
1317}
1318
1319/*
1320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1321% %
1322% %
1323% %
1324+ D e s t r o y I m a g e P i x e l s %
1325% %
1326% %
1327% %
1328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1329%
1330% DestroyImagePixels() deallocates memory associated with the pixel cache.
1331%
1332% The format of the DestroyImagePixels() method is:
1333%
1334% void DestroyImagePixels(Image *image)
1335%
1336% A description of each parameter follows:
1337%
1338% o image: the image.
1339%
1340*/
1341MagickExport void DestroyImagePixels(Image *image)
1342{
1343 CacheInfo
1344 *cache_info;
1345
1346 assert(image != (const Image *) NULL);
1347 assert(image->signature == MagickSignature);
1348 if (image->debug != MagickFalse)
1349 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1350 assert(image->cache != (Cache) NULL);
1351 cache_info=(CacheInfo *) image->cache;
1352 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001353 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1354 {
1355 cache_info->methods.destroy_pixel_handler(image);
1356 return;
1357 }
cristy2036f5c2010-09-19 21:18:17 +00001358 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001359}
1360
1361/*
1362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363% %
1364% %
1365% %
1366+ D e s t r o y P i x e l C a c h e %
1367% %
1368% %
1369% %
1370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371%
1372% DestroyPixelCache() deallocates memory associated with the pixel cache.
1373%
1374% The format of the DestroyPixelCache() method is:
1375%
1376% Cache DestroyPixelCache(Cache cache)
1377%
1378% A description of each parameter follows:
1379%
1380% o cache: the pixel cache.
1381%
1382*/
1383
1384static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1385{
1386 switch (cache_info->type)
1387 {
1388 case MemoryCache:
1389 {
1390 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001391 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001392 cache_info->pixels);
1393 else
cristy4c08aed2011-07-01 19:47:50 +00001394 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001395 (size_t) cache_info->length);
1396 RelinquishMagickResource(MemoryResource,cache_info->length);
1397 break;
1398 }
1399 case MapCache:
1400 {
cristy4c08aed2011-07-01 19:47:50 +00001401 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001402 cache_info->length);
1403 RelinquishMagickResource(MapResource,cache_info->length);
1404 }
1405 case DiskCache:
1406 {
1407 if (cache_info->file != -1)
1408 (void) ClosePixelCacheOnDisk(cache_info);
1409 RelinquishMagickResource(DiskResource,cache_info->length);
1410 break;
1411 }
1412 default:
1413 break;
1414 }
1415 cache_info->type=UndefinedCache;
1416 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001417 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001418}
1419
cristya6577ff2011-09-02 19:54:26 +00001420MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001421{
1422 CacheInfo
1423 *cache_info;
1424
cristy3ed852e2009-09-05 21:47:34 +00001425 assert(cache != (Cache) NULL);
1426 cache_info=(CacheInfo *) cache;
1427 assert(cache_info->signature == MagickSignature);
1428 if (cache_info->debug != MagickFalse)
1429 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1430 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001431 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001432 cache_info->reference_count--;
1433 if (cache_info->reference_count != 0)
1434 {
cristyf84a1932010-01-03 18:00:18 +00001435 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001436 return((Cache) NULL);
1437 }
cristyf84a1932010-01-03 18:00:18 +00001438 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001439 if (cache_resources != (SplayTreeInfo *) NULL)
1440 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001441 if (cache_info->debug != MagickFalse)
1442 {
1443 char
1444 message[MaxTextExtent];
1445
cristyb51dff52011-05-19 16:55:47 +00001446 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001447 cache_info->filename);
1448 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1449 }
cristyc2e1bdd2009-09-10 23:43:34 +00001450 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1451 (cache_info->type != DiskCache)))
1452 RelinquishPixelCachePixels(cache_info);
1453 else
1454 {
1455 RelinquishPixelCachePixels(cache_info);
1456 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1457 }
cristy3ed852e2009-09-05 21:47:34 +00001458 *cache_info->cache_filename='\0';
1459 if (cache_info->nexus_info != (NexusInfo **) NULL)
1460 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1461 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001462 if (cache_info->random_info != (RandomInfo *) NULL)
1463 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001464 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1465 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1466 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1467 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001468 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001469 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001470 cache=(Cache) NULL;
1471 return(cache);
1472}
1473
1474/*
1475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1476% %
1477% %
1478% %
1479+ D e s t r o y P i x e l C a c h e N e x u s %
1480% %
1481% %
1482% %
1483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484%
1485% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1486%
1487% The format of the DestroyPixelCacheNexus() method is:
1488%
1489% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001490% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001491%
1492% A description of each parameter follows:
1493%
1494% o nexus_info: the nexus to destroy.
1495%
1496% o number_threads: the number of nexus threads.
1497%
1498*/
1499
1500static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1501{
1502 if (nexus_info->mapped == MagickFalse)
1503 (void) RelinquishMagickMemory(nexus_info->cache);
1504 else
1505 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001506 nexus_info->cache=(Quantum *) NULL;
1507 nexus_info->pixels=(Quantum *) NULL;
1508 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001509 nexus_info->length=0;
1510 nexus_info->mapped=MagickFalse;
1511}
1512
cristya6577ff2011-09-02 19:54:26 +00001513MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001514 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001515{
cristybb503372010-05-27 20:51:26 +00001516 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001517 i;
1518
1519 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001520 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001521 {
cristy4c08aed2011-07-01 19:47:50 +00001522 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001523 RelinquishCacheNexusPixels(nexus_info[i]);
1524 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001525 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001526 }
cristyb41ee102010-10-04 16:46:15 +00001527 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001528 return(nexus_info);
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
cristy4c08aed2011-07-01 19:47:50 +00001536% 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 +00001537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
cristy4c08aed2011-07-01 19:47:50 +00001542% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1543% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1544% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001545%
cristy4c08aed2011-07-01 19:47:50 +00001546% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001547%
cristy4c08aed2011-07-01 19:47:50 +00001548% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001549%
1550% A description of each parameter follows:
1551%
1552% o image: the image.
1553%
1554*/
cristy4c08aed2011-07-01 19:47:50 +00001555MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001556{
1557 CacheInfo
1558 *cache_info;
1559
cristy5c9e6f22010-09-17 17:31:01 +00001560 const int
1561 id = GetOpenMPThreadId();
1562
cristy4c08aed2011-07-01 19:47:50 +00001563 void
1564 *metacontent;
1565
cristye7cc7cf2010-09-21 13:26:47 +00001566 assert(image != (const Image *) NULL);
1567 assert(image->signature == MagickSignature);
1568 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001569 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001570 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001571 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1572 (GetAuthenticMetacontentFromHandler) NULL)
1573 {
1574 metacontent=cache_info->methods.
1575 get_authentic_metacontent_from_handler(image);
1576 return(metacontent);
1577 }
cristy6ebe97c2010-07-03 01:17:28 +00001578 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001579 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1580 cache_info->nexus_info[id]);
1581 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001582}
1583
1584/*
1585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586% %
1587% %
1588% %
cristy4c08aed2011-07-01 19:47:50 +00001589+ 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 +00001590% %
1591% %
1592% %
1593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594%
cristy4c08aed2011-07-01 19:47:50 +00001595% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1596% with the last call to QueueAuthenticPixelsCache() or
1597% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001598%
cristy4c08aed2011-07-01 19:47:50 +00001599% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001600%
cristy4c08aed2011-07-01 19:47:50 +00001601% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001602%
1603% A description of each parameter follows:
1604%
1605% o image: the image.
1606%
1607*/
cristy4c08aed2011-07-01 19:47:50 +00001608static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001609{
1610 CacheInfo
1611 *cache_info;
1612
cristy2036f5c2010-09-19 21:18:17 +00001613 const int
1614 id = GetOpenMPThreadId();
1615
cristy4c08aed2011-07-01 19:47:50 +00001616 void
1617 *metacontent;
1618
cristy3ed852e2009-09-05 21:47:34 +00001619 assert(image != (const Image *) NULL);
1620 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001621 assert(image->cache != (Cache) NULL);
1622 cache_info=(CacheInfo *) image->cache;
1623 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001624 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001625 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1626 cache_info->nexus_info[id]);
1627 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
1635+ 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 %
1636% %
1637% %
1638% %
1639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640%
1641% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1642% disk pixel cache as defined by the geometry parameters. A pointer to the
1643% pixels is returned if the pixels are transferred, otherwise a NULL is
1644% returned.
1645%
1646% The format of the GetAuthenticPixelCacheNexus() method is:
1647%
cristy4c08aed2011-07-01 19:47:50 +00001648% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001649% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001650% NexusInfo *nexus_info,ExceptionInfo *exception)
1651%
1652% A description of each parameter follows:
1653%
1654% o image: the image.
1655%
1656% o x,y,columns,rows: These values define the perimeter of a region of
1657% pixels.
1658%
1659% o nexus_info: the cache nexus to return.
1660%
1661% o exception: return any errors or warnings in this structure.
1662%
1663*/
1664
cristy4c08aed2011-07-01 19:47:50 +00001665static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001666 NexusInfo *nexus_info)
1667{
cristy4c08aed2011-07-01 19:47:50 +00001668 MagickBooleanType
1669 status;
1670
cristy3ed852e2009-09-05 21:47:34 +00001671 MagickOffsetType
1672 offset;
1673
cristy73724512010-04-12 14:43:14 +00001674 if (cache_info->type == PingCache)
1675 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001676 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1677 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001678 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001679 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001680 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001681}
1682
cristya6577ff2011-09-02 19:54:26 +00001683MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001684 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001685 NexusInfo *nexus_info,ExceptionInfo *exception)
1686{
1687 CacheInfo
1688 *cache_info;
1689
cristy4c08aed2011-07-01 19:47:50 +00001690 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001691 *q;
cristy3ed852e2009-09-05 21:47:34 +00001692
1693 /*
1694 Transfer pixels from the cache.
1695 */
1696 assert(image != (Image *) NULL);
1697 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001698 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001699 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001700 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001701 cache_info=(CacheInfo *) image->cache;
1702 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001703 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001704 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001705 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001706 return((Quantum *) NULL);
1707 if (cache_info->metacontent_extent != 0)
1708 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1709 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001710 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001711}
1712
1713/*
1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715% %
1716% %
1717% %
1718+ 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 %
1719% %
1720% %
1721% %
1722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1723%
1724% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1725% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1726%
1727% The format of the GetAuthenticPixelsFromCache() method is:
1728%
cristy4c08aed2011-07-01 19:47:50 +00001729% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001730%
1731% A description of each parameter follows:
1732%
1733% o image: the image.
1734%
1735*/
cristy4c08aed2011-07-01 19:47:50 +00001736static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001737{
1738 CacheInfo
1739 *cache_info;
1740
cristy5c9e6f22010-09-17 17:31:01 +00001741 const int
1742 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001743
cristye7cc7cf2010-09-21 13:26:47 +00001744 assert(image != (const Image *) NULL);
1745 assert(image->signature == MagickSignature);
1746 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001747 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001748 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001749 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001750 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001751}
1752
1753/*
1754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755% %
1756% %
1757% %
1758% G e t A u t h e n t i c P i x e l Q u e u e %
1759% %
1760% %
1761% %
1762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763%
cristy4c08aed2011-07-01 19:47:50 +00001764% GetAuthenticPixelQueue() returns the authentic pixels associated
1765% corresponding with the last call to QueueAuthenticPixels() or
1766% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001767%
1768% The format of the GetAuthenticPixelQueue() method is:
1769%
cristy4c08aed2011-07-01 19:47:50 +00001770% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001771%
1772% A description of each parameter follows:
1773%
1774% o image: the image.
1775%
1776*/
cristy4c08aed2011-07-01 19:47:50 +00001777MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001778{
1779 CacheInfo
1780 *cache_info;
1781
cristy2036f5c2010-09-19 21:18:17 +00001782 const int
1783 id = GetOpenMPThreadId();
1784
cristy3ed852e2009-09-05 21:47:34 +00001785 assert(image != (const Image *) NULL);
1786 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001787 assert(image->cache != (Cache) NULL);
1788 cache_info=(CacheInfo *) image->cache;
1789 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001790 if (cache_info->methods.get_authentic_pixels_from_handler !=
1791 (GetAuthenticPixelsFromHandler) NULL)
1792 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001793 assert(id < (int) cache_info->number_threads);
1794 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001795}
1796
1797/*
1798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1799% %
1800% %
1801% %
1802% G e t A u t h e n t i c P i x e l s %
1803% %
1804% %
cristy4c08aed2011-07-01 19:47:50 +00001805% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001806%
1807% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001808% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001809% representing the region is returned, otherwise NULL is returned.
1810%
1811% The returned pointer may point to a temporary working copy of the pixels
1812% or it may point to the original pixels in memory. Performance is maximized
1813% if the selected region is part of one row, or one or more full rows, since
1814% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001815% if the image is in memory, or in a memory-mapped file. The returned pointer
1816% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001817%
1818% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001819% Quantum. If the image has corresponding metacontent,call
1820% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1821% meta-content corresponding to the region. Once the Quantum array has
1822% been updated, the changes must be saved back to the underlying image using
1823% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001824%
1825% The format of the GetAuthenticPixels() method is:
1826%
cristy4c08aed2011-07-01 19:47:50 +00001827% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001828% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001829% ExceptionInfo *exception)
1830%
1831% A description of each parameter follows:
1832%
1833% o image: the image.
1834%
1835% o x,y,columns,rows: These values define the perimeter of a region of
1836% pixels.
1837%
1838% o exception: return any errors or warnings in this structure.
1839%
1840*/
cristy4c08aed2011-07-01 19:47:50 +00001841MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001842 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001843 ExceptionInfo *exception)
1844{
1845 CacheInfo
1846 *cache_info;
1847
cristy2036f5c2010-09-19 21:18:17 +00001848 const int
1849 id = GetOpenMPThreadId();
1850
cristy4c08aed2011-07-01 19:47:50 +00001851 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001852 *q;
cristy4c08aed2011-07-01 19:47:50 +00001853
cristy3ed852e2009-09-05 21:47:34 +00001854 assert(image != (Image *) NULL);
1855 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001856 assert(image->cache != (Cache) NULL);
1857 cache_info=(CacheInfo *) image->cache;
1858 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001859 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001860 (GetAuthenticPixelsHandler) NULL)
1861 {
cristyacd2ed22011-08-30 01:44:23 +00001862 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1863 exception);
1864 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001865 }
cristy2036f5c2010-09-19 21:18:17 +00001866 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001867 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001868 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001869 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001870}
1871
1872/*
1873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1874% %
1875% %
1876% %
1877+ G e t A u t h e n t i c P i x e l s C a c h e %
1878% %
1879% %
1880% %
1881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1882%
1883% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1884% as defined by the geometry parameters. A pointer to the pixels is returned
1885% if the pixels are transferred, otherwise a NULL is returned.
1886%
1887% The format of the GetAuthenticPixelsCache() method is:
1888%
cristy4c08aed2011-07-01 19:47:50 +00001889% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001890% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001891% ExceptionInfo *exception)
1892%
1893% A description of each parameter follows:
1894%
1895% o image: the image.
1896%
1897% o x,y,columns,rows: These values define the perimeter of a region of
1898% pixels.
1899%
1900% o exception: return any errors or warnings in this structure.
1901%
1902*/
cristy4c08aed2011-07-01 19:47:50 +00001903static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001904 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001905 ExceptionInfo *exception)
1906{
1907 CacheInfo
1908 *cache_info;
1909
cristy5c9e6f22010-09-17 17:31:01 +00001910 const int
1911 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001912
cristy4c08aed2011-07-01 19:47:50 +00001913 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001914 *q;
cristy4c08aed2011-07-01 19:47:50 +00001915
cristye7cc7cf2010-09-21 13:26:47 +00001916 assert(image != (const Image *) NULL);
1917 assert(image->signature == MagickSignature);
1918 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001919 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001920 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001921 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001922 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001923 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001924 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001925 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001926 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001927}
1928
1929/*
1930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1931% %
1932% %
1933% %
1934+ G e t I m a g e E x t e n t %
1935% %
1936% %
1937% %
1938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1939%
cristy4c08aed2011-07-01 19:47:50 +00001940% GetImageExtent() returns the extent of the pixels associated corresponding
1941% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001942%
1943% The format of the GetImageExtent() method is:
1944%
1945% MagickSizeType GetImageExtent(const Image *image)
1946%
1947% A description of each parameter follows:
1948%
1949% o image: the image.
1950%
1951*/
1952MagickExport MagickSizeType GetImageExtent(const Image *image)
1953{
1954 CacheInfo
1955 *cache_info;
1956
cristy5c9e6f22010-09-17 17:31:01 +00001957 const int
1958 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001959
cristy3ed852e2009-09-05 21:47:34 +00001960 assert(image != (Image *) NULL);
1961 assert(image->signature == MagickSignature);
1962 if (image->debug != MagickFalse)
1963 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1964 assert(image->cache != (Cache) NULL);
1965 cache_info=(CacheInfo *) image->cache;
1966 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001967 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001968 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001969}
1970
1971/*
1972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1973% %
1974% %
1975% %
1976+ G e t I m a g e P i x e l C a c h e %
1977% %
1978% %
1979% %
1980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981%
1982% GetImagePixelCache() ensures that there is only a single reference to the
1983% pixel cache to be modified, updating the provided cache pointer to point to
1984% a clone of the original pixel cache if necessary.
1985%
1986% The format of the GetImagePixelCache method is:
1987%
1988% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1989% ExceptionInfo *exception)
1990%
1991% A description of each parameter follows:
1992%
1993% o image: the image.
1994%
1995% o clone: any value other than MagickFalse clones the cache pixels.
1996%
1997% o exception: return any errors or warnings in this structure.
1998%
1999*/
cristyaf894d72011-08-06 23:03:10 +00002000
cristy3ed852e2009-09-05 21:47:34 +00002001static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2002{
2003 CacheInfo
2004 *cache_info;
2005
cristy9e0719b2011-12-29 03:45:45 +00002006 PixelChannelMap
2007 *p,
2008 *q;
2009
cristy3ed852e2009-09-05 21:47:34 +00002010 /*
2011 Does the image match the pixel cache morphology?
2012 */
2013 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00002014 p=image->channel_map;
2015 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00002016 if ((image->storage_class != cache_info->storage_class) ||
2017 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002018 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002019 (image->columns != cache_info->columns) ||
2020 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002021 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002022 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002023 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002024 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2025 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2026 return(MagickFalse);
2027 return(MagickTrue);
2028}
2029
cristycd01fae2011-08-06 23:52:42 +00002030static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2031 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002032{
2033 CacheInfo
2034 *cache_info;
2035
cristy3ed852e2009-09-05 21:47:34 +00002036 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002037 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002038 status;
2039
cristy50a10922010-02-15 18:35:25 +00002040 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002041 cpu_throttle = 0,
2042 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002043 time_limit = 0;
2044
cristy1ea34962010-07-01 19:49:21 +00002045 static time_t
cristy208b1002011-08-07 18:51:50 +00002046 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002047
cristyc4f9f132010-03-04 18:50:01 +00002048 status=MagickTrue;
2049 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002050 if (cpu_throttle == 0)
2051 {
2052 char
2053 *limit;
2054
2055 /*
2056 Set CPU throttle in milleseconds.
2057 */
2058 cpu_throttle=MagickResourceInfinity;
2059 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2060 if (limit == (char *) NULL)
2061 limit=GetPolicyValue("throttle");
2062 if (limit != (char *) NULL)
2063 {
2064 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2065 limit=DestroyString(limit);
2066 }
2067 }
2068 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2069 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002070 if (time_limit == 0)
2071 {
cristy6ebe97c2010-07-03 01:17:28 +00002072 /*
2073 Set the exire time in seconds.
2074 */
cristy1ea34962010-07-01 19:49:21 +00002075 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002076 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002077 }
2078 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002079 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002080 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002081 assert(image->cache != (Cache) NULL);
2082 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002083 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002084 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002085 {
cristyceb55ee2010-11-06 16:05:49 +00002086 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002087 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002088 {
cristyceb55ee2010-11-06 16:05:49 +00002089 Image
2090 clone_image;
2091
2092 CacheInfo
2093 *clone_info;
2094
2095 /*
2096 Clone pixel cache.
2097 */
2098 clone_image=(*image);
2099 clone_image.semaphore=AllocateSemaphoreInfo();
2100 clone_image.reference_count=1;
2101 clone_image.cache=ClonePixelCache(cache_info);
2102 clone_info=(CacheInfo *) clone_image.cache;
2103 status=OpenPixelCache(&clone_image,IOMode,exception);
2104 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002105 {
cristy5a7fbfb2010-11-06 16:10:59 +00002106 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002107 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002108 if (status != MagickFalse)
2109 {
cristy979bf772011-08-08 00:04:15 +00002110 if (cache_info->mode == ReadMode)
2111 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002112 destroy=MagickTrue;
2113 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002114 }
2115 }
cristyceb55ee2010-11-06 16:05:49 +00002116 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002117 }
cristyceb55ee2010-11-06 16:05:49 +00002118 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002119 }
cristy4320e0e2009-09-10 15:00:08 +00002120 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002121 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002122 if (status != MagickFalse)
2123 {
2124 /*
2125 Ensure the image matches the pixel cache morphology.
2126 */
2127 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002128 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002129 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2130 status=OpenPixelCache(image,IOMode,exception);
2131 }
cristyf84a1932010-01-03 18:00:18 +00002132 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002133 if (status == MagickFalse)
2134 return((Cache) NULL);
2135 return(image->cache);
2136}
2137
2138/*
2139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2140% %
2141% %
2142% %
2143% G e t O n e A u t h e n t i c P i x e l %
2144% %
2145% %
2146% %
2147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2148%
2149% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2150% location. The image background color is returned if an error occurs.
2151%
2152% The format of the GetOneAuthenticPixel() method is:
2153%
cristybb503372010-05-27 20:51:26 +00002154% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002155% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002156%
2157% A description of each parameter follows:
2158%
2159% o image: the image.
2160%
2161% o x,y: These values define the location of the pixel to return.
2162%
2163% o pixel: return a pixel at the specified (x,y) location.
2164%
2165% o exception: return any errors or warnings in this structure.
2166%
2167*/
cristyacbbb7c2010-06-30 18:56:48 +00002168MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002169 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002170{
2171 CacheInfo
2172 *cache_info;
2173
cristy4c08aed2011-07-01 19:47:50 +00002174 register Quantum
2175 *q;
cristy2036f5c2010-09-19 21:18:17 +00002176
cristy2ed42f62011-10-02 19:49:57 +00002177 register ssize_t
2178 i;
2179
cristy3ed852e2009-09-05 21:47:34 +00002180 assert(image != (Image *) NULL);
2181 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002182 assert(image->cache != (Cache) NULL);
2183 cache_info=(CacheInfo *) image->cache;
2184 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002185 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002186 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2187 (GetOneAuthenticPixelFromHandler) NULL)
2188 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2189 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002190 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2191 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002192 {
cristy9e0719b2011-12-29 03:45:45 +00002193 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2194 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2195 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2196 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2197 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002198 return(MagickFalse);
2199 }
2200 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2201 {
2202 PixelChannel
2203 channel;
2204
cristye2a912b2011-12-05 20:02:07 +00002205 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002206 pixel[channel]=q[i];
2207 }
cristy2036f5c2010-09-19 21:18:17 +00002208 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002209}
2210
2211/*
2212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2213% %
2214% %
2215% %
2216+ 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 %
2217% %
2218% %
2219% %
2220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2221%
2222% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2223% location. The image background color is returned if an error occurs.
2224%
2225% The format of the GetOneAuthenticPixelFromCache() method is:
2226%
2227% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002228% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002229% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002230%
2231% A description of each parameter follows:
2232%
2233% o image: the image.
2234%
2235% o x,y: These values define the location of the pixel to return.
2236%
2237% o pixel: return a pixel at the specified (x,y) location.
2238%
2239% o exception: return any errors or warnings in this structure.
2240%
2241*/
2242static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002243 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002244{
cristy098f78c2010-09-23 17:28:44 +00002245 CacheInfo
2246 *cache_info;
2247
2248 const int
2249 id = GetOpenMPThreadId();
2250
cristy4c08aed2011-07-01 19:47:50 +00002251 register Quantum
2252 *q;
cristy3ed852e2009-09-05 21:47:34 +00002253
cristy2ed42f62011-10-02 19:49:57 +00002254 register ssize_t
2255 i;
2256
cristy0158a4b2010-09-20 13:59:45 +00002257 assert(image != (const Image *) NULL);
2258 assert(image->signature == MagickSignature);
2259 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002260 cache_info=(CacheInfo *) image->cache;
2261 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002262 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002263 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002264 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2265 exception);
2266 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002267 {
cristy9e0719b2011-12-29 03:45:45 +00002268 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2269 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2270 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2271 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2272 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002273 return(MagickFalse);
2274 }
2275 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2276 {
2277 PixelChannel
2278 channel;
2279
cristye2a912b2011-12-05 20:02:07 +00002280 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002281 pixel[channel]=q[i];
2282 }
cristy3ed852e2009-09-05 21:47:34 +00002283 return(MagickTrue);
2284}
2285
2286/*
2287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2288% %
2289% %
2290% %
cristy3ed852e2009-09-05 21:47:34 +00002291% G e t O n e V i r t u a l P i x e l %
2292% %
2293% %
2294% %
2295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2296%
2297% GetOneVirtualPixel() returns a single virtual pixel at the specified
2298% (x,y) location. The image background color is returned if an error occurs.
2299% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2300%
2301% The format of the GetOneVirtualPixel() method is:
2302%
cristybb503372010-05-27 20:51:26 +00002303% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002304% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002305%
2306% A description of each parameter follows:
2307%
2308% o image: the image.
2309%
2310% o x,y: These values define the location of the pixel to return.
2311%
2312% o pixel: return a pixel at the specified (x,y) location.
2313%
2314% o exception: return any errors or warnings in this structure.
2315%
2316*/
2317MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002318 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002319{
cristy3ed852e2009-09-05 21:47:34 +00002320 CacheInfo
2321 *cache_info;
2322
cristy0158a4b2010-09-20 13:59:45 +00002323 const int
2324 id = GetOpenMPThreadId();
2325
cristy4c08aed2011-07-01 19:47:50 +00002326 const Quantum
2327 *p;
cristy2036f5c2010-09-19 21:18:17 +00002328
cristy2ed42f62011-10-02 19:49:57 +00002329 register ssize_t
2330 i;
2331
cristy3ed852e2009-09-05 21:47:34 +00002332 assert(image != (const Image *) NULL);
2333 assert(image->signature == MagickSignature);
2334 assert(image->cache != (Cache) NULL);
2335 cache_info=(CacheInfo *) image->cache;
2336 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002337 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002338 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2339 (GetOneVirtualPixelFromHandler) NULL)
2340 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2341 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002342 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002343 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002344 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002345 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002346 {
cristy9e0719b2011-12-29 03:45:45 +00002347 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2348 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2349 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2350 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2351 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002352 return(MagickFalse);
2353 }
2354 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2355 {
2356 PixelChannel
2357 channel;
2358
cristye2a912b2011-12-05 20:02:07 +00002359 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002360 pixel[channel]=p[i];
2361 }
cristy2036f5c2010-09-19 21:18:17 +00002362 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002363}
2364
2365/*
2366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367% %
2368% %
2369% %
2370+ 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 %
2371% %
2372% %
2373% %
2374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375%
2376% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2377% specified (x,y) location. The image background color is returned if an
2378% error occurs.
2379%
2380% The format of the GetOneVirtualPixelFromCache() method is:
2381%
2382% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002383% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002384% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002385%
2386% A description of each parameter follows:
2387%
2388% o image: the image.
2389%
2390% o virtual_pixel_method: the virtual pixel method.
2391%
2392% o x,y: These values define the location of the pixel to return.
2393%
2394% o pixel: return a pixel at the specified (x,y) location.
2395%
2396% o exception: return any errors or warnings in this structure.
2397%
2398*/
2399static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002400 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002401 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002402{
cristy0158a4b2010-09-20 13:59:45 +00002403 CacheInfo
2404 *cache_info;
2405
2406 const int
2407 id = GetOpenMPThreadId();
2408
cristy4c08aed2011-07-01 19:47:50 +00002409 const Quantum
2410 *p;
cristy3ed852e2009-09-05 21:47:34 +00002411
cristy2ed42f62011-10-02 19:49:57 +00002412 register ssize_t
2413 i;
2414
cristye7cc7cf2010-09-21 13:26:47 +00002415 assert(image != (const Image *) NULL);
2416 assert(image->signature == MagickSignature);
2417 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002418 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002419 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002420 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002421 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002422 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002423 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002424 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002425 {
cristy9e0719b2011-12-29 03:45:45 +00002426 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2427 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2428 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2429 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2430 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002431 return(MagickFalse);
2432 }
2433 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2434 {
2435 PixelChannel
2436 channel;
2437
cristye2a912b2011-12-05 20:02:07 +00002438 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002439 pixel[channel]=p[i];
2440 }
cristy3ed852e2009-09-05 21:47:34 +00002441 return(MagickTrue);
2442}
2443
2444/*
2445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2446% %
2447% %
2448% %
cristy3aa93752011-12-18 15:54:24 +00002449% G e t O n e V i r t u a l P i x e l I n f o %
2450% %
2451% %
2452% %
2453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2454%
2455% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2456% location. The image background color is returned if an error occurs. If
2457% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2458%
2459% The format of the GetOneVirtualPixelInfo() method is:
2460%
2461% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2462% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2463% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2464%
2465% A description of each parameter follows:
2466%
2467% o image: the image.
2468%
2469% o virtual_pixel_method: the virtual pixel method.
2470%
2471% o x,y: these values define the location of the pixel to return.
2472%
2473% o pixel: return a pixel at the specified (x,y) location.
2474%
2475% o exception: return any errors or warnings in this structure.
2476%
2477*/
2478MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2479 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2480 PixelInfo *pixel,ExceptionInfo *exception)
2481{
2482 CacheInfo
2483 *cache_info;
2484
2485 const int
2486 id = GetOpenMPThreadId();
2487
2488 register const Quantum
2489 *p;
2490
2491 assert(image != (const Image *) NULL);
2492 assert(image->signature == MagickSignature);
2493 assert(image->cache != (Cache) NULL);
2494 cache_info=(CacheInfo *) image->cache;
2495 assert(cache_info->signature == MagickSignature);
2496 assert(id < (int) cache_info->number_threads);
2497 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2498 cache_info->nexus_info[id],exception);
2499 GetPixelInfo(image,pixel);
2500 if (p == (const Quantum *) NULL)
2501 return(MagickFalse);
2502 GetPixelInfoPixel(image,p,pixel);
2503 return(MagickTrue);
2504}
2505
2506/*
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508% %
2509% %
2510% %
cristy3ed852e2009-09-05 21:47:34 +00002511+ G e t P i x e l C a c h e C o l o r s p a c e %
2512% %
2513% %
2514% %
2515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516%
2517% GetPixelCacheColorspace() returns the class type of the pixel cache.
2518%
2519% The format of the GetPixelCacheColorspace() method is:
2520%
2521% Colorspace GetPixelCacheColorspace(Cache cache)
2522%
2523% A description of each parameter follows:
2524%
2525% o cache: the pixel cache.
2526%
2527*/
cristya6577ff2011-09-02 19:54:26 +00002528MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002529{
2530 CacheInfo
2531 *cache_info;
2532
2533 assert(cache != (Cache) NULL);
2534 cache_info=(CacheInfo *) cache;
2535 assert(cache_info->signature == MagickSignature);
2536 if (cache_info->debug != MagickFalse)
2537 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2538 cache_info->filename);
2539 return(cache_info->colorspace);
2540}
2541
2542/*
2543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544% %
2545% %
2546% %
2547+ G e t P i x e l C a c h e M e t h o d s %
2548% %
2549% %
2550% %
2551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2552%
2553% GetPixelCacheMethods() initializes the CacheMethods structure.
2554%
2555% The format of the GetPixelCacheMethods() method is:
2556%
2557% void GetPixelCacheMethods(CacheMethods *cache_methods)
2558%
2559% A description of each parameter follows:
2560%
2561% o cache_methods: Specifies a pointer to a CacheMethods structure.
2562%
2563*/
cristya6577ff2011-09-02 19:54:26 +00002564MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002565{
2566 assert(cache_methods != (CacheMethods *) NULL);
2567 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2568 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2569 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002570 cache_methods->get_virtual_metacontent_from_handler=
2571 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002572 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2573 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002574 cache_methods->get_authentic_metacontent_from_handler=
2575 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002576 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2577 cache_methods->get_one_authentic_pixel_from_handler=
2578 GetOneAuthenticPixelFromCache;
2579 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2580 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2581 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2582}
2583
2584/*
2585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2586% %
2587% %
2588% %
2589+ G e t P i x e l C a c h e N e x u s E x t e n t %
2590% %
2591% %
2592% %
2593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2594%
cristy4c08aed2011-07-01 19:47:50 +00002595% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2596% corresponding with the last call to SetPixelCacheNexusPixels() or
2597% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002598%
2599% The format of the GetPixelCacheNexusExtent() method is:
2600%
2601% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2602% NexusInfo *nexus_info)
2603%
2604% A description of each parameter follows:
2605%
2606% o nexus_info: the nexus info.
2607%
2608*/
cristya6577ff2011-09-02 19:54:26 +00002609MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002610 NexusInfo *nexus_info)
2611{
2612 CacheInfo
2613 *cache_info;
2614
2615 MagickSizeType
2616 extent;
2617
cristy9f027d12011-09-21 01:17:17 +00002618 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002619 cache_info=(CacheInfo *) cache;
2620 assert(cache_info->signature == MagickSignature);
2621 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2622 if (extent == 0)
2623 return((MagickSizeType) cache_info->columns*cache_info->rows);
2624 return(extent);
2625}
2626
2627/*
2628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629% %
2630% %
2631% %
cristy4c08aed2011-07-01 19:47:50 +00002632+ 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 +00002633% %
2634% %
2635% %
2636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2637%
cristy4c08aed2011-07-01 19:47:50 +00002638% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2639% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002640%
cristy4c08aed2011-07-01 19:47:50 +00002641% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002642%
cristy4c08aed2011-07-01 19:47:50 +00002643% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002644% NexusInfo *nexus_info)
2645%
2646% A description of each parameter follows:
2647%
2648% o cache: the pixel cache.
2649%
cristy4c08aed2011-07-01 19:47:50 +00002650% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002651%
2652*/
cristya6577ff2011-09-02 19:54:26 +00002653MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002654 NexusInfo *nexus_info)
2655{
2656 CacheInfo
2657 *cache_info;
2658
cristy9f027d12011-09-21 01:17:17 +00002659 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002660 cache_info=(CacheInfo *) cache;
2661 assert(cache_info->signature == MagickSignature);
2662 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002663 return((void *) NULL);
2664 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002665}
2666
2667/*
2668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2669% %
2670% %
2671% %
2672+ G e t P i x e l C a c h e N e x u s P i x e l s %
2673% %
2674% %
2675% %
2676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2677%
2678% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2679% cache nexus.
2680%
2681% The format of the GetPixelCacheNexusPixels() method is:
2682%
cristy4c08aed2011-07-01 19:47:50 +00002683% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002684% NexusInfo *nexus_info)
2685%
2686% A description of each parameter follows:
2687%
2688% o cache: the pixel cache.
2689%
2690% o nexus_info: the cache nexus to return the pixels.
2691%
2692*/
cristya6577ff2011-09-02 19:54:26 +00002693MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002694 NexusInfo *nexus_info)
2695{
2696 CacheInfo
2697 *cache_info;
2698
cristy9f027d12011-09-21 01:17:17 +00002699 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002700 cache_info=(CacheInfo *) cache;
2701 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002702 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002703 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002704 return(nexus_info->pixels);
2705}
2706
2707/*
2708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709% %
2710% %
2711% %
cristy056ba772010-01-02 23:33:54 +00002712+ G e t P i x e l C a c h e P i x e l s %
2713% %
2714% %
2715% %
2716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2717%
2718% GetPixelCachePixels() returns the pixels associated with the specified image.
2719%
2720% The format of the GetPixelCachePixels() method is:
2721%
cristyf84a1932010-01-03 18:00:18 +00002722% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2723% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002724%
2725% A description of each parameter follows:
2726%
2727% o image: the image.
2728%
2729% o length: the pixel cache length.
2730%
cristyf84a1932010-01-03 18:00:18 +00002731% o exception: return any errors or warnings in this structure.
2732%
cristy056ba772010-01-02 23:33:54 +00002733*/
cristyd1dd6e42011-09-04 01:46:08 +00002734MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002735 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002736{
2737 CacheInfo
2738 *cache_info;
2739
2740 assert(image != (const Image *) NULL);
2741 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002742 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002743 assert(length != (MagickSizeType *) NULL);
2744 assert(exception != (ExceptionInfo *) NULL);
2745 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002746 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002747 assert(cache_info->signature == MagickSignature);
2748 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002749 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002750 return((void *) NULL);
2751 *length=cache_info->length;
2752 return((void *) cache_info->pixels);
2753}
2754
2755/*
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757% %
2758% %
2759% %
cristyb32b90a2009-09-07 21:45:48 +00002760+ 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 +00002761% %
2762% %
2763% %
2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765%
2766% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2767%
2768% The format of the GetPixelCacheStorageClass() method is:
2769%
2770% ClassType GetPixelCacheStorageClass(Cache cache)
2771%
2772% A description of each parameter follows:
2773%
2774% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2775%
2776% o cache: the pixel cache.
2777%
2778*/
cristya6577ff2011-09-02 19:54:26 +00002779MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002780{
2781 CacheInfo
2782 *cache_info;
2783
2784 assert(cache != (Cache) NULL);
2785 cache_info=(CacheInfo *) cache;
2786 assert(cache_info->signature == MagickSignature);
2787 if (cache_info->debug != MagickFalse)
2788 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2789 cache_info->filename);
2790 return(cache_info->storage_class);
2791}
2792
2793/*
2794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2795% %
2796% %
2797% %
cristyb32b90a2009-09-07 21:45:48 +00002798+ G e t P i x e l C a c h e T i l e S i z e %
2799% %
2800% %
2801% %
2802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2803%
2804% GetPixelCacheTileSize() returns the pixel cache tile size.
2805%
2806% The format of the GetPixelCacheTileSize() method is:
2807%
cristybb503372010-05-27 20:51:26 +00002808% void GetPixelCacheTileSize(const Image *image,size_t *width,
2809% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002810%
2811% A description of each parameter follows:
2812%
2813% o image: the image.
2814%
2815% o width: the optimize cache tile width in pixels.
2816%
2817% o height: the optimize cache tile height in pixels.
2818%
2819*/
cristya6577ff2011-09-02 19:54:26 +00002820MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002821 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002822{
cristy4c08aed2011-07-01 19:47:50 +00002823 CacheInfo
2824 *cache_info;
2825
cristyb32b90a2009-09-07 21:45:48 +00002826 assert(image != (Image *) NULL);
2827 assert(image->signature == MagickSignature);
2828 if (image->debug != MagickFalse)
2829 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002830 cache_info=(CacheInfo *) image->cache;
2831 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002832 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002833 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002834 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002835 *height=(*width);
2836}
2837
2838/*
2839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2840% %
2841% %
2842% %
2843+ G e t P i x e l C a c h e T y p e %
2844% %
2845% %
2846% %
2847%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2848%
2849% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2850%
2851% The format of the GetPixelCacheType() method is:
2852%
2853% CacheType GetPixelCacheType(const Image *image)
2854%
2855% A description of each parameter follows:
2856%
2857% o image: the image.
2858%
2859*/
cristya6577ff2011-09-02 19:54:26 +00002860MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002861{
2862 CacheInfo
2863 *cache_info;
2864
2865 assert(image != (Image *) NULL);
2866 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002867 assert(image->cache != (Cache) NULL);
2868 cache_info=(CacheInfo *) image->cache;
2869 assert(cache_info->signature == MagickSignature);
2870 return(cache_info->type);
2871}
2872
2873/*
2874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875% %
2876% %
2877% %
cristy3ed852e2009-09-05 21:47:34 +00002878+ 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 %
2879% %
2880% %
2881% %
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883%
2884% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2885% pixel cache. A virtual pixel is any pixel access that is outside the
2886% boundaries of the image cache.
2887%
2888% The format of the GetPixelCacheVirtualMethod() method is:
2889%
2890% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2891%
2892% A description of each parameter follows:
2893%
2894% o image: the image.
2895%
2896*/
cristyd1dd6e42011-09-04 01:46:08 +00002897MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002898{
2899 CacheInfo
2900 *cache_info;
2901
2902 assert(image != (Image *) NULL);
2903 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002904 assert(image->cache != (Cache) NULL);
2905 cache_info=(CacheInfo *) image->cache;
2906 assert(cache_info->signature == MagickSignature);
2907 return(cache_info->virtual_pixel_method);
2908}
2909
2910/*
2911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2912% %
2913% %
2914% %
cristy4c08aed2011-07-01 19:47:50 +00002915+ 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 +00002916% %
2917% %
2918% %
2919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2920%
cristy4c08aed2011-07-01 19:47:50 +00002921% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2922% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002923%
cristy4c08aed2011-07-01 19:47:50 +00002924% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002925%
cristy4c08aed2011-07-01 19:47:50 +00002926% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002927%
2928% A description of each parameter follows:
2929%
2930% o image: the image.
2931%
2932*/
cristy4c08aed2011-07-01 19:47:50 +00002933static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002934{
2935 CacheInfo
2936 *cache_info;
2937
cristy5c9e6f22010-09-17 17:31:01 +00002938 const int
2939 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002940
cristy4c08aed2011-07-01 19:47:50 +00002941 const void
2942 *metacontent;
2943
cristye7cc7cf2010-09-21 13:26:47 +00002944 assert(image != (const Image *) NULL);
2945 assert(image->signature == MagickSignature);
2946 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002947 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002948 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002949 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002950 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2951 cache_info->nexus_info[id]);
2952 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002953}
2954
2955/*
2956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2957% %
2958% %
2959% %
cristy4c08aed2011-07-01 19:47:50 +00002960+ 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 +00002961% %
2962% %
2963% %
2964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965%
cristy4c08aed2011-07-01 19:47:50 +00002966% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2967% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002968%
cristy4c08aed2011-07-01 19:47:50 +00002969% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002970%
cristy4c08aed2011-07-01 19:47:50 +00002971% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002972% NexusInfo *nexus_info)
2973%
2974% A description of each parameter follows:
2975%
2976% o cache: the pixel cache.
2977%
cristy4c08aed2011-07-01 19:47:50 +00002978% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002979%
2980*/
cristya6577ff2011-09-02 19:54:26 +00002981MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002982 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002983{
2984 CacheInfo
2985 *cache_info;
2986
cristye7cc7cf2010-09-21 13:26:47 +00002987 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002988 cache_info=(CacheInfo *) cache;
2989 assert(cache_info->signature == MagickSignature);
2990 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002991 return((void *) NULL);
2992 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002993}
2994
2995/*
2996%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2997% %
2998% %
2999% %
cristy4c08aed2011-07-01 19:47:50 +00003000% 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 +00003001% %
3002% %
3003% %
3004%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3005%
cristy4c08aed2011-07-01 19:47:50 +00003006% GetVirtualMetacontent() returns the virtual metacontent corresponding with
3007% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3008% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003009%
cristy4c08aed2011-07-01 19:47:50 +00003010% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003011%
cristy4c08aed2011-07-01 19:47:50 +00003012% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003013%
3014% A description of each parameter follows:
3015%
3016% o image: the image.
3017%
3018*/
cristy4c08aed2011-07-01 19:47:50 +00003019MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003020{
3021 CacheInfo
3022 *cache_info;
3023
cristy2036f5c2010-09-19 21:18:17 +00003024 const int
3025 id = GetOpenMPThreadId();
3026
cristy4c08aed2011-07-01 19:47:50 +00003027 const void
3028 *metacontent;
3029
cristy3ed852e2009-09-05 21:47:34 +00003030 assert(image != (const Image *) NULL);
3031 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003032 assert(image->cache != (Cache) NULL);
3033 cache_info=(CacheInfo *) image->cache;
3034 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003035 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3036 (GetVirtualMetacontentFromHandler) NULL)
3037 {
3038 metacontent=cache_info->methods.
3039 get_virtual_metacontent_from_handler(image);
3040 return(metacontent);
3041 }
cristy2036f5c2010-09-19 21:18:17 +00003042 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003043 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3044 cache_info->nexus_info[id]);
3045 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003046}
3047
3048/*
3049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3050% %
3051% %
3052% %
3053+ 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 %
3054% %
3055% %
3056% %
3057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3058%
3059% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3060% pixel cache as defined by the geometry parameters. A pointer to the pixels
3061% is returned if the pixels are transferred, otherwise a NULL is returned.
3062%
3063% The format of the GetVirtualPixelsFromNexus() method is:
3064%
cristy4c08aed2011-07-01 19:47:50 +00003065% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003066% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003067% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3068% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003069%
3070% A description of each parameter follows:
3071%
3072% o image: the image.
3073%
3074% o virtual_pixel_method: the virtual pixel method.
3075%
3076% o x,y,columns,rows: These values define the perimeter of a region of
3077% pixels.
3078%
3079% o nexus_info: the cache nexus to acquire.
3080%
3081% o exception: return any errors or warnings in this structure.
3082%
3083*/
3084
cristybb503372010-05-27 20:51:26 +00003085static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003086 DitherMatrix[64] =
3087 {
3088 0, 48, 12, 60, 3, 51, 15, 63,
3089 32, 16, 44, 28, 35, 19, 47, 31,
3090 8, 56, 4, 52, 11, 59, 7, 55,
3091 40, 24, 36, 20, 43, 27, 39, 23,
3092 2, 50, 14, 62, 1, 49, 13, 61,
3093 34, 18, 46, 30, 33, 17, 45, 29,
3094 10, 58, 6, 54, 9, 57, 5, 53,
3095 42, 26, 38, 22, 41, 25, 37, 21
3096 };
3097
cristybb503372010-05-27 20:51:26 +00003098static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003099{
cristybb503372010-05-27 20:51:26 +00003100 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003101 index;
3102
3103 index=x+DitherMatrix[x & 0x07]-32L;
3104 if (index < 0L)
3105 return(0L);
cristybb503372010-05-27 20:51:26 +00003106 if (index >= (ssize_t) columns)
3107 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003108 return(index);
3109}
3110
cristybb503372010-05-27 20:51:26 +00003111static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003112{
cristybb503372010-05-27 20:51:26 +00003113 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003114 index;
3115
3116 index=y+DitherMatrix[y & 0x07]-32L;
3117 if (index < 0L)
3118 return(0L);
cristybb503372010-05-27 20:51:26 +00003119 if (index >= (ssize_t) rows)
3120 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003121 return(index);
3122}
3123
cristybb503372010-05-27 20:51:26 +00003124static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003125{
3126 if (x < 0L)
3127 return(0L);
cristybb503372010-05-27 20:51:26 +00003128 if (x >= (ssize_t) columns)
3129 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003130 return(x);
3131}
3132
cristybb503372010-05-27 20:51:26 +00003133static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003134{
3135 if (y < 0L)
3136 return(0L);
cristybb503372010-05-27 20:51:26 +00003137 if (y >= (ssize_t) rows)
3138 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003139 return(y);
3140}
3141
cristybb503372010-05-27 20:51:26 +00003142static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003143{
cristybb503372010-05-27 20:51:26 +00003144 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003145}
3146
cristybb503372010-05-27 20:51:26 +00003147static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003148{
cristybb503372010-05-27 20:51:26 +00003149 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003150}
3151
cristybb503372010-05-27 20:51:26 +00003152static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3153 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003154{
3155 MagickModulo
3156 modulo;
3157
cristy6162bb42011-07-18 11:34:09 +00003158 /*
3159 Compute the remainder of dividing offset by extent. It returns not only
3160 the quotient (tile the offset falls in) but also the positive remainer
3161 within that tile such that 0 <= remainder < extent. This method is
3162 essentially a ldiv() using a floored modulo division rather than the
3163 normal default truncated modulo division.
3164 */
cristybb503372010-05-27 20:51:26 +00003165 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003166 if (offset < 0L)
3167 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003168 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003169 return(modulo);
3170}
3171
cristya6577ff2011-09-02 19:54:26 +00003172MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003173 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3174 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003175 ExceptionInfo *exception)
3176{
3177 CacheInfo
3178 *cache_info;
3179
3180 MagickOffsetType
3181 offset;
3182
3183 MagickSizeType
3184 length,
3185 number_pixels;
3186
3187 NexusInfo
3188 **virtual_nexus;
3189
cristy4c08aed2011-07-01 19:47:50 +00003190 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003191 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003192 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003193
3194 RectangleInfo
3195 region;
3196
cristy4c08aed2011-07-01 19:47:50 +00003197 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003198 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003199
cristy4c08aed2011-07-01 19:47:50 +00003200 register const void
3201 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003202
cristy4c08aed2011-07-01 19:47:50 +00003203 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003204 *restrict q;
3205
cristybb503372010-05-27 20:51:26 +00003206 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003207 i,
3208 u;
cristy3ed852e2009-09-05 21:47:34 +00003209
cristy4c08aed2011-07-01 19:47:50 +00003210 register unsigned char
3211 *restrict s;
3212
cristy105ba3c2011-07-18 02:28:38 +00003213 ssize_t
3214 v;
3215
cristy4c08aed2011-07-01 19:47:50 +00003216 void
cristy105ba3c2011-07-18 02:28:38 +00003217 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003218
cristy3ed852e2009-09-05 21:47:34 +00003219 /*
3220 Acquire pixels.
3221 */
cristye7cc7cf2010-09-21 13:26:47 +00003222 assert(image != (const Image *) NULL);
3223 assert(image->signature == MagickSignature);
3224 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003225 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003226 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003227 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003228 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003229 region.x=x;
3230 region.y=y;
3231 region.width=columns;
3232 region.height=rows;
3233 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003234 if (pixels == (Quantum *) NULL)
3235 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003236 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003237 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3238 nexus_info->region.x;
3239 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3240 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003241 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3242 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003243 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3244 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003245 {
3246 MagickBooleanType
3247 status;
3248
3249 /*
3250 Pixel request is inside cache extents.
3251 */
cristy4c08aed2011-07-01 19:47:50 +00003252 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003253 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003254 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3255 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003256 return((const Quantum *) NULL);
3257 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003258 {
cristy4c08aed2011-07-01 19:47:50 +00003259 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003260 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003261 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003262 }
cristyacd2ed22011-08-30 01:44:23 +00003263 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003264 }
3265 /*
3266 Pixel request is outside cache extents.
3267 */
cristy4c08aed2011-07-01 19:47:50 +00003268 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003269 virtual_nexus=AcquirePixelCacheNexus(1);
3270 if (virtual_nexus == (NexusInfo **) NULL)
3271 {
cristy4c08aed2011-07-01 19:47:50 +00003272 if (virtual_nexus != (NexusInfo **) NULL)
3273 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003274 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3275 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003276 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003277 }
cristy105ba3c2011-07-18 02:28:38 +00003278 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3279 sizeof(*virtual_pixel));
3280 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003281 switch (virtual_pixel_method)
3282 {
cristy4c08aed2011-07-01 19:47:50 +00003283 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003284 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003285 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003286 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003287 case MaskVirtualPixelMethod:
3288 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003289 case EdgeVirtualPixelMethod:
3290 case CheckerTileVirtualPixelMethod:
3291 case HorizontalTileVirtualPixelMethod:
3292 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003293 {
cristy4c08aed2011-07-01 19:47:50 +00003294 if (cache_info->metacontent_extent != 0)
3295 {
cristy6162bb42011-07-18 11:34:09 +00003296 /*
3297 Acquire a metacontent buffer.
3298 */
cristya64b85d2011-09-14 01:02:31 +00003299 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003300 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003301 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003302 {
cristy4c08aed2011-07-01 19:47:50 +00003303 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3304 (void) ThrowMagickException(exception,GetMagickModule(),
3305 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3306 return((const Quantum *) NULL);
3307 }
cristy105ba3c2011-07-18 02:28:38 +00003308 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003309 cache_info->metacontent_extent);
3310 }
3311 switch (virtual_pixel_method)
3312 {
3313 case BlackVirtualPixelMethod:
3314 {
cristy30301712011-07-18 15:06:51 +00003315 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3316 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003317 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3318 break;
3319 }
3320 case GrayVirtualPixelMethod:
3321 {
cristy30301712011-07-18 15:06:51 +00003322 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003323 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3324 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003325 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3326 break;
3327 }
3328 case TransparentVirtualPixelMethod:
3329 {
cristy30301712011-07-18 15:06:51 +00003330 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3331 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003332 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3333 break;
3334 }
3335 case MaskVirtualPixelMethod:
3336 case WhiteVirtualPixelMethod:
3337 {
cristy30301712011-07-18 15:06:51 +00003338 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3339 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003340 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3341 break;
3342 }
3343 default:
3344 {
cristy9e0719b2011-12-29 03:45:45 +00003345 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3346 virtual_pixel);
3347 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3348 virtual_pixel);
3349 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3350 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003351 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003352 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3353 virtual_pixel);
3354 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3355 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003356 break;
3357 }
3358 }
cristy3ed852e2009-09-05 21:47:34 +00003359 break;
3360 }
3361 default:
cristy3ed852e2009-09-05 21:47:34 +00003362 break;
cristy3ed852e2009-09-05 21:47:34 +00003363 }
cristybb503372010-05-27 20:51:26 +00003364 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003365 {
cristybb503372010-05-27 20:51:26 +00003366 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003367 {
3368 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003369 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003370 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3371 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003372 {
3373 MagickModulo
3374 x_modulo,
3375 y_modulo;
3376
3377 /*
3378 Transfer a single pixel.
3379 */
3380 length=(MagickSizeType) 1;
3381 switch (virtual_pixel_method)
3382 {
cristy3ed852e2009-09-05 21:47:34 +00003383 default:
3384 {
3385 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003386 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003387 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003388 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003389 break;
3390 }
3391 case RandomVirtualPixelMethod:
3392 {
3393 if (cache_info->random_info == (RandomInfo *) NULL)
3394 cache_info->random_info=AcquireRandomInfo();
3395 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003396 RandomX(cache_info->random_info,cache_info->columns),
3397 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003398 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003399 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003400 break;
3401 }
3402 case DitherVirtualPixelMethod:
3403 {
3404 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003405 DitherX(x+u,cache_info->columns),DitherY(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 TileVirtualPixelMethod:
3411 {
3412 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3413 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3414 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003415 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003416 exception);
cristy4c08aed2011-07-01 19:47:50 +00003417 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003418 break;
3419 }
3420 case MirrorVirtualPixelMethod:
3421 {
3422 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3423 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003424 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003425 x_modulo.remainder-1L;
3426 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3427 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003428 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003429 y_modulo.remainder-1L;
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003431 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003432 exception);
cristy4c08aed2011-07-01 19:47:50 +00003433 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003434 break;
3435 }
3436 case HorizontalTileEdgeVirtualPixelMethod:
3437 {
3438 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003440 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003441 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003442 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003443 break;
3444 }
3445 case VerticalTileEdgeVirtualPixelMethod:
3446 {
3447 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3448 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003449 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003450 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003451 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3452 break;
3453 }
3454 case BackgroundVirtualPixelMethod:
3455 case BlackVirtualPixelMethod:
3456 case GrayVirtualPixelMethod:
3457 case TransparentVirtualPixelMethod:
3458 case MaskVirtualPixelMethod:
3459 case WhiteVirtualPixelMethod:
3460 {
3461 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003462 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003463 break;
3464 }
3465 case EdgeVirtualPixelMethod:
3466 case CheckerTileVirtualPixelMethod:
3467 {
3468 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3469 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3470 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3471 {
3472 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003473 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003474 break;
3475 }
3476 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3477 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3478 exception);
3479 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3480 break;
3481 }
3482 case HorizontalTileVirtualPixelMethod:
3483 {
3484 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3485 {
3486 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003487 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003488 break;
3489 }
3490 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3491 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3492 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3493 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3494 exception);
3495 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3496 break;
3497 }
3498 case VerticalTileVirtualPixelMethod:
3499 {
3500 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3501 {
3502 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003503 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003504 break;
3505 }
3506 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3507 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3508 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3509 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3510 exception);
3511 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003512 break;
3513 }
3514 }
cristy4c08aed2011-07-01 19:47:50 +00003515 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003516 break;
cristyed231572011-07-14 02:18:59 +00003517 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003518 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003519 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003520 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003521 {
3522 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3523 s+=cache_info->metacontent_extent;
3524 }
cristy3ed852e2009-09-05 21:47:34 +00003525 continue;
3526 }
3527 /*
3528 Transfer a run of pixels.
3529 */
cristy4c08aed2011-07-01 19:47:50 +00003530 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3531 length,1UL,*virtual_nexus,exception);
3532 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003533 break;
cristy4c08aed2011-07-01 19:47:50 +00003534 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003535 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3536 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003537 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003538 {
cristy4c08aed2011-07-01 19:47:50 +00003539 (void) memcpy(s,r,(size_t) length);
3540 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003541 }
3542 }
3543 }
cristy4c08aed2011-07-01 19:47:50 +00003544 /*
3545 Free resources.
3546 */
cristy105ba3c2011-07-18 02:28:38 +00003547 if (virtual_metacontent != (void *) NULL)
3548 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003549 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3550 return(pixels);
3551}
3552
3553/*
3554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3555% %
3556% %
3557% %
3558+ G e t V i r t u a l P i x e l C a c h e %
3559% %
3560% %
3561% %
3562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3563%
3564% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3565% cache as defined by the geometry parameters. A pointer to the pixels
3566% is returned if the pixels are transferred, otherwise a NULL is returned.
3567%
3568% The format of the GetVirtualPixelCache() method is:
3569%
cristy4c08aed2011-07-01 19:47:50 +00003570% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003571% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3572% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003573% ExceptionInfo *exception)
3574%
3575% A description of each parameter follows:
3576%
3577% o image: the image.
3578%
3579% o virtual_pixel_method: the virtual pixel method.
3580%
3581% o x,y,columns,rows: These values define the perimeter of a region of
3582% pixels.
3583%
3584% o exception: return any errors or warnings in this structure.
3585%
3586*/
cristy4c08aed2011-07-01 19:47:50 +00003587static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003588 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3589 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003590{
3591 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003592 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003593
cristy5c9e6f22010-09-17 17:31:01 +00003594 const int
3595 id = GetOpenMPThreadId();
3596
cristy4c08aed2011-07-01 19:47:50 +00003597 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003598 *p;
cristy4c08aed2011-07-01 19:47:50 +00003599
cristye7cc7cf2010-09-21 13:26:47 +00003600 assert(image != (const Image *) NULL);
3601 assert(image->signature == MagickSignature);
3602 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003603 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003604 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003605 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003606 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003607 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003608 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003609}
3610
3611/*
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613% %
3614% %
3615% %
3616% G e t V i r t u a l P i x e l Q u e u e %
3617% %
3618% %
3619% %
3620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3621%
cristy4c08aed2011-07-01 19:47:50 +00003622% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3623% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003624%
3625% The format of the GetVirtualPixelQueue() method is:
3626%
cristy4c08aed2011-07-01 19:47:50 +00003627% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003628%
3629% A description of each parameter follows:
3630%
3631% o image: the image.
3632%
3633*/
cristy4c08aed2011-07-01 19:47:50 +00003634MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003635{
3636 CacheInfo
3637 *cache_info;
3638
cristy2036f5c2010-09-19 21:18:17 +00003639 const int
3640 id = GetOpenMPThreadId();
3641
cristy3ed852e2009-09-05 21:47:34 +00003642 assert(image != (const Image *) NULL);
3643 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003644 assert(image->cache != (Cache) NULL);
3645 cache_info=(CacheInfo *) image->cache;
3646 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003647 if (cache_info->methods.get_virtual_pixels_handler !=
3648 (GetVirtualPixelsHandler) NULL)
3649 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003650 assert(id < (int) cache_info->number_threads);
3651 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003652}
3653
3654/*
3655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3656% %
3657% %
3658% %
3659% G e t V i r t u a l P i x e l s %
3660% %
3661% %
3662% %
3663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3664%
3665% GetVirtualPixels() returns an immutable pixel region. If the
3666% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003667% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003668% copy of the pixels or it may point to the original pixels in memory.
3669% Performance is maximized if the selected region is part of one row, or one
3670% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003671% (without a copy) if the image is in memory, or in a memory-mapped file. The
3672% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003673%
3674% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003675% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3676% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3677% access the meta-content (of type void) corresponding to the the
3678% region.
cristy3ed852e2009-09-05 21:47:34 +00003679%
3680% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3681%
3682% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3683% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3684% GetCacheViewAuthenticPixels() instead.
3685%
3686% The format of the GetVirtualPixels() method is:
3687%
cristy4c08aed2011-07-01 19:47:50 +00003688% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003689% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003690% ExceptionInfo *exception)
3691%
3692% A description of each parameter follows:
3693%
3694% o image: the image.
3695%
3696% o x,y,columns,rows: These values define the perimeter of a region of
3697% pixels.
3698%
3699% o exception: return any errors or warnings in this structure.
3700%
3701*/
cristy4c08aed2011-07-01 19:47:50 +00003702MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003703 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3704 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003705{
3706 CacheInfo
3707 *cache_info;
3708
cristy2036f5c2010-09-19 21:18:17 +00003709 const int
3710 id = GetOpenMPThreadId();
3711
cristy4c08aed2011-07-01 19:47:50 +00003712 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003713 *p;
cristy4c08aed2011-07-01 19:47:50 +00003714
cristy3ed852e2009-09-05 21:47:34 +00003715 assert(image != (const Image *) NULL);
3716 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003717 assert(image->cache != (Cache) NULL);
3718 cache_info=(CacheInfo *) image->cache;
3719 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003720 if (cache_info->methods.get_virtual_pixel_handler !=
3721 (GetVirtualPixelHandler) NULL)
3722 return(cache_info->methods.get_virtual_pixel_handler(image,
3723 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003724 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003725 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003726 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003727 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003728}
3729
3730/*
3731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3732% %
3733% %
3734% %
3735+ 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 %
3736% %
3737% %
3738% %
3739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3740%
cristy4c08aed2011-07-01 19:47:50 +00003741% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3742% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003743%
3744% The format of the GetVirtualPixelsCache() method is:
3745%
cristy4c08aed2011-07-01 19:47:50 +00003746% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003747%
3748% A description of each parameter follows:
3749%
3750% o image: the image.
3751%
3752*/
cristy4c08aed2011-07-01 19:47:50 +00003753static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003754{
3755 CacheInfo
3756 *cache_info;
3757
cristy5c9e6f22010-09-17 17:31:01 +00003758 const int
3759 id = GetOpenMPThreadId();
3760
cristye7cc7cf2010-09-21 13:26:47 +00003761 assert(image != (const Image *) NULL);
3762 assert(image->signature == MagickSignature);
3763 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003764 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003765 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003766 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003767 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003768}
3769
3770/*
3771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3772% %
3773% %
3774% %
3775+ G e t V i r t u a l P i x e l s N e x u s %
3776% %
3777% %
3778% %
3779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3780%
3781% GetVirtualPixelsNexus() returns the pixels associated with the specified
3782% cache nexus.
3783%
3784% The format of the GetVirtualPixelsNexus() method is:
3785%
cristy4c08aed2011-07-01 19:47:50 +00003786% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003787% NexusInfo *nexus_info)
3788%
3789% A description of each parameter follows:
3790%
3791% o cache: the pixel cache.
3792%
3793% o nexus_info: the cache nexus to return the colormap pixels.
3794%
3795*/
cristya6577ff2011-09-02 19:54:26 +00003796MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003797 NexusInfo *nexus_info)
3798{
3799 CacheInfo
3800 *cache_info;
3801
cristye7cc7cf2010-09-21 13:26:47 +00003802 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003803 cache_info=(CacheInfo *) cache;
3804 assert(cache_info->signature == MagickSignature);
3805 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003806 return((Quantum *) NULL);
3807 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003808}
3809
3810/*
3811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3812% %
3813% %
3814% %
3815+ M a s k P i x e l C a c h e N e x u s %
3816% %
3817% %
3818% %
3819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3820%
3821% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3822% The method returns MagickTrue if the pixel region is masked, otherwise
3823% MagickFalse.
3824%
3825% The format of the MaskPixelCacheNexus() method is:
3826%
3827% MagickBooleanType MaskPixelCacheNexus(Image *image,
3828% NexusInfo *nexus_info,ExceptionInfo *exception)
3829%
3830% A description of each parameter follows:
3831%
3832% o image: the image.
3833%
3834% o nexus_info: the cache nexus to clip.
3835%
3836% o exception: return any errors or warnings in this structure.
3837%
3838*/
3839
cristy3aa93752011-12-18 15:54:24 +00003840static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3841 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003842{
3843 MagickRealType
3844 gamma;
3845
cristyaa83c2c2011-09-21 13:36:25 +00003846 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003847 {
3848 *composite=(*q);
3849 return;
3850 }
3851 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3852 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003853 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3854 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3855 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003856 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003857 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003858}
3859
3860static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3861 ExceptionInfo *exception)
3862{
3863 CacheInfo
3864 *cache_info;
3865
cristy4c08aed2011-07-01 19:47:50 +00003866 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003867 alpha,
3868 beta;
3869
3870 MagickSizeType
3871 number_pixels;
3872
3873 NexusInfo
3874 **clip_nexus,
3875 **image_nexus;
3876
cristy4c08aed2011-07-01 19:47:50 +00003877 register const Quantum
3878 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003879 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003880
cristy4c08aed2011-07-01 19:47:50 +00003881 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003882 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003883
cristye076a6e2010-08-15 19:59:43 +00003884 register ssize_t
3885 i;
3886
cristy3ed852e2009-09-05 21:47:34 +00003887 /*
3888 Apply clip mask.
3889 */
3890 if (image->debug != MagickFalse)
3891 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3892 if (image->mask == (Image *) NULL)
3893 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003894 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003895 if (cache_info == (Cache) NULL)
3896 return(MagickFalse);
3897 image_nexus=AcquirePixelCacheNexus(1);
3898 clip_nexus=AcquirePixelCacheNexus(1);
3899 if ((image_nexus == (NexusInfo **) NULL) ||
3900 (clip_nexus == (NexusInfo **) NULL))
3901 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003902 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3903 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3904 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003905 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003906 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3907 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003908 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003909 GetPixelInfo(image,&alpha);
3910 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003911 number_pixels=(MagickSizeType) nexus_info->region.width*
3912 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003913 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003914 {
cristy4c08aed2011-07-01 19:47:50 +00003915 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003916 break;
cristy803640d2011-11-17 02:11:32 +00003917 GetPixelInfoPixel(image,p,&alpha);
3918 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003919 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003920 &alpha,alpha.alpha,&beta);
3921 SetPixelRed(image,ClampToQuantum(beta.red),q);
3922 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3923 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3924 if (cache_info->colorspace == CMYKColorspace)
3925 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3926 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003927 p++;
3928 q++;
3929 r++;
3930 }
3931 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3932 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003933 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003934 return(MagickFalse);
3935 return(MagickTrue);
3936}
3937
3938/*
3939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3940% %
3941% %
3942% %
3943+ O p e n P i x e l C a c h e %
3944% %
3945% %
3946% %
3947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3948%
3949% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3950% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003951% metacontent, and memory mapping the cache if it is disk based. The cache
3952% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003953%
3954% The format of the OpenPixelCache() method is:
3955%
3956% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3957% ExceptionInfo *exception)
3958%
3959% A description of each parameter follows:
3960%
3961% o image: the image.
3962%
3963% o mode: ReadMode, WriteMode, or IOMode.
3964%
3965% o exception: return any errors or warnings in this structure.
3966%
3967*/
3968
cristyd43a46b2010-01-21 02:13:41 +00003969static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003970{
3971 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003972 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003973 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003974 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003975 {
3976 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003977 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003978 cache_info->length);
3979 }
3980}
3981
3982static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3983{
3984 CacheInfo
3985 *cache_info;
3986
3987 MagickOffsetType
3988 count,
3989 extent,
3990 offset;
3991
3992 cache_info=(CacheInfo *) image->cache;
3993 if (image->debug != MagickFalse)
3994 {
3995 char
3996 format[MaxTextExtent],
3997 message[MaxTextExtent];
3998
cristyb9080c92009-12-01 20:13:26 +00003999 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004000 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004001 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004002 cache_info->cache_filename,cache_info->file,format);
4003 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4004 }
4005 if (length != (MagickSizeType) ((MagickOffsetType) length))
4006 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004007 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004008 if (extent < 0)
4009 return(MagickFalse);
4010 if ((MagickSizeType) extent >= length)
4011 return(MagickTrue);
4012 offset=(MagickOffsetType) length-1;
4013 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4014 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4015}
4016
4017static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4018 ExceptionInfo *exception)
4019{
cristy3ed852e2009-09-05 21:47:34 +00004020 CacheInfo
4021 *cache_info,
4022 source_info;
4023
cristyf3a6a9d2010-11-07 21:02:56 +00004024 char
4025 format[MaxTextExtent],
4026 message[MaxTextExtent];
4027
cristy4c08aed2011-07-01 19:47:50 +00004028 MagickBooleanType
4029 status;
4030
cristy3ed852e2009-09-05 21:47:34 +00004031 MagickSizeType
4032 length,
4033 number_pixels;
4034
cristy3b8fe922011-12-29 18:56:23 +00004035 PixelChannelMap
4036 *p,
4037 *q;
4038
cristy3ed852e2009-09-05 21:47:34 +00004039 size_t
cristye076a6e2010-08-15 19:59:43 +00004040 columns,
cristy3ed852e2009-09-05 21:47:34 +00004041 packet_size;
4042
cristye7cc7cf2010-09-21 13:26:47 +00004043 assert(image != (const Image *) NULL);
4044 assert(image->signature == MagickSignature);
4045 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004046 if (image->debug != MagickFalse)
4047 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4048 if ((image->columns == 0) || (image->rows == 0))
4049 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4050 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004051 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004052 source_info=(*cache_info);
4053 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004054 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004055 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004056 cache_info->storage_class=image->storage_class;
4057 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004058 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004059 cache_info->rows=image->rows;
4060 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004061 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004062 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004063 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4064 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004065 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004066 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004067 if (image->ping != MagickFalse)
4068 {
cristy73724512010-04-12 14:43:14 +00004069 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004070 cache_info->pixels=(Quantum *) NULL;
4071 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004072 cache_info->length=0;
4073 return(MagickTrue);
4074 }
cristy3ed852e2009-09-05 21:47:34 +00004075 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004076 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004077 if (image->metacontent_extent != 0)
4078 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004079 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004080 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004081 if (cache_info->columns != columns)
4082 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4083 image->filename);
4084 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004085 p=cache_info->channel_map;
4086 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004087 if ((cache_info->type != UndefinedCache) &&
4088 (cache_info->columns <= source_info.columns) &&
4089 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004090 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004091 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004092 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4093 {
4094 /*
4095 Inline pixel cache clone optimization.
4096 */
4097 if ((cache_info->columns == source_info.columns) &&
4098 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004099 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004100 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004101 (cache_info->metacontent_extent == source_info.metacontent_extent))
4102 return(MagickTrue);
4103 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4104 }
cristy3ed852e2009-09-05 21:47:34 +00004105 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004106 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004107 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004108 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4109 {
4110 status=AcquireMagickResource(MemoryResource,cache_info->length);
4111 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4112 (cache_info->type == MemoryCache))
4113 {
cristyd43a46b2010-01-21 02:13:41 +00004114 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004115 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004116 cache_info->pixels=source_info.pixels;
4117 else
4118 {
4119 /*
4120 Create memory pixel cache.
4121 */
cristy4c08aed2011-07-01 19:47:50 +00004122 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004123 if (image->debug != MagickFalse)
4124 {
cristy32cacff2011-12-31 03:36:27 +00004125 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004126 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004127 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4128 cache_info->filename,cache_info->mapped != MagickFalse ?
4129 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004130 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004131 format);
cristy3ed852e2009-09-05 21:47:34 +00004132 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4133 message);
4134 }
cristy3ed852e2009-09-05 21:47:34 +00004135 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004136 cache_info->metacontent=(void *) NULL;
4137 if (cache_info->metacontent_extent != 0)
4138 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004139 number_pixels*cache_info->number_channels);
cristy0f4425e2011-12-31 20:33:02 +00004140 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004141 {
cristy4c08aed2011-07-01 19:47:50 +00004142 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004143 exception);
4144 RelinquishPixelCachePixels(&source_info);
4145 }
cristy4c08aed2011-07-01 19:47:50 +00004146 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004147 }
4148 }
4149 RelinquishMagickResource(MemoryResource,cache_info->length);
4150 }
4151 /*
4152 Create pixel cache on disk.
4153 */
4154 status=AcquireMagickResource(DiskResource,cache_info->length);
4155 if (status == MagickFalse)
4156 {
4157 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4158 "CacheResourcesExhausted","`%s'",image->filename);
4159 return(MagickFalse);
4160 }
4161 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4162 {
4163 RelinquishMagickResource(DiskResource,cache_info->length);
4164 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4165 image->filename);
4166 return(MagickFalse);
4167 }
4168 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4169 cache_info->length);
4170 if (status == MagickFalse)
4171 {
4172 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4173 image->filename);
4174 return(MagickFalse);
4175 }
cristyed231572011-07-14 02:18:59 +00004176 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004177 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004178 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004179 cache_info->type=DiskCache;
4180 else
4181 {
4182 status=AcquireMagickResource(MapResource,cache_info->length);
4183 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4184 (cache_info->type != MemoryCache))
4185 cache_info->type=DiskCache;
4186 else
4187 {
cristy4c08aed2011-07-01 19:47:50 +00004188 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004189 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004190 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004191 {
cristy3ed852e2009-09-05 21:47:34 +00004192 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004193 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004194 }
4195 else
4196 {
4197 /*
4198 Create file-backed memory-mapped pixel cache.
4199 */
cristy4c08aed2011-07-01 19:47:50 +00004200 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004201 (void) ClosePixelCacheOnDisk(cache_info);
4202 cache_info->type=MapCache;
4203 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004204 cache_info->metacontent=(void *) NULL;
4205 if (cache_info->metacontent_extent != 0)
4206 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004207 number_pixels*cache_info->number_channels);
cristy0f4425e2011-12-31 20:33:02 +00004208 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004209 {
4210 status=ClonePixelCachePixels(cache_info,&source_info,
4211 exception);
4212 RelinquishPixelCachePixels(&source_info);
4213 }
4214 if (image->debug != MagickFalse)
4215 {
cristy97e7a572009-12-05 15:07:53 +00004216 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004217 format);
cristyb51dff52011-05-19 16:55:47 +00004218 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004219 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004220 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004221 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004222 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004223 format);
cristy3ed852e2009-09-05 21:47:34 +00004224 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4225 message);
4226 }
cristy4c08aed2011-07-01 19:47:50 +00004227 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004228 }
4229 }
4230 RelinquishMagickResource(MapResource,cache_info->length);
4231 }
cristy4c08aed2011-07-01 19:47:50 +00004232 status=MagickTrue;
cristy0f4425e2011-12-31 20:33:02 +00004233 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004234 {
4235 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4236 RelinquishPixelCachePixels(&source_info);
4237 }
4238 if (image->debug != MagickFalse)
4239 {
cristyb9080c92009-12-01 20:13:26 +00004240 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004241 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004242 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004243 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004244 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004245 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004246 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4247 }
cristy4c08aed2011-07-01 19:47:50 +00004248 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004249}
4250
4251/*
4252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4253% %
4254% %
4255% %
4256+ P e r s i s t P i x e l C a c h e %
4257% %
4258% %
4259% %
4260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4261%
4262% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4263% persistent pixel cache is one that resides on disk and is not destroyed
4264% when the program exits.
4265%
4266% The format of the PersistPixelCache() method is:
4267%
4268% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4269% const MagickBooleanType attach,MagickOffsetType *offset,
4270% ExceptionInfo *exception)
4271%
4272% A description of each parameter follows:
4273%
4274% o image: the image.
4275%
4276% o filename: the persistent pixel cache filename.
4277%
cristyf3a6a9d2010-11-07 21:02:56 +00004278% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004279%
cristy3ed852e2009-09-05 21:47:34 +00004280% o initialize: A value other than zero initializes the persistent pixel
4281% cache.
4282%
4283% o offset: the offset in the persistent cache to store pixels.
4284%
4285% o exception: return any errors or warnings in this structure.
4286%
4287*/
4288MagickExport MagickBooleanType PersistPixelCache(Image *image,
4289 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4290 ExceptionInfo *exception)
4291{
4292 CacheInfo
4293 *cache_info,
4294 *clone_info;
4295
4296 Image
4297 clone_image;
4298
cristy3ed852e2009-09-05 21:47:34 +00004299 MagickBooleanType
4300 status;
4301
cristye076a6e2010-08-15 19:59:43 +00004302 ssize_t
4303 page_size;
4304
cristy3ed852e2009-09-05 21:47:34 +00004305 assert(image != (Image *) NULL);
4306 assert(image->signature == MagickSignature);
4307 if (image->debug != MagickFalse)
4308 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4309 assert(image->cache != (void *) NULL);
4310 assert(filename != (const char *) NULL);
4311 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004312 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004313 cache_info=(CacheInfo *) image->cache;
4314 assert(cache_info->signature == MagickSignature);
4315 if (attach != MagickFalse)
4316 {
4317 /*
cristy01b7eb02009-09-10 23:10:14 +00004318 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004319 */
4320 if (image->debug != MagickFalse)
4321 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004322 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004323 (void) CopyMagickString(cache_info->cache_filename,filename,
4324 MaxTextExtent);
4325 cache_info->type=DiskCache;
4326 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004327 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004328 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004329 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004330 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004331 }
cristy01b7eb02009-09-10 23:10:14 +00004332 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4333 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004334 {
cristyf84a1932010-01-03 18:00:18 +00004335 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004336 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004337 (cache_info->reference_count == 1))
4338 {
4339 int
4340 status;
4341
4342 /*
cristy01b7eb02009-09-10 23:10:14 +00004343 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004344 */
cristy320684d2011-09-23 14:55:47 +00004345 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004346 if (status == 0)
4347 {
4348 (void) CopyMagickString(cache_info->cache_filename,filename,
4349 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004350 *offset+=cache_info->length+page_size-(cache_info->length %
4351 page_size);
cristyf84a1932010-01-03 18:00:18 +00004352 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004353 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004354 if (image->debug != MagickFalse)
4355 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4356 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004357 return(MagickTrue);
4358 }
4359 }
cristyf84a1932010-01-03 18:00:18 +00004360 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004361 }
4362 /*
cristy01b7eb02009-09-10 23:10:14 +00004363 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004364 */
4365 clone_image=(*image);
4366 clone_info=(CacheInfo *) clone_image.cache;
4367 image->cache=ClonePixelCache(cache_info);
4368 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4369 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4370 cache_info->type=DiskCache;
4371 cache_info->offset=(*offset);
4372 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004373 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004374 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004375 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004376 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004377 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4378 return(status);
4379}
4380
4381/*
4382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4383% %
4384% %
4385% %
4386+ Q u e u e A u t h e n t i c N e x u s %
4387% %
4388% %
4389% %
4390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4391%
4392% QueueAuthenticNexus() allocates an region to store image pixels as defined
4393% by the region rectangle and returns a pointer to the region. This region is
4394% subsequently transferred from the pixel cache with
4395% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4396% pixels are transferred, otherwise a NULL is returned.
4397%
4398% The format of the QueueAuthenticNexus() method is:
4399%
cristy4c08aed2011-07-01 19:47:50 +00004400% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004401% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004402% const MagickBooleanType clone,NexusInfo *nexus_info,
4403% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004404%
4405% A description of each parameter follows:
4406%
4407% o image: the image.
4408%
4409% o x,y,columns,rows: These values define the perimeter of a region of
4410% pixels.
4411%
4412% o nexus_info: the cache nexus to set.
4413%
cristy65dbf172011-10-06 17:32:04 +00004414% o clone: clone the pixel cache.
4415%
cristy3ed852e2009-09-05 21:47:34 +00004416% o exception: return any errors or warnings in this structure.
4417%
4418*/
cristya6577ff2011-09-02 19:54:26 +00004419MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004420 const ssize_t y,const size_t columns,const size_t rows,
4421 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004422{
4423 CacheInfo
4424 *cache_info;
4425
4426 MagickOffsetType
4427 offset;
4428
4429 MagickSizeType
4430 number_pixels;
4431
4432 RectangleInfo
4433 region;
4434
4435 /*
4436 Validate pixel cache geometry.
4437 */
cristye7cc7cf2010-09-21 13:26:47 +00004438 assert(image != (const Image *) NULL);
4439 assert(image->signature == MagickSignature);
4440 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004441 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004442 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004443 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004444 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004445 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4446 {
4447 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4448 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004449 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004450 }
cristybb503372010-05-27 20:51:26 +00004451 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4452 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004453 {
4454 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4455 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004456 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004457 }
4458 offset=(MagickOffsetType) y*cache_info->columns+x;
4459 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004460 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004461 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4462 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4463 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004464 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004465 /*
4466 Return pixel cache.
4467 */
4468 region.x=x;
4469 region.y=y;
4470 region.width=columns;
4471 region.height=rows;
4472 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4473}
4474
4475/*
4476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4477% %
4478% %
4479% %
4480+ 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 %
4481% %
4482% %
4483% %
4484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4485%
4486% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4487% defined by the region rectangle and returns a pointer to the region. This
4488% region is subsequently transferred from the pixel cache with
4489% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4490% pixels are transferred, otherwise a NULL is returned.
4491%
4492% The format of the QueueAuthenticPixelsCache() method is:
4493%
cristy4c08aed2011-07-01 19:47:50 +00004494% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004495% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004496% ExceptionInfo *exception)
4497%
4498% A description of each parameter follows:
4499%
4500% o image: the image.
4501%
4502% o x,y,columns,rows: These values define the perimeter of a region of
4503% pixels.
4504%
4505% o exception: return any errors or warnings in this structure.
4506%
4507*/
cristy4c08aed2011-07-01 19:47:50 +00004508static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004509 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004510 ExceptionInfo *exception)
4511{
4512 CacheInfo
4513 *cache_info;
4514
cristy5c9e6f22010-09-17 17:31:01 +00004515 const int
4516 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004517
cristy4c08aed2011-07-01 19:47:50 +00004518 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004519 *q;
cristy4c08aed2011-07-01 19:47:50 +00004520
cristye7cc7cf2010-09-21 13:26:47 +00004521 assert(image != (const Image *) NULL);
4522 assert(image->signature == MagickSignature);
4523 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004524 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004525 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004526 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004527 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4528 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004529 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004530}
4531
4532/*
4533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4534% %
4535% %
4536% %
4537% Q u e u e A u t h e n t i c P i x e l s %
4538% %
4539% %
4540% %
4541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4542%
4543% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004544% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004545% region is returned, otherwise NULL is returned. The returned pointer may
4546% point to a temporary working buffer for the pixels or it may point to the
4547% final location of the pixels in memory.
4548%
4549% Write-only access means that any existing pixel values corresponding to
4550% the region are ignored. This is useful if the initial image is being
4551% created from scratch, or if the existing pixel values are to be
4552% completely replaced without need to refer to their pre-existing values.
4553% The application is free to read and write the pixel buffer returned by
4554% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4555% initialize the pixel array values. Initializing pixel array values is the
4556% application's responsibility.
4557%
4558% Performance is maximized if the selected region is part of one row, or
4559% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004560% pixels in-place (without a copy) if the image is in memory, or in a
4561% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004562% by the user.
4563%
4564% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004565% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4566% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4567% obtain the meta-content (of type void) corresponding to the region.
4568% Once the Quantum (and/or Quantum) array has been updated, the
4569% changes must be saved back to the underlying image using
4570% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004571%
4572% The format of the QueueAuthenticPixels() method is:
4573%
cristy4c08aed2011-07-01 19:47:50 +00004574% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004575% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004576% ExceptionInfo *exception)
4577%
4578% A description of each parameter follows:
4579%
4580% o image: the image.
4581%
4582% o x,y,columns,rows: These values define the perimeter of a region of
4583% pixels.
4584%
4585% o exception: return any errors or warnings in this structure.
4586%
4587*/
cristy4c08aed2011-07-01 19:47:50 +00004588MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004589 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004590 ExceptionInfo *exception)
4591{
4592 CacheInfo
4593 *cache_info;
4594
cristy2036f5c2010-09-19 21:18:17 +00004595 const int
4596 id = GetOpenMPThreadId();
4597
cristy4c08aed2011-07-01 19:47:50 +00004598 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004599 *q;
cristy4c08aed2011-07-01 19:47:50 +00004600
cristy3ed852e2009-09-05 21:47:34 +00004601 assert(image != (Image *) NULL);
4602 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004603 assert(image->cache != (Cache) NULL);
4604 cache_info=(CacheInfo *) image->cache;
4605 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004606 if (cache_info->methods.queue_authentic_pixels_handler !=
4607 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004608 {
cristyacd2ed22011-08-30 01:44:23 +00004609 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004610 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004611 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004612 }
cristy2036f5c2010-09-19 21:18:17 +00004613 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004614 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4615 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004616 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004617}
4618
4619/*
4620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4621% %
4622% %
4623% %
cristy4c08aed2011-07-01 19:47:50 +00004624+ 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 +00004625% %
4626% %
4627% %
4628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4629%
cristy4c08aed2011-07-01 19:47:50 +00004630% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004631% the pixel cache.
4632%
cristy4c08aed2011-07-01 19:47:50 +00004633% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004634%
cristy4c08aed2011-07-01 19:47:50 +00004635% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004636% NexusInfo *nexus_info,ExceptionInfo *exception)
4637%
4638% A description of each parameter follows:
4639%
4640% o cache_info: the pixel cache.
4641%
cristy4c08aed2011-07-01 19:47:50 +00004642% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004643%
4644% o exception: return any errors or warnings in this structure.
4645%
4646*/
cristy4c08aed2011-07-01 19:47:50 +00004647static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004648 NexusInfo *nexus_info,ExceptionInfo *exception)
4649{
4650 MagickOffsetType
4651 count,
4652 offset;
4653
4654 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004655 extent,
4656 length;
cristy3ed852e2009-09-05 21:47:34 +00004657
cristybb503372010-05-27 20:51:26 +00004658 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004659 y;
4660
cristy4c08aed2011-07-01 19:47:50 +00004661 register unsigned char
4662 *restrict q;
4663
cristybb503372010-05-27 20:51:26 +00004664 size_t
cristy3ed852e2009-09-05 21:47:34 +00004665 rows;
4666
cristy4c08aed2011-07-01 19:47:50 +00004667 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004668 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004669 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004670 return(MagickTrue);
4671 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4672 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004673 length=(MagickSizeType) nexus_info->region.width*
4674 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004675 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004676 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004677 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004678 switch (cache_info->type)
4679 {
4680 case MemoryCache:
4681 case MapCache:
4682 {
cristy4c08aed2011-07-01 19:47:50 +00004683 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004684 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004685
4686 /*
cristy4c08aed2011-07-01 19:47:50 +00004687 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004688 */
cristydd341db2010-03-04 19:06:38 +00004689 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004690 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004691 {
cristy48078b12010-09-23 17:11:01 +00004692 length=extent;
cristydd341db2010-03-04 19:06:38 +00004693 rows=1UL;
4694 }
cristy4c08aed2011-07-01 19:47:50 +00004695 p=(unsigned char *) cache_info->metacontent+offset*
4696 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004697 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004698 {
cristy8f036fe2010-09-18 02:02:00 +00004699 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004700 p+=cache_info->metacontent_extent*cache_info->columns;
4701 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004702 }
4703 break;
4704 }
4705 case DiskCache:
4706 {
4707 /*
cristy4c08aed2011-07-01 19:47:50 +00004708 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004709 */
4710 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4711 {
4712 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4713 cache_info->cache_filename);
4714 return(MagickFalse);
4715 }
cristydd341db2010-03-04 19:06:38 +00004716 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004717 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004718 {
cristy48078b12010-09-23 17:11:01 +00004719 length=extent;
cristydd341db2010-03-04 19:06:38 +00004720 rows=1UL;
4721 }
cristy48078b12010-09-23 17:11:01 +00004722 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004723 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004724 {
cristy48078b12010-09-23 17:11:01 +00004725 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004726 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004727 cache_info->metacontent_extent,length,(unsigned char *) q);
4728 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004729 break;
4730 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004731 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004732 }
cristybb503372010-05-27 20:51:26 +00004733 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004734 {
4735 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4736 cache_info->cache_filename);
4737 return(MagickFalse);
4738 }
4739 break;
4740 }
4741 default:
4742 break;
4743 }
4744 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004745 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004746 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004747 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004748 nexus_info->region.width,(double) nexus_info->region.height,(double)
4749 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004750 return(MagickTrue);
4751}
4752
4753/*
4754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4755% %
4756% %
4757% %
4758+ R e a d P i x e l C a c h e P i x e l s %
4759% %
4760% %
4761% %
4762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4763%
4764% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4765% cache.
4766%
4767% The format of the ReadPixelCachePixels() method is:
4768%
4769% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4770% NexusInfo *nexus_info,ExceptionInfo *exception)
4771%
4772% A description of each parameter follows:
4773%
4774% o cache_info: the pixel cache.
4775%
4776% o nexus_info: the cache nexus to read the pixels.
4777%
4778% o exception: return any errors or warnings in this structure.
4779%
4780*/
4781static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4782 NexusInfo *nexus_info,ExceptionInfo *exception)
4783{
4784 MagickOffsetType
4785 count,
4786 offset;
4787
4788 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004789 extent,
4790 length;
cristy3ed852e2009-09-05 21:47:34 +00004791
cristy4c08aed2011-07-01 19:47:50 +00004792 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004793 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004794
cristye076a6e2010-08-15 19:59:43 +00004795 register ssize_t
4796 y;
4797
cristybb503372010-05-27 20:51:26 +00004798 size_t
cristy3ed852e2009-09-05 21:47:34 +00004799 rows;
4800
cristy4c08aed2011-07-01 19:47:50 +00004801 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004802 return(MagickTrue);
4803 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4804 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004805 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004806 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004807 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004808 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004809 q=nexus_info->pixels;
4810 switch (cache_info->type)
4811 {
4812 case MemoryCache:
4813 case MapCache:
4814 {
cristy4c08aed2011-07-01 19:47:50 +00004815 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004816 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004817
4818 /*
4819 Read pixels from memory.
4820 */
cristydd341db2010-03-04 19:06:38 +00004821 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004822 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004823 {
cristy48078b12010-09-23 17:11:01 +00004824 length=extent;
cristydd341db2010-03-04 19:06:38 +00004825 rows=1UL;
4826 }
cristyed231572011-07-14 02:18:59 +00004827 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004828 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004829 {
cristy8f036fe2010-09-18 02:02:00 +00004830 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004831 p+=cache_info->number_channels*cache_info->columns;
4832 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004833 }
4834 break;
4835 }
4836 case DiskCache:
4837 {
4838 /*
4839 Read pixels from disk.
4840 */
4841 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4842 {
4843 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4844 cache_info->cache_filename);
4845 return(MagickFalse);
4846 }
cristydd341db2010-03-04 19:06:38 +00004847 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004848 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004849 {
cristy48078b12010-09-23 17:11:01 +00004850 length=extent;
cristydd341db2010-03-04 19:06:38 +00004851 rows=1UL;
4852 }
cristybb503372010-05-27 20:51:26 +00004853 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004854 {
4855 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004856 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004857 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004858 break;
4859 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004860 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004861 }
cristybb503372010-05-27 20:51:26 +00004862 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004863 {
4864 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4865 cache_info->cache_filename);
4866 return(MagickFalse);
4867 }
4868 break;
4869 }
4870 default:
4871 break;
4872 }
4873 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004874 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004875 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004876 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004877 nexus_info->region.width,(double) nexus_info->region.height,(double)
4878 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004879 return(MagickTrue);
4880}
4881
4882/*
4883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4884% %
4885% %
4886% %
4887+ R e f e r e n c e P i x e l C a c h e %
4888% %
4889% %
4890% %
4891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4892%
4893% ReferencePixelCache() increments the reference count associated with the
4894% pixel cache returning a pointer to the cache.
4895%
4896% The format of the ReferencePixelCache method is:
4897%
4898% Cache ReferencePixelCache(Cache cache_info)
4899%
4900% A description of each parameter follows:
4901%
4902% o cache_info: the pixel cache.
4903%
4904*/
cristya6577ff2011-09-02 19:54:26 +00004905MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004906{
4907 CacheInfo
4908 *cache_info;
4909
4910 assert(cache != (Cache *) NULL);
4911 cache_info=(CacheInfo *) cache;
4912 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004913 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004914 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004915 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004916 return(cache_info);
4917}
4918
4919/*
4920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4921% %
4922% %
4923% %
4924+ S e t P i x e l C a c h e M e t h o d s %
4925% %
4926% %
4927% %
4928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4929%
4930% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4931%
4932% The format of the SetPixelCacheMethods() method is:
4933%
4934% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4935%
4936% A description of each parameter follows:
4937%
4938% o cache: the pixel cache.
4939%
4940% o cache_methods: Specifies a pointer to a CacheMethods structure.
4941%
4942*/
cristya6577ff2011-09-02 19:54:26 +00004943MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004944{
4945 CacheInfo
4946 *cache_info;
4947
4948 GetOneAuthenticPixelFromHandler
4949 get_one_authentic_pixel_from_handler;
4950
4951 GetOneVirtualPixelFromHandler
4952 get_one_virtual_pixel_from_handler;
4953
4954 /*
4955 Set cache pixel methods.
4956 */
4957 assert(cache != (Cache) NULL);
4958 assert(cache_methods != (CacheMethods *) NULL);
4959 cache_info=(CacheInfo *) cache;
4960 assert(cache_info->signature == MagickSignature);
4961 if (cache_info->debug != MagickFalse)
4962 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4963 cache_info->filename);
4964 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4965 cache_info->methods.get_virtual_pixel_handler=
4966 cache_methods->get_virtual_pixel_handler;
4967 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4968 cache_info->methods.destroy_pixel_handler=
4969 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004970 if (cache_methods->get_virtual_metacontent_from_handler !=
4971 (GetVirtualMetacontentFromHandler) NULL)
4972 cache_info->methods.get_virtual_metacontent_from_handler=
4973 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004974 if (cache_methods->get_authentic_pixels_handler !=
4975 (GetAuthenticPixelsHandler) NULL)
4976 cache_info->methods.get_authentic_pixels_handler=
4977 cache_methods->get_authentic_pixels_handler;
4978 if (cache_methods->queue_authentic_pixels_handler !=
4979 (QueueAuthenticPixelsHandler) NULL)
4980 cache_info->methods.queue_authentic_pixels_handler=
4981 cache_methods->queue_authentic_pixels_handler;
4982 if (cache_methods->sync_authentic_pixels_handler !=
4983 (SyncAuthenticPixelsHandler) NULL)
4984 cache_info->methods.sync_authentic_pixels_handler=
4985 cache_methods->sync_authentic_pixels_handler;
4986 if (cache_methods->get_authentic_pixels_from_handler !=
4987 (GetAuthenticPixelsFromHandler) NULL)
4988 cache_info->methods.get_authentic_pixels_from_handler=
4989 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004990 if (cache_methods->get_authentic_metacontent_from_handler !=
4991 (GetAuthenticMetacontentFromHandler) NULL)
4992 cache_info->methods.get_authentic_metacontent_from_handler=
4993 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004994 get_one_virtual_pixel_from_handler=
4995 cache_info->methods.get_one_virtual_pixel_from_handler;
4996 if (get_one_virtual_pixel_from_handler !=
4997 (GetOneVirtualPixelFromHandler) NULL)
4998 cache_info->methods.get_one_virtual_pixel_from_handler=
4999 cache_methods->get_one_virtual_pixel_from_handler;
5000 get_one_authentic_pixel_from_handler=
5001 cache_methods->get_one_authentic_pixel_from_handler;
5002 if (get_one_authentic_pixel_from_handler !=
5003 (GetOneAuthenticPixelFromHandler) NULL)
5004 cache_info->methods.get_one_authentic_pixel_from_handler=
5005 cache_methods->get_one_authentic_pixel_from_handler;
5006}
5007
5008/*
5009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5010% %
5011% %
5012% %
5013+ S e t P i x e l C a c h e N e x u s P i x e l s %
5014% %
5015% %
5016% %
5017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5018%
5019% SetPixelCacheNexusPixels() defines the region of the cache for the
5020% specified cache nexus.
5021%
5022% The format of the SetPixelCacheNexusPixels() method is:
5023%
cristy4c08aed2011-07-01 19:47:50 +00005024% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005025% const RectangleInfo *region,NexusInfo *nexus_info,
5026% ExceptionInfo *exception)
5027%
5028% A description of each parameter follows:
5029%
5030% o image: the image.
5031%
5032% o region: A pointer to the RectangleInfo structure that defines the
5033% region of this particular cache nexus.
5034%
5035% o nexus_info: the cache nexus to set.
5036%
5037% o exception: return any errors or warnings in this structure.
5038%
5039*/
cristyabd6e372010-09-15 19:11:26 +00005040
5041static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5042 NexusInfo *nexus_info,ExceptionInfo *exception)
5043{
5044 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5045 return(MagickFalse);
5046 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005047 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005048 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005049 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005050 {
5051 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005052 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005053 nexus_info->length);
5054 }
cristy4c08aed2011-07-01 19:47:50 +00005055 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005056 {
5057 (void) ThrowMagickException(exception,GetMagickModule(),
5058 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5059 cache_info->filename);
5060 return(MagickFalse);
5061 }
5062 return(MagickTrue);
5063}
5064
cristy4c08aed2011-07-01 19:47:50 +00005065static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005066 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5067{
5068 CacheInfo
5069 *cache_info;
5070
5071 MagickBooleanType
5072 status;
5073
cristy3ed852e2009-09-05 21:47:34 +00005074 MagickSizeType
5075 length,
5076 number_pixels;
5077
cristy3ed852e2009-09-05 21:47:34 +00005078 cache_info=(CacheInfo *) image->cache;
5079 assert(cache_info->signature == MagickSignature);
5080 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005081 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005082 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005083 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5084 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005085 {
cristybb503372010-05-27 20:51:26 +00005086 ssize_t
cristybad067a2010-02-15 17:20:55 +00005087 x,
5088 y;
cristy3ed852e2009-09-05 21:47:34 +00005089
cristyeaedf062010-05-29 22:36:02 +00005090 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5091 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005092 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5093 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005094 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005095 ((nexus_info->region.width == cache_info->columns) ||
5096 ((nexus_info->region.width % cache_info->columns) == 0)))))
5097 {
5098 MagickOffsetType
5099 offset;
5100
5101 /*
5102 Pixels are accessed directly from memory.
5103 */
5104 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5105 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005106 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005107 offset;
5108 nexus_info->metacontent=(void *) NULL;
5109 if (cache_info->metacontent_extent != 0)
5110 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5111 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005112 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005113 }
5114 }
5115 /*
5116 Pixels are stored in a cache region until they are synced to the cache.
5117 */
5118 number_pixels=(MagickSizeType) nexus_info->region.width*
5119 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005120 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005121 if (cache_info->metacontent_extent != 0)
5122 length+=number_pixels*cache_info->metacontent_extent;
5123 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005124 {
5125 nexus_info->length=length;
5126 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5127 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005128 {
5129 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005130 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005131 }
cristy3ed852e2009-09-05 21:47:34 +00005132 }
5133 else
5134 if (nexus_info->length != length)
5135 {
5136 RelinquishCacheNexusPixels(nexus_info);
5137 nexus_info->length=length;
5138 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5139 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005140 {
5141 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005142 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005143 }
cristy3ed852e2009-09-05 21:47:34 +00005144 }
5145 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005146 nexus_info->metacontent=(void *) NULL;
5147 if (cache_info->metacontent_extent != 0)
5148 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005149 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005150 return(nexus_info->pixels);
5151}
5152
5153/*
5154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5155% %
5156% %
5157% %
5158% 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 %
5159% %
5160% %
5161% %
5162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5163%
5164% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5165% pixel cache and returns the previous setting. A virtual pixel is any pixel
5166% access that is outside the boundaries of the image cache.
5167%
5168% The format of the SetPixelCacheVirtualMethod() method is:
5169%
5170% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5171% const VirtualPixelMethod virtual_pixel_method)
5172%
5173% A description of each parameter follows:
5174%
5175% o image: the image.
5176%
5177% o virtual_pixel_method: choose the type of virtual pixel.
5178%
5179*/
cristyd1dd6e42011-09-04 01:46:08 +00005180MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005181 const VirtualPixelMethod virtual_pixel_method)
5182{
5183 CacheInfo
5184 *cache_info;
5185
5186 VirtualPixelMethod
5187 method;
5188
5189 assert(image != (Image *) NULL);
5190 assert(image->signature == MagickSignature);
5191 if (image->debug != MagickFalse)
5192 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5193 assert(image->cache != (Cache) NULL);
5194 cache_info=(CacheInfo *) image->cache;
5195 assert(cache_info->signature == MagickSignature);
5196 method=cache_info->virtual_pixel_method;
5197 cache_info->virtual_pixel_method=virtual_pixel_method;
5198 return(method);
5199}
5200
5201/*
5202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5203% %
5204% %
5205% %
5206+ 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 %
5207% %
5208% %
5209% %
5210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5211%
5212% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5213% in-memory or disk cache. The method returns MagickTrue if the pixel region
5214% is synced, otherwise MagickFalse.
5215%
5216% The format of the SyncAuthenticPixelCacheNexus() method is:
5217%
5218% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5219% NexusInfo *nexus_info,ExceptionInfo *exception)
5220%
5221% A description of each parameter follows:
5222%
5223% o image: the image.
5224%
5225% o nexus_info: the cache nexus to sync.
5226%
5227% o exception: return any errors or warnings in this structure.
5228%
5229*/
cristya6577ff2011-09-02 19:54:26 +00005230MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005231 NexusInfo *nexus_info,ExceptionInfo *exception)
5232{
5233 CacheInfo
5234 *cache_info;
5235
5236 MagickBooleanType
5237 status;
5238
5239 /*
5240 Transfer pixels to the cache.
5241 */
5242 assert(image != (Image *) NULL);
5243 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005244 if (image->cache == (Cache) NULL)
5245 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5246 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005247 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005248 if (cache_info->type == UndefinedCache)
5249 return(MagickFalse);
5250 if ((image->clip_mask != (Image *) NULL) &&
5251 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5252 return(MagickFalse);
5253 if ((image->mask != (Image *) NULL) &&
5254 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5255 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005256 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005257 return(MagickTrue);
5258 assert(cache_info->signature == MagickSignature);
5259 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005260 if ((cache_info->metacontent_extent != 0) &&
5261 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005262 return(MagickFalse);
5263 return(status);
5264}
5265
5266/*
5267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5268% %
5269% %
5270% %
5271+ S y n c A u t h e n t i c P i x e l C a c h e %
5272% %
5273% %
5274% %
5275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5276%
5277% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5278% or disk cache. The method returns MagickTrue if the pixel region is synced,
5279% otherwise MagickFalse.
5280%
5281% The format of the SyncAuthenticPixelsCache() method is:
5282%
5283% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5284% ExceptionInfo *exception)
5285%
5286% A description of each parameter follows:
5287%
5288% o image: the image.
5289%
5290% o exception: return any errors or warnings in this structure.
5291%
5292*/
5293static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5294 ExceptionInfo *exception)
5295{
5296 CacheInfo
5297 *cache_info;
5298
cristy5c9e6f22010-09-17 17:31:01 +00005299 const int
5300 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005301
cristy4c08aed2011-07-01 19:47:50 +00005302 MagickBooleanType
5303 status;
5304
cristye7cc7cf2010-09-21 13:26:47 +00005305 assert(image != (Image *) NULL);
5306 assert(image->signature == MagickSignature);
5307 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005308 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005309 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005310 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005311 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5312 exception);
5313 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005314}
5315
5316/*
5317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5318% %
5319% %
5320% %
5321% S y n c A u t h e n t i c P i x e l s %
5322% %
5323% %
5324% %
5325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5326%
5327% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5328% The method returns MagickTrue if the pixel region is flushed, otherwise
5329% MagickFalse.
5330%
5331% The format of the SyncAuthenticPixels() method is:
5332%
5333% MagickBooleanType SyncAuthenticPixels(Image *image,
5334% ExceptionInfo *exception)
5335%
5336% A description of each parameter follows:
5337%
5338% o image: the image.
5339%
5340% o exception: return any errors or warnings in this structure.
5341%
5342*/
5343MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5344 ExceptionInfo *exception)
5345{
5346 CacheInfo
5347 *cache_info;
5348
cristy2036f5c2010-09-19 21:18:17 +00005349 const int
5350 id = GetOpenMPThreadId();
5351
cristy4c08aed2011-07-01 19:47:50 +00005352 MagickBooleanType
5353 status;
5354
cristy3ed852e2009-09-05 21:47:34 +00005355 assert(image != (Image *) NULL);
5356 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005357 assert(image->cache != (Cache) NULL);
5358 cache_info=(CacheInfo *) image->cache;
5359 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005360 if (cache_info->methods.sync_authentic_pixels_handler !=
5361 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005362 {
5363 status=cache_info->methods.sync_authentic_pixels_handler(image,
5364 exception);
5365 return(status);
5366 }
cristy2036f5c2010-09-19 21:18:17 +00005367 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005368 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5369 exception);
5370 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005371}
5372
5373/*
5374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5375% %
5376% %
5377% %
cristyd1dd6e42011-09-04 01:46:08 +00005378+ 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 +00005379% %
5380% %
5381% %
5382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5383%
5384% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5385% The method returns MagickTrue if the pixel region is flushed, otherwise
5386% MagickFalse.
5387%
5388% The format of the SyncImagePixelCache() method is:
5389%
5390% MagickBooleanType SyncImagePixelCache(Image *image,
5391% ExceptionInfo *exception)
5392%
5393% A description of each parameter follows:
5394%
5395% o image: the image.
5396%
5397% o exception: return any errors or warnings in this structure.
5398%
5399*/
cristyd1dd6e42011-09-04 01:46:08 +00005400MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005401 ExceptionInfo *exception)
5402{
5403 CacheInfo
5404 *cache_info;
5405
5406 assert(image != (Image *) NULL);
5407 assert(exception != (ExceptionInfo *) NULL);
5408 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5409 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5410}
5411
5412/*
5413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5414% %
5415% %
5416% %
cristy4c08aed2011-07-01 19:47:50 +00005417+ 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 +00005418% %
5419% %
5420% %
5421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5422%
cristy4c08aed2011-07-01 19:47:50 +00005423% WritePixelCacheMetacontent() writes the meta-content to the specified region
5424% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005425%
cristy4c08aed2011-07-01 19:47:50 +00005426% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005427%
cristy4c08aed2011-07-01 19:47:50 +00005428% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005429% NexusInfo *nexus_info,ExceptionInfo *exception)
5430%
5431% A description of each parameter follows:
5432%
5433% o cache_info: the pixel cache.
5434%
cristy4c08aed2011-07-01 19:47:50 +00005435% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005436%
5437% o exception: return any errors or warnings in this structure.
5438%
5439*/
cristy4c08aed2011-07-01 19:47:50 +00005440static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005441 NexusInfo *nexus_info,ExceptionInfo *exception)
5442{
5443 MagickOffsetType
5444 count,
5445 offset;
5446
5447 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005448 extent,
5449 length;
cristy3ed852e2009-09-05 21:47:34 +00005450
cristy4c08aed2011-07-01 19:47:50 +00005451 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005452 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005453
cristybb503372010-05-27 20:51:26 +00005454 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005455 y;
5456
cristybb503372010-05-27 20:51:26 +00005457 size_t
cristy3ed852e2009-09-05 21:47:34 +00005458 rows;
5459
cristy4c08aed2011-07-01 19:47:50 +00005460 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005461 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005462 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005463 return(MagickTrue);
5464 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5465 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005466 length=(MagickSizeType) nexus_info->region.width*
5467 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005468 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005469 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005470 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005471 switch (cache_info->type)
5472 {
5473 case MemoryCache:
5474 case MapCache:
5475 {
cristy4c08aed2011-07-01 19:47:50 +00005476 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005477 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005478
5479 /*
cristy4c08aed2011-07-01 19:47:50 +00005480 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005481 */
cristydd341db2010-03-04 19:06:38 +00005482 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005483 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005484 {
cristy48078b12010-09-23 17:11:01 +00005485 length=extent;
cristydd341db2010-03-04 19:06:38 +00005486 rows=1UL;
5487 }
cristy4c08aed2011-07-01 19:47:50 +00005488 q=(unsigned char *) cache_info->metacontent+offset*
5489 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005490 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005491 {
cristy8f036fe2010-09-18 02:02:00 +00005492 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005493 p+=nexus_info->region.width*cache_info->metacontent_extent;
5494 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005495 }
5496 break;
5497 }
5498 case DiskCache:
5499 {
5500 /*
cristy4c08aed2011-07-01 19:47:50 +00005501 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005502 */
5503 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5504 {
5505 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5506 cache_info->cache_filename);
5507 return(MagickFalse);
5508 }
cristydd341db2010-03-04 19:06:38 +00005509 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005510 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005511 {
cristy48078b12010-09-23 17:11:01 +00005512 length=extent;
cristydd341db2010-03-04 19:06:38 +00005513 rows=1UL;
5514 }
cristy48078b12010-09-23 17:11:01 +00005515 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005516 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005517 {
cristy48078b12010-09-23 17:11:01 +00005518 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005519 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005520 cache_info->metacontent_extent,length,(const unsigned char *) p);
5521 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005522 break;
cristy4c08aed2011-07-01 19:47:50 +00005523 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005524 offset+=cache_info->columns;
5525 }
cristybb503372010-05-27 20:51:26 +00005526 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005527 {
5528 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5529 cache_info->cache_filename);
5530 return(MagickFalse);
5531 }
5532 break;
5533 }
5534 default:
5535 break;
5536 }
5537 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005538 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005539 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005540 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005541 nexus_info->region.width,(double) nexus_info->region.height,(double)
5542 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005543 return(MagickTrue);
5544}
5545
5546/*
5547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5548% %
5549% %
5550% %
5551+ W r i t e C a c h e P i x e l s %
5552% %
5553% %
5554% %
5555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5556%
5557% WritePixelCachePixels() writes image pixels to the specified region of the
5558% pixel cache.
5559%
5560% The format of the WritePixelCachePixels() method is:
5561%
5562% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5563% NexusInfo *nexus_info,ExceptionInfo *exception)
5564%
5565% A description of each parameter follows:
5566%
5567% o cache_info: the pixel cache.
5568%
5569% o nexus_info: the cache nexus to write the pixels.
5570%
5571% o exception: return any errors or warnings in this structure.
5572%
5573*/
5574static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5575 NexusInfo *nexus_info,ExceptionInfo *exception)
5576{
5577 MagickOffsetType
5578 count,
5579 offset;
5580
5581 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005582 extent,
5583 length;
cristy3ed852e2009-09-05 21:47:34 +00005584
cristy4c08aed2011-07-01 19:47:50 +00005585 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005586 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005587
cristybb503372010-05-27 20:51:26 +00005588 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005589 y;
5590
cristybb503372010-05-27 20:51:26 +00005591 size_t
cristy3ed852e2009-09-05 21:47:34 +00005592 rows;
5593
cristy4c08aed2011-07-01 19:47:50 +00005594 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005595 return(MagickTrue);
5596 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5597 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005598 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005599 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005600 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005601 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005602 p=nexus_info->pixels;
5603 switch (cache_info->type)
5604 {
5605 case MemoryCache:
5606 case MapCache:
5607 {
cristy4c08aed2011-07-01 19:47:50 +00005608 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005609 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005610
5611 /*
5612 Write pixels to memory.
5613 */
cristydd341db2010-03-04 19:06:38 +00005614 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005615 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005616 {
cristy48078b12010-09-23 17:11:01 +00005617 length=extent;
cristydd341db2010-03-04 19:06:38 +00005618 rows=1UL;
5619 }
cristyed231572011-07-14 02:18:59 +00005620 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005621 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005622 {
cristy8f036fe2010-09-18 02:02:00 +00005623 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005624 p+=nexus_info->region.width*cache_info->number_channels;
5625 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005626 }
5627 break;
5628 }
5629 case DiskCache:
5630 {
5631 /*
5632 Write pixels to disk.
5633 */
5634 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5635 {
5636 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5637 cache_info->cache_filename);
5638 return(MagickFalse);
5639 }
cristydd341db2010-03-04 19:06:38 +00005640 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005641 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005642 {
cristy48078b12010-09-23 17:11:01 +00005643 length=extent;
cristydd341db2010-03-04 19:06:38 +00005644 rows=1UL;
5645 }
cristybb503372010-05-27 20:51:26 +00005646 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005647 {
5648 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005649 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005650 p);
5651 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005652 break;
cristyed231572011-07-14 02:18:59 +00005653 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005654 offset+=cache_info->columns;
5655 }
cristybb503372010-05-27 20:51:26 +00005656 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005657 {
5658 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5659 cache_info->cache_filename);
5660 return(MagickFalse);
5661 }
5662 break;
5663 }
5664 default:
5665 break;
5666 }
5667 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005668 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005669 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005670 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005671 nexus_info->region.width,(double) nexus_info->region.height,(double)
5672 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005673 return(MagickTrue);
5674}