blob: 443cddfc7c53f94de749d700454d7a89a8311982 [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;
673 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000674 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000675 return(MagickTrue);
676}
677
678static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
679 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000680 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000681{
682 register MagickOffsetType
683 i;
684
685 ssize_t
686 count;
687
cristy08a88202010-03-04 19:18:05 +0000688 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000689#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000690 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000691 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristyf84a1932010-01-03 18:00:18 +0000693 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 return((MagickOffsetType) -1);
695 }
696#endif
697 count=0;
698 for (i=0; i < (MagickOffsetType) length; i+=count)
699 {
700#if !defined(MAGICKCORE_HAVE_PREAD)
701 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX));
703#else
704 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000705 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000706#endif
707 if (count > 0)
708 continue;
709 count=0;
710 if (errno != EINTR)
711 {
712 i=(-1);
713 break;
714 }
715 }
716#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000717 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000718#endif
719 return(i);
720}
721
722static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
723 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000724 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000725{
726 register MagickOffsetType
727 i;
728
729 ssize_t
730 count;
731
cristy08a88202010-03-04 19:18:05 +0000732 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000733#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000734 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000735 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000736 {
cristyf84a1932010-01-03 18:00:18 +0000737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 return((MagickOffsetType) -1);
739 }
740#endif
741 count=0;
742 for (i=0; i < (MagickOffsetType) length; i+=count)
743 {
744#if !defined(MAGICKCORE_HAVE_PWRITE)
745 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX));
747#else
748 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000749 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000750#endif
751 if (count > 0)
752 continue;
753 count=0;
754 if (errno != EINTR)
755 {
756 i=(-1);
757 break;
758 }
759 }
760#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000761 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000762#endif
763 return(i);
764}
765
cristy4c08aed2011-07-01 19:47:50 +0000766static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000767 CacheInfo *cache_info,ExceptionInfo *exception)
768{
769 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000770 count;
cristy3ed852e2009-09-05 21:47:34 +0000771
cristy4c08aed2011-07-01 19:47:50 +0000772 register MagickOffsetType
773 i;
cristye076a6e2010-08-15 19:59:43 +0000774
cristybb503372010-05-27 20:51:26 +0000775 size_t
cristy4c08aed2011-07-01 19:47:50 +0000776 length;
cristy3ed852e2009-09-05 21:47:34 +0000777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
780
781 /*
782 Clone pixel cache (both caches on disk).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000786 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000787 sizeof(*blob));
788 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000789 {
cristy4c08aed2011-07-01 19:47:50 +0000790 (void) ThrowMagickException(exception,GetMagickModule(),
791 ResourceLimitError,"MemoryAllocationFailed","`%s'",
792 cache_info->filename);
793 return(MagickFalse);
794 }
cristy3dedf062011-07-02 14:07:40 +0000795 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000796 {
797 blob=(unsigned char *) RelinquishMagickMemory(blob);
798 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
799 cache_info->cache_filename);
800 return(MagickFalse);
801 }
cristy3dedf062011-07-02 14:07:40 +0000802 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000803 {
804 (void) ClosePixelCacheOnDisk(cache_info);
805 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000806 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
807 clone_info->cache_filename);
808 return(MagickFalse);
809 }
cristy4c08aed2011-07-01 19:47:50 +0000810 count=0;
811 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
814 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
815 blob);
816 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000817 {
cristy4c08aed2011-07-01 19:47:50 +0000818 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
819 cache_info->cache_filename);
820 break;
cristy3ed852e2009-09-05 21:47:34 +0000821 }
cristy4c08aed2011-07-01 19:47:50 +0000822 length=(size_t) count;
823 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
824 if ((MagickSizeType) count != length)
825 {
826 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
827 clone_info->cache_filename);
828 break;
829 }
830 }
831 (void) ClosePixelCacheOnDisk(clone_info);
832 (void) ClosePixelCacheOnDisk(cache_info);
833 blob=(unsigned char *) RelinquishMagickMemory(blob);
834 if (i < (MagickOffsetType) cache_info->length)
835 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000836 return(MagickTrue);
837}
838
cristy4c08aed2011-07-01 19:47:50 +0000839static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000840 CacheInfo *cache_info,ExceptionInfo *exception)
841{
842 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000843 count;
cristy3ed852e2009-09-05 21:47:34 +0000844
cristy4c08aed2011-07-01 19:47:50 +0000845 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000846 {
cristy3ed852e2009-09-05 21:47:34 +0000847 /*
cristy4c08aed2011-07-01 19:47:50 +0000848 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000849 */
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->debug != MagickFalse)
851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
852 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
853 cache_info->length);
854 return(MagickTrue);
855 }
856 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
857 {
858 /*
859 Clone pixel cache (one cache on disk, one in memory).
860 */
861 if (cache_info->debug != MagickFalse)
862 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
863 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy4c08aed2011-07-01 19:47:50 +0000865 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000866 cache_info->cache_filename);
867 return(MagickFalse);
868 }
cristy4c08aed2011-07-01 19:47:50 +0000869 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
870 cache_info->length,(unsigned char *) clone_info->pixels);
871 (void) ClosePixelCacheOnDisk(cache_info);
872 if ((MagickSizeType) count != cache_info->length)
873 {
874 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
875 cache_info->cache_filename);
876 return(MagickFalse);
877 }
878 return(MagickTrue);
879 }
880 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
881 {
882 /*
883 Clone pixel cache (one cache on disk, one in memory).
884 */
885 if (clone_info->debug != MagickFalse)
886 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
887 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
888 {
889 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
890 clone_info->cache_filename);
891 return(MagickFalse);
892 }
893 count=WritePixelCacheRegion(clone_info,clone_info->offset,
894 clone_info->length,(unsigned char *) cache_info->pixels);
895 (void) ClosePixelCacheOnDisk(clone_info);
896 if ((MagickSizeType) count != clone_info->length)
897 {
898 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
899 clone_info->cache_filename);
900 return(MagickFalse);
901 }
902 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000903 }
904 /*
cristy4c08aed2011-07-01 19:47:50 +0000905 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000906 */
cristy4c08aed2011-07-01 19:47:50 +0000907 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000908}
909
cristy4c08aed2011-07-01 19:47:50 +0000910static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000911 CacheInfo *cache_info,ExceptionInfo *exception)
912{
cristy4c08aed2011-07-01 19:47:50 +0000913 MagickBooleanType
914 status;
cristy3ed852e2009-09-05 21:47:34 +0000915
cristy4c08aed2011-07-01 19:47:50 +0000916 MagickOffsetType
917 cache_offset,
918 clone_offset,
919 count;
920
921 register ssize_t
922 x;
923
924 size_t
cristy3ed852e2009-09-05 21:47:34 +0000925 length;
926
cristy4c08aed2011-07-01 19:47:50 +0000927 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000928 y;
929
cristy4c08aed2011-07-01 19:47:50 +0000930 unsigned char
931 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000932
cristy4c08aed2011-07-01 19:47:50 +0000933 /*
934 Clone pixel cache (unoptimized).
935 */
cristy3ed852e2009-09-05 21:47:34 +0000936 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000937 {
cristy4c08aed2011-07-01 19:47:50 +0000938 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
939 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
940 else
941 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
942 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
943 else
944 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
946 else
947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
948 }
cristyed231572011-07-14 02:18:59 +0000949 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
950 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000951 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000952 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000953 if (blob == (unsigned char *) NULL)
954 {
955 (void) ThrowMagickException(exception,GetMagickModule(),
956 ResourceLimitError,"MemoryAllocationFailed","`%s'",
957 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000958 return(MagickFalse);
959 }
cristy4c08aed2011-07-01 19:47:50 +0000960 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
961 cache_offset=0;
962 clone_offset=0;
963 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000964 {
cristy4c08aed2011-07-01 19:47:50 +0000965 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
cristy4c08aed2011-07-01 19:47:50 +0000967 blob=(unsigned char *) RelinquishMagickMemory(blob);
968 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
cristy4c08aed2011-07-01 19:47:50 +0000972 cache_offset=cache_info->offset;
973 }
cristy32cacff2011-12-31 03:36:27 +0000974 if ((cache_info->type != MemoryCache) && (clone_info->type != MemoryCache) &&
975 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
976 {
977 /*
978 Inplace cloning not reliable.
979 */
980 (void) ClosePixelCacheOnDisk(clone_info);
981 if (cache_info->type == MapCache)
982 {
983 clone_info->pixels=(Quantum *) UnmapBlob(clone_info->pixels,(size_t)
984 clone_info->length);
985 RelinquishMagickResource(MapResource,clone_info->length);
986 }
987 *clone_info->cache_filename='\0';
988 clone_info->type=DiskCache;
989 }
cristy4c08aed2011-07-01 19:47:50 +0000990 if (clone_info->type == DiskCache)
991 {
cristy3dedf062011-07-02 14:07:40 +0000992 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000993 {
cristy4c08aed2011-07-01 19:47:50 +0000994 if (cache_info->type == DiskCache)
995 (void) ClosePixelCacheOnDisk(cache_info);
996 blob=(unsigned char *) RelinquishMagickMemory(blob);
997 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
998 clone_info->cache_filename);
999 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001000 }
cristy4c08aed2011-07-01 19:47:50 +00001001 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +00001002 }
1003 /*
cristy4c08aed2011-07-01 19:47:50 +00001004 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001005 */
cristy4c08aed2011-07-01 19:47:50 +00001006 status=MagickTrue;
1007 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001008 {
cristy4c08aed2011-07-01 19:47:50 +00001009 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001010 {
cristy9e0719b2011-12-29 03:45:45 +00001011 register ssize_t
1012 i;
1013
cristy3ed852e2009-09-05 21:47:34 +00001014 /*
cristy4c08aed2011-07-01 19:47:50 +00001015 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001016 */
cristyed231572011-07-14 02:18:59 +00001017 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001018 if (cache_info->type != DiskCache)
1019 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1020 length);
cristy3ed852e2009-09-05 21:47:34 +00001021 else
1022 {
cristy4c08aed2011-07-01 19:47:50 +00001023 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1024 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001025 {
cristy4c08aed2011-07-01 19:47:50 +00001026 status=MagickFalse;
1027 break;
cristy3ed852e2009-09-05 21:47:34 +00001028 }
1029 }
cristy4c08aed2011-07-01 19:47:50 +00001030 cache_offset+=length;
1031 if ((y < (ssize_t) clone_info->rows) &&
1032 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001033 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001034 {
cristy9e0719b2011-12-29 03:45:45 +00001035 PixelChannel
1036 channel;
1037
1038 PixelTrait
1039 traits;
1040
1041 ssize_t
1042 offset;
1043
cristy4c08aed2011-07-01 19:47:50 +00001044 /*
cristy3b8fe922011-12-29 18:56:23 +00001045 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001046 */
cristy9e0719b2011-12-29 03:45:45 +00001047 channel=clone_info->channel_map[i].channel;
1048 traits=cache_info->channel_map[channel].traits;
1049 if (traits == UndefinedPixelTrait)
1050 {
1051 clone_offset+=sizeof(Quantum);
1052 continue;
1053 }
1054 offset=cache_info->channel_map[channel].offset;
cristy4c08aed2011-07-01 19:47:50 +00001055 if (clone_info->type != DiskCache)
1056 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristy9e0719b2011-12-29 03:45:45 +00001057 blob+offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +00001058 else
1059 {
cristy9e0719b2011-12-29 03:45:45 +00001060 count=WritePixelCacheRegion(clone_info,clone_offset,
1061 sizeof(Quantum),blob+offset*sizeof(Quantum));
1062 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +00001063 {
1064 status=MagickFalse;
1065 break;
1066 }
1067 }
cristy9e0719b2011-12-29 03:45:45 +00001068 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001069 }
1070 }
cristyed231572011-07-14 02:18:59 +00001071 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001072 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1073 for ( ; x < (ssize_t) clone_info->columns; x++)
1074 {
1075 /*
cristy9e0719b2011-12-29 03:45:45 +00001076 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001077 */
1078 if (clone_info->type != DiskCache)
1079 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1080 length);
1081 else
1082 {
1083 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1084 if ((MagickSizeType) count != length)
1085 {
1086 status=MagickFalse;
1087 break;
1088 }
1089 }
1090 clone_offset+=length;
1091 }
1092 }
cristyed231572011-07-14 02:18:59 +00001093 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001094 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1095 for ( ; y < (ssize_t) clone_info->rows; y++)
1096 {
1097 /*
cristy9e0719b2011-12-29 03:45:45 +00001098 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001099 */
1100 for (x=0; x < (ssize_t) clone_info->columns; x++)
1101 {
1102 if (clone_info->type != DiskCache)
1103 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1104 length);
1105 else
1106 {
1107 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1108 if ((MagickSizeType) count != length)
1109 {
1110 status=MagickFalse;
1111 break;
1112 }
1113 }
1114 clone_offset+=length;
1115 }
1116 }
cristy9e0719b2011-12-29 03:45:45 +00001117 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001118 (clone_info->metacontent_extent != 0))
1119 {
1120 /*
1121 Clone metacontent.
1122 */
1123 for (y=0; y < (ssize_t) cache_info->rows; y++)
1124 {
1125 for (x=0; x < (ssize_t) cache_info->columns; x++)
1126 {
1127 /*
1128 Read a set of metacontent.
1129 */
1130 length=cache_info->metacontent_extent;
1131 if (cache_info->type != DiskCache)
1132 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1133 cache_offset,length);
1134 else
1135 {
1136 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1137 if ((MagickSizeType) count != length)
1138 {
1139 status=MagickFalse;
1140 break;
1141 }
1142 }
1143 cache_offset+=length;
1144 if ((y < (ssize_t) clone_info->rows) &&
1145 (x < (ssize_t) clone_info->columns))
1146 {
1147 /*
1148 Write a set of metacontent.
1149 */
1150 length=clone_info->metacontent_extent;
1151 if (clone_info->type != DiskCache)
1152 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1153 blob,length);
1154 else
1155 {
1156 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1157 blob);
1158 if ((MagickSizeType) count != length)
1159 {
1160 status=MagickFalse;
1161 break;
1162 }
1163 }
1164 clone_offset+=length;
1165 }
1166 }
1167 length=clone_info->metacontent_extent;
1168 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1169 for ( ; x < (ssize_t) clone_info->columns; x++)
1170 {
1171 /*
cristy9e0719b2011-12-29 03:45:45 +00001172 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001173 */
1174 if (clone_info->type != DiskCache)
1175 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1176 blob,length);
1177 else
1178 {
cristy208b1002011-08-07 18:51:50 +00001179 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001180 if ((MagickSizeType) count != length)
1181 {
1182 status=MagickFalse;
1183 break;
1184 }
1185 }
1186 clone_offset+=length;
1187 }
1188 }
1189 length=clone_info->metacontent_extent;
1190 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1191 for ( ; y < (ssize_t) clone_info->rows; y++)
1192 {
1193 /*
cristy9e0719b2011-12-29 03:45:45 +00001194 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001195 */
1196 for (x=0; x < (ssize_t) clone_info->columns; x++)
1197 {
1198 if (clone_info->type != DiskCache)
1199 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1200 blob,length);
1201 else
1202 {
1203 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1204 if ((MagickSizeType) count != length)
1205 {
1206 status=MagickFalse;
1207 break;
1208 }
1209 }
1210 clone_offset+=length;
1211 }
1212 }
1213 }
1214 if (clone_info->type == DiskCache)
1215 (void) ClosePixelCacheOnDisk(clone_info);
1216 if (cache_info->type == DiskCache)
1217 (void) ClosePixelCacheOnDisk(cache_info);
1218 blob=(unsigned char *) RelinquishMagickMemory(blob);
1219 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001220}
1221
1222static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1223 CacheInfo *cache_info,ExceptionInfo *exception)
1224{
cristy3dfccb22011-12-28 21:47:20 +00001225 PixelChannelMap
1226 *p,
1227 *q;
1228
cristy5a7fbfb2010-11-06 16:10:59 +00001229 if (cache_info->type == PingCache)
1230 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001231 p=cache_info->channel_map;
1232 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001233 if ((cache_info->columns == clone_info->columns) &&
1234 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001235 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001236 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001237 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1238 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1239 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001240}
1241
1242/*
1243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1244% %
1245% %
1246% %
1247+ C l o n e P i x e l C a c h e M e t h o d s %
1248% %
1249% %
1250% %
1251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252%
1253% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1254% another.
1255%
1256% The format of the ClonePixelCacheMethods() method is:
1257%
1258% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1259%
1260% A description of each parameter follows:
1261%
1262% o clone: Specifies a pointer to a Cache structure.
1263%
1264% o cache: the pixel cache.
1265%
1266*/
cristya6577ff2011-09-02 19:54:26 +00001267MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001268{
1269 CacheInfo
1270 *cache_info,
1271 *source_info;
1272
1273 assert(clone != (Cache) NULL);
1274 source_info=(CacheInfo *) clone;
1275 assert(source_info->signature == MagickSignature);
1276 if (source_info->debug != MagickFalse)
1277 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1278 source_info->filename);
1279 assert(cache != (Cache) NULL);
1280 cache_info=(CacheInfo *) cache;
1281 assert(cache_info->signature == MagickSignature);
1282 source_info->methods=cache_info->methods;
1283}
1284
1285/*
1286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1287% %
1288% %
1289% %
1290+ D e s t r o y I m a g e P i x e l C a c h e %
1291% %
1292% %
1293% %
1294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1295%
1296% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1297%
1298% The format of the DestroyImagePixelCache() method is:
1299%
1300% void DestroyImagePixelCache(Image *image)
1301%
1302% A description of each parameter follows:
1303%
1304% o image: the image.
1305%
1306*/
1307static void DestroyImagePixelCache(Image *image)
1308{
1309 assert(image != (Image *) NULL);
1310 assert(image->signature == MagickSignature);
1311 if (image->debug != MagickFalse)
1312 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1313 if (image->cache == (void *) NULL)
1314 return;
1315 image->cache=DestroyPixelCache(image->cache);
1316}
1317
1318/*
1319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1320% %
1321% %
1322% %
1323+ D e s t r o y I m a g e P i x e l s %
1324% %
1325% %
1326% %
1327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1328%
1329% DestroyImagePixels() deallocates memory associated with the pixel cache.
1330%
1331% The format of the DestroyImagePixels() method is:
1332%
1333% void DestroyImagePixels(Image *image)
1334%
1335% A description of each parameter follows:
1336%
1337% o image: the image.
1338%
1339*/
1340MagickExport void DestroyImagePixels(Image *image)
1341{
1342 CacheInfo
1343 *cache_info;
1344
1345 assert(image != (const Image *) NULL);
1346 assert(image->signature == MagickSignature);
1347 if (image->debug != MagickFalse)
1348 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1349 assert(image->cache != (Cache) NULL);
1350 cache_info=(CacheInfo *) image->cache;
1351 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001352 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1353 {
1354 cache_info->methods.destroy_pixel_handler(image);
1355 return;
1356 }
cristy2036f5c2010-09-19 21:18:17 +00001357 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001358}
1359
1360/*
1361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362% %
1363% %
1364% %
1365+ D e s t r o y P i x e l C a c h e %
1366% %
1367% %
1368% %
1369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370%
1371% DestroyPixelCache() deallocates memory associated with the pixel cache.
1372%
1373% The format of the DestroyPixelCache() method is:
1374%
1375% Cache DestroyPixelCache(Cache cache)
1376%
1377% A description of each parameter follows:
1378%
1379% o cache: the pixel cache.
1380%
1381*/
1382
1383static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1384{
1385 switch (cache_info->type)
1386 {
1387 case MemoryCache:
1388 {
1389 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001390 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001391 cache_info->pixels);
1392 else
cristy4c08aed2011-07-01 19:47:50 +00001393 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001394 (size_t) cache_info->length);
1395 RelinquishMagickResource(MemoryResource,cache_info->length);
1396 break;
1397 }
1398 case MapCache:
1399 {
cristy4c08aed2011-07-01 19:47:50 +00001400 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001401 cache_info->length);
1402 RelinquishMagickResource(MapResource,cache_info->length);
1403 }
1404 case DiskCache:
1405 {
1406 if (cache_info->file != -1)
1407 (void) ClosePixelCacheOnDisk(cache_info);
1408 RelinquishMagickResource(DiskResource,cache_info->length);
1409 break;
1410 }
1411 default:
1412 break;
1413 }
1414 cache_info->type=UndefinedCache;
1415 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001416 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001417}
1418
cristya6577ff2011-09-02 19:54:26 +00001419MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001420{
1421 CacheInfo
1422 *cache_info;
1423
cristy3ed852e2009-09-05 21:47:34 +00001424 assert(cache != (Cache) NULL);
1425 cache_info=(CacheInfo *) cache;
1426 assert(cache_info->signature == MagickSignature);
1427 if (cache_info->debug != MagickFalse)
1428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1429 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001430 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001431 cache_info->reference_count--;
1432 if (cache_info->reference_count != 0)
1433 {
cristyf84a1932010-01-03 18:00:18 +00001434 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001435 return((Cache) NULL);
1436 }
cristyf84a1932010-01-03 18:00:18 +00001437 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001438 if (cache_resources != (SplayTreeInfo *) NULL)
1439 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001440 if (cache_info->debug != MagickFalse)
1441 {
1442 char
1443 message[MaxTextExtent];
1444
cristyb51dff52011-05-19 16:55:47 +00001445 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001446 cache_info->filename);
1447 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1448 }
cristyc2e1bdd2009-09-10 23:43:34 +00001449 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1450 (cache_info->type != DiskCache)))
1451 RelinquishPixelCachePixels(cache_info);
1452 else
1453 {
1454 RelinquishPixelCachePixels(cache_info);
1455 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1456 }
cristy3ed852e2009-09-05 21:47:34 +00001457 *cache_info->cache_filename='\0';
1458 if (cache_info->nexus_info != (NexusInfo **) NULL)
1459 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1460 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001461 if (cache_info->random_info != (RandomInfo *) NULL)
1462 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001463 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1464 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1465 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1466 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001467 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001468 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001469 cache=(Cache) NULL;
1470 return(cache);
1471}
1472
1473/*
1474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475% %
1476% %
1477% %
1478+ D e s t r o y P i x e l C a c h e N e x u s %
1479% %
1480% %
1481% %
1482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1483%
1484% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1485%
1486% The format of the DestroyPixelCacheNexus() method is:
1487%
1488% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001489% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001490%
1491% A description of each parameter follows:
1492%
1493% o nexus_info: the nexus to destroy.
1494%
1495% o number_threads: the number of nexus threads.
1496%
1497*/
1498
1499static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1500{
1501 if (nexus_info->mapped == MagickFalse)
1502 (void) RelinquishMagickMemory(nexus_info->cache);
1503 else
1504 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001505 nexus_info->cache=(Quantum *) NULL;
1506 nexus_info->pixels=(Quantum *) NULL;
1507 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001508 nexus_info->length=0;
1509 nexus_info->mapped=MagickFalse;
1510}
1511
cristya6577ff2011-09-02 19:54:26 +00001512MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001513 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001514{
cristybb503372010-05-27 20:51:26 +00001515 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001516 i;
1517
1518 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001519 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001520 {
cristy4c08aed2011-07-01 19:47:50 +00001521 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001522 RelinquishCacheNexusPixels(nexus_info[i]);
1523 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001524 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001525 }
cristyb41ee102010-10-04 16:46:15 +00001526 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001527 return(nexus_info);
1528}
1529
1530/*
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532% %
1533% %
1534% %
cristy4c08aed2011-07-01 19:47:50 +00001535% 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 +00001536% %
1537% %
1538% %
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540%
cristy4c08aed2011-07-01 19:47:50 +00001541% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1542% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1543% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001544%
cristy4c08aed2011-07-01 19:47:50 +00001545% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001546%
cristy4c08aed2011-07-01 19:47:50 +00001547% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001548%
1549% A description of each parameter follows:
1550%
1551% o image: the image.
1552%
1553*/
cristy4c08aed2011-07-01 19:47:50 +00001554MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001555{
1556 CacheInfo
1557 *cache_info;
1558
cristy5c9e6f22010-09-17 17:31:01 +00001559 const int
1560 id = GetOpenMPThreadId();
1561
cristy4c08aed2011-07-01 19:47:50 +00001562 void
1563 *metacontent;
1564
cristye7cc7cf2010-09-21 13:26:47 +00001565 assert(image != (const Image *) NULL);
1566 assert(image->signature == MagickSignature);
1567 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001568 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001569 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001570 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1571 (GetAuthenticMetacontentFromHandler) NULL)
1572 {
1573 metacontent=cache_info->methods.
1574 get_authentic_metacontent_from_handler(image);
1575 return(metacontent);
1576 }
cristy6ebe97c2010-07-03 01:17:28 +00001577 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001578 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1579 cache_info->nexus_info[id]);
1580 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001581}
1582
1583/*
1584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585% %
1586% %
1587% %
cristy4c08aed2011-07-01 19:47:50 +00001588+ 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 +00001589% %
1590% %
1591% %
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593%
cristy4c08aed2011-07-01 19:47:50 +00001594% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1595% with the last call to QueueAuthenticPixelsCache() or
1596% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001597%
cristy4c08aed2011-07-01 19:47:50 +00001598% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001599%
cristy4c08aed2011-07-01 19:47:50 +00001600% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001601%
1602% A description of each parameter follows:
1603%
1604% o image: the image.
1605%
1606*/
cristy4c08aed2011-07-01 19:47:50 +00001607static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001608{
1609 CacheInfo
1610 *cache_info;
1611
cristy2036f5c2010-09-19 21:18:17 +00001612 const int
1613 id = GetOpenMPThreadId();
1614
cristy4c08aed2011-07-01 19:47:50 +00001615 void
1616 *metacontent;
1617
cristy3ed852e2009-09-05 21:47:34 +00001618 assert(image != (const Image *) NULL);
1619 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001620 assert(image->cache != (Cache) NULL);
1621 cache_info=(CacheInfo *) image->cache;
1622 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001623 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001624 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1625 cache_info->nexus_info[id]);
1626 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
1634+ 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 %
1635% %
1636% %
1637% %
1638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639%
1640% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1641% disk pixel cache as defined by the geometry parameters. A pointer to the
1642% pixels is returned if the pixels are transferred, otherwise a NULL is
1643% returned.
1644%
1645% The format of the GetAuthenticPixelCacheNexus() method is:
1646%
cristy4c08aed2011-07-01 19:47:50 +00001647% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001648% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001649% NexusInfo *nexus_info,ExceptionInfo *exception)
1650%
1651% A description of each parameter follows:
1652%
1653% o image: the image.
1654%
1655% o x,y,columns,rows: These values define the perimeter of a region of
1656% pixels.
1657%
1658% o nexus_info: the cache nexus to return.
1659%
1660% o exception: return any errors or warnings in this structure.
1661%
1662*/
1663
cristy4c08aed2011-07-01 19:47:50 +00001664static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001665 NexusInfo *nexus_info)
1666{
cristy4c08aed2011-07-01 19:47:50 +00001667 MagickBooleanType
1668 status;
1669
cristy3ed852e2009-09-05 21:47:34 +00001670 MagickOffsetType
1671 offset;
1672
cristy73724512010-04-12 14:43:14 +00001673 if (cache_info->type == PingCache)
1674 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001675 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1676 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001677 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001678 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001679 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001680}
1681
cristya6577ff2011-09-02 19:54:26 +00001682MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001683 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001684 NexusInfo *nexus_info,ExceptionInfo *exception)
1685{
1686 CacheInfo
1687 *cache_info;
1688
cristy4c08aed2011-07-01 19:47:50 +00001689 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001690 *q;
cristy3ed852e2009-09-05 21:47:34 +00001691
1692 /*
1693 Transfer pixels from the cache.
1694 */
1695 assert(image != (Image *) NULL);
1696 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001697 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001698 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001699 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001700 cache_info=(CacheInfo *) image->cache;
1701 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001702 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001703 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001704 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001705 return((Quantum *) NULL);
1706 if (cache_info->metacontent_extent != 0)
1707 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1708 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001709 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001710}
1711
1712/*
1713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1714% %
1715% %
1716% %
1717+ 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 %
1718% %
1719% %
1720% %
1721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1722%
1723% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1724% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1725%
1726% The format of the GetAuthenticPixelsFromCache() method is:
1727%
cristy4c08aed2011-07-01 19:47:50 +00001728% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001729%
1730% A description of each parameter follows:
1731%
1732% o image: the image.
1733%
1734*/
cristy4c08aed2011-07-01 19:47:50 +00001735static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001736{
1737 CacheInfo
1738 *cache_info;
1739
cristy5c9e6f22010-09-17 17:31:01 +00001740 const int
1741 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001742
cristye7cc7cf2010-09-21 13:26:47 +00001743 assert(image != (const Image *) NULL);
1744 assert(image->signature == MagickSignature);
1745 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001746 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001747 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001748 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001749 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001750}
1751
1752/*
1753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754% %
1755% %
1756% %
1757% G e t A u t h e n t i c P i x e l Q u e u e %
1758% %
1759% %
1760% %
1761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762%
cristy4c08aed2011-07-01 19:47:50 +00001763% GetAuthenticPixelQueue() returns the authentic pixels associated
1764% corresponding with the last call to QueueAuthenticPixels() or
1765% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001766%
1767% The format of the GetAuthenticPixelQueue() method is:
1768%
cristy4c08aed2011-07-01 19:47:50 +00001769% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001770%
1771% A description of each parameter follows:
1772%
1773% o image: the image.
1774%
1775*/
cristy4c08aed2011-07-01 19:47:50 +00001776MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001777{
1778 CacheInfo
1779 *cache_info;
1780
cristy2036f5c2010-09-19 21:18:17 +00001781 const int
1782 id = GetOpenMPThreadId();
1783
cristy3ed852e2009-09-05 21:47:34 +00001784 assert(image != (const Image *) NULL);
1785 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001786 assert(image->cache != (Cache) NULL);
1787 cache_info=(CacheInfo *) image->cache;
1788 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001789 if (cache_info->methods.get_authentic_pixels_from_handler !=
1790 (GetAuthenticPixelsFromHandler) NULL)
1791 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001792 assert(id < (int) cache_info->number_threads);
1793 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001794}
1795
1796/*
1797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1798% %
1799% %
1800% %
1801% G e t A u t h e n t i c P i x e l s %
1802% %
1803% %
cristy4c08aed2011-07-01 19:47:50 +00001804% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001805%
1806% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001807% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001808% representing the region is returned, otherwise NULL is returned.
1809%
1810% The returned pointer may point to a temporary working copy of the pixels
1811% or it may point to the original pixels in memory. Performance is maximized
1812% if the selected region is part of one row, or one or more full rows, since
1813% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001814% if the image is in memory, or in a memory-mapped file. The returned pointer
1815% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001816%
1817% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001818% Quantum. If the image has corresponding metacontent,call
1819% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1820% meta-content corresponding to the region. Once the Quantum array has
1821% been updated, the changes must be saved back to the underlying image using
1822% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001823%
1824% The format of the GetAuthenticPixels() method is:
1825%
cristy4c08aed2011-07-01 19:47:50 +00001826% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001827% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001828% ExceptionInfo *exception)
1829%
1830% A description of each parameter follows:
1831%
1832% o image: the image.
1833%
1834% o x,y,columns,rows: These values define the perimeter of a region of
1835% pixels.
1836%
1837% o exception: return any errors or warnings in this structure.
1838%
1839*/
cristy4c08aed2011-07-01 19:47:50 +00001840MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001841 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001842 ExceptionInfo *exception)
1843{
1844 CacheInfo
1845 *cache_info;
1846
cristy2036f5c2010-09-19 21:18:17 +00001847 const int
1848 id = GetOpenMPThreadId();
1849
cristy4c08aed2011-07-01 19:47:50 +00001850 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001851 *q;
cristy4c08aed2011-07-01 19:47:50 +00001852
cristy3ed852e2009-09-05 21:47:34 +00001853 assert(image != (Image *) NULL);
1854 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001855 assert(image->cache != (Cache) NULL);
1856 cache_info=(CacheInfo *) image->cache;
1857 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001858 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001859 (GetAuthenticPixelsHandler) NULL)
1860 {
cristyacd2ed22011-08-30 01:44:23 +00001861 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1862 exception);
1863 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001864 }
cristy2036f5c2010-09-19 21:18:17 +00001865 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001866 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001867 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001868 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001869}
1870
1871/*
1872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1873% %
1874% %
1875% %
1876+ G e t A u t h e n t i c P i x e l s C a c h e %
1877% %
1878% %
1879% %
1880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1881%
1882% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1883% as defined by the geometry parameters. A pointer to the pixels is returned
1884% if the pixels are transferred, otherwise a NULL is returned.
1885%
1886% The format of the GetAuthenticPixelsCache() method is:
1887%
cristy4c08aed2011-07-01 19:47:50 +00001888% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001889% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001890% ExceptionInfo *exception)
1891%
1892% A description of each parameter follows:
1893%
1894% o image: the image.
1895%
1896% o x,y,columns,rows: These values define the perimeter of a region of
1897% pixels.
1898%
1899% o exception: return any errors or warnings in this structure.
1900%
1901*/
cristy4c08aed2011-07-01 19:47:50 +00001902static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001903 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001904 ExceptionInfo *exception)
1905{
1906 CacheInfo
1907 *cache_info;
1908
cristy5c9e6f22010-09-17 17:31:01 +00001909 const int
1910 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001911
cristy4c08aed2011-07-01 19:47:50 +00001912 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001913 *q;
cristy4c08aed2011-07-01 19:47:50 +00001914
cristye7cc7cf2010-09-21 13:26:47 +00001915 assert(image != (const Image *) NULL);
1916 assert(image->signature == MagickSignature);
1917 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001918 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001919 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001920 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001921 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001922 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001923 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001924 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001925 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001926}
1927
1928/*
1929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1930% %
1931% %
1932% %
1933+ G e t I m a g e E x t e n t %
1934% %
1935% %
1936% %
1937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938%
cristy4c08aed2011-07-01 19:47:50 +00001939% GetImageExtent() returns the extent of the pixels associated corresponding
1940% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001941%
1942% The format of the GetImageExtent() method is:
1943%
1944% MagickSizeType GetImageExtent(const Image *image)
1945%
1946% A description of each parameter follows:
1947%
1948% o image: the image.
1949%
1950*/
1951MagickExport MagickSizeType GetImageExtent(const Image *image)
1952{
1953 CacheInfo
1954 *cache_info;
1955
cristy5c9e6f22010-09-17 17:31:01 +00001956 const int
1957 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001958
cristy3ed852e2009-09-05 21:47:34 +00001959 assert(image != (Image *) NULL);
1960 assert(image->signature == MagickSignature);
1961 if (image->debug != MagickFalse)
1962 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1963 assert(image->cache != (Cache) NULL);
1964 cache_info=(CacheInfo *) image->cache;
1965 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001966 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001967 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001968}
1969
1970/*
1971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1972% %
1973% %
1974% %
1975+ G e t I m a g e P i x e l C a c h e %
1976% %
1977% %
1978% %
1979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980%
1981% GetImagePixelCache() ensures that there is only a single reference to the
1982% pixel cache to be modified, updating the provided cache pointer to point to
1983% a clone of the original pixel cache if necessary.
1984%
1985% The format of the GetImagePixelCache method is:
1986%
1987% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1988% ExceptionInfo *exception)
1989%
1990% A description of each parameter follows:
1991%
1992% o image: the image.
1993%
1994% o clone: any value other than MagickFalse clones the cache pixels.
1995%
1996% o exception: return any errors or warnings in this structure.
1997%
1998*/
cristyaf894d72011-08-06 23:03:10 +00001999
cristy3ed852e2009-09-05 21:47:34 +00002000static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2001{
2002 CacheInfo
2003 *cache_info;
2004
cristy9e0719b2011-12-29 03:45:45 +00002005 PixelChannelMap
2006 *p,
2007 *q;
2008
cristy3ed852e2009-09-05 21:47:34 +00002009 /*
2010 Does the image match the pixel cache morphology?
2011 */
2012 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00002013 p=image->channel_map;
2014 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00002015 if ((image->storage_class != cache_info->storage_class) ||
2016 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002017 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002018 (image->columns != cache_info->columns) ||
2019 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002020 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002021 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002022 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002023 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2024 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2025 return(MagickFalse);
2026 return(MagickTrue);
2027}
2028
cristycd01fae2011-08-06 23:52:42 +00002029static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2030 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002031{
2032 CacheInfo
2033 *cache_info;
2034
cristy3ed852e2009-09-05 21:47:34 +00002035 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002036 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002037 status;
2038
cristy50a10922010-02-15 18:35:25 +00002039 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002040 cpu_throttle = 0,
2041 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002042 time_limit = 0;
2043
cristy1ea34962010-07-01 19:49:21 +00002044 static time_t
cristy208b1002011-08-07 18:51:50 +00002045 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002046
cristyc4f9f132010-03-04 18:50:01 +00002047 status=MagickTrue;
2048 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002049 if (cpu_throttle == 0)
2050 {
2051 char
2052 *limit;
2053
2054 /*
2055 Set CPU throttle in milleseconds.
2056 */
2057 cpu_throttle=MagickResourceInfinity;
2058 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2059 if (limit == (char *) NULL)
2060 limit=GetPolicyValue("throttle");
2061 if (limit != (char *) NULL)
2062 {
2063 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2064 limit=DestroyString(limit);
2065 }
2066 }
2067 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2068 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002069 if (time_limit == 0)
2070 {
cristy6ebe97c2010-07-03 01:17:28 +00002071 /*
2072 Set the exire time in seconds.
2073 */
cristy1ea34962010-07-01 19:49:21 +00002074 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002075 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002076 }
2077 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002078 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002079 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002080 assert(image->cache != (Cache) NULL);
2081 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002082 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002083 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002084 {
cristyceb55ee2010-11-06 16:05:49 +00002085 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002086 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002087 {
cristyceb55ee2010-11-06 16:05:49 +00002088 Image
2089 clone_image;
2090
2091 CacheInfo
2092 *clone_info;
2093
2094 /*
2095 Clone pixel cache.
2096 */
2097 clone_image=(*image);
2098 clone_image.semaphore=AllocateSemaphoreInfo();
2099 clone_image.reference_count=1;
2100 clone_image.cache=ClonePixelCache(cache_info);
2101 clone_info=(CacheInfo *) clone_image.cache;
2102 status=OpenPixelCache(&clone_image,IOMode,exception);
2103 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002104 {
cristy5a7fbfb2010-11-06 16:10:59 +00002105 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002106 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002107 if (status != MagickFalse)
2108 {
cristy979bf772011-08-08 00:04:15 +00002109 if (cache_info->mode == ReadMode)
2110 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002111 destroy=MagickTrue;
2112 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002113 }
2114 }
cristyceb55ee2010-11-06 16:05:49 +00002115 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002116 }
cristyceb55ee2010-11-06 16:05:49 +00002117 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002118 }
cristy4320e0e2009-09-10 15:00:08 +00002119 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002120 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002121 if (status != MagickFalse)
2122 {
2123 /*
2124 Ensure the image matches the pixel cache morphology.
2125 */
2126 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002127 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002128 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2129 status=OpenPixelCache(image,IOMode,exception);
2130 }
cristyf84a1932010-01-03 18:00:18 +00002131 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002132 if (status == MagickFalse)
2133 return((Cache) NULL);
2134 return(image->cache);
2135}
2136
2137/*
2138%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2139% %
2140% %
2141% %
2142% G e t O n e A u t h e n t i c P i x e l %
2143% %
2144% %
2145% %
2146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2147%
2148% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2149% location. The image background color is returned if an error occurs.
2150%
2151% The format of the GetOneAuthenticPixel() method is:
2152%
cristybb503372010-05-27 20:51:26 +00002153% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002154% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002155%
2156% A description of each parameter follows:
2157%
2158% o image: the image.
2159%
2160% o x,y: These values define the location of the pixel to return.
2161%
2162% o pixel: return a pixel at the specified (x,y) location.
2163%
2164% o exception: return any errors or warnings in this structure.
2165%
2166*/
cristyacbbb7c2010-06-30 18:56:48 +00002167MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002168 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002169{
2170 CacheInfo
2171 *cache_info;
2172
cristy4c08aed2011-07-01 19:47:50 +00002173 register Quantum
2174 *q;
cristy2036f5c2010-09-19 21:18:17 +00002175
cristy2ed42f62011-10-02 19:49:57 +00002176 register ssize_t
2177 i;
2178
cristy3ed852e2009-09-05 21:47:34 +00002179 assert(image != (Image *) NULL);
2180 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002181 assert(image->cache != (Cache) NULL);
2182 cache_info=(CacheInfo *) image->cache;
2183 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002184 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002185 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2186 (GetOneAuthenticPixelFromHandler) NULL)
2187 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2188 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002189 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2190 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002191 {
cristy9e0719b2011-12-29 03:45:45 +00002192 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2193 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2194 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2195 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2196 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002197 return(MagickFalse);
2198 }
2199 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2200 {
2201 PixelChannel
2202 channel;
2203
cristye2a912b2011-12-05 20:02:07 +00002204 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002205 pixel[channel]=q[i];
2206 }
cristy2036f5c2010-09-19 21:18:17 +00002207 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002208}
2209
2210/*
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212% %
2213% %
2214% %
2215+ 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 %
2216% %
2217% %
2218% %
2219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220%
2221% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2222% location. The image background color is returned if an error occurs.
2223%
2224% The format of the GetOneAuthenticPixelFromCache() method is:
2225%
2226% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002227% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002228% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002229%
2230% A description of each parameter follows:
2231%
2232% o image: the image.
2233%
2234% o x,y: These values define the location of the pixel to return.
2235%
2236% o pixel: return a pixel at the specified (x,y) location.
2237%
2238% o exception: return any errors or warnings in this structure.
2239%
2240*/
2241static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002242 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002243{
cristy098f78c2010-09-23 17:28:44 +00002244 CacheInfo
2245 *cache_info;
2246
2247 const int
2248 id = GetOpenMPThreadId();
2249
cristy4c08aed2011-07-01 19:47:50 +00002250 register Quantum
2251 *q;
cristy3ed852e2009-09-05 21:47:34 +00002252
cristy2ed42f62011-10-02 19:49:57 +00002253 register ssize_t
2254 i;
2255
cristy0158a4b2010-09-20 13:59:45 +00002256 assert(image != (const Image *) NULL);
2257 assert(image->signature == MagickSignature);
2258 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002259 cache_info=(CacheInfo *) image->cache;
2260 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002261 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002262 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002263 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2264 exception);
2265 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002266 {
cristy9e0719b2011-12-29 03:45:45 +00002267 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2268 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2269 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2270 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2271 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002272 return(MagickFalse);
2273 }
2274 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2275 {
2276 PixelChannel
2277 channel;
2278
cristye2a912b2011-12-05 20:02:07 +00002279 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002280 pixel[channel]=q[i];
2281 }
cristy3ed852e2009-09-05 21:47:34 +00002282 return(MagickTrue);
2283}
2284
2285/*
2286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2287% %
2288% %
2289% %
cristy3ed852e2009-09-05 21:47:34 +00002290% G e t O n e V i r t u a l P i x e l %
2291% %
2292% %
2293% %
2294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2295%
2296% GetOneVirtualPixel() returns a single virtual pixel at the specified
2297% (x,y) location. The image background color is returned if an error occurs.
2298% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2299%
2300% The format of the GetOneVirtualPixel() method is:
2301%
cristybb503372010-05-27 20:51:26 +00002302% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002303% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002304%
2305% A description of each parameter follows:
2306%
2307% o image: the image.
2308%
2309% o x,y: These values define the location of the pixel to return.
2310%
2311% o pixel: return a pixel at the specified (x,y) location.
2312%
2313% o exception: return any errors or warnings in this structure.
2314%
2315*/
2316MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002317 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002318{
cristy3ed852e2009-09-05 21:47:34 +00002319 CacheInfo
2320 *cache_info;
2321
cristy0158a4b2010-09-20 13:59:45 +00002322 const int
2323 id = GetOpenMPThreadId();
2324
cristy4c08aed2011-07-01 19:47:50 +00002325 const Quantum
2326 *p;
cristy2036f5c2010-09-19 21:18:17 +00002327
cristy2ed42f62011-10-02 19:49:57 +00002328 register ssize_t
2329 i;
2330
cristy3ed852e2009-09-05 21:47:34 +00002331 assert(image != (const Image *) NULL);
2332 assert(image->signature == MagickSignature);
2333 assert(image->cache != (Cache) NULL);
2334 cache_info=(CacheInfo *) image->cache;
2335 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002336 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002337 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2338 (GetOneVirtualPixelFromHandler) NULL)
2339 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2340 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002341 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002342 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002343 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002344 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002345 {
cristy9e0719b2011-12-29 03:45:45 +00002346 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2347 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2348 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2349 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2350 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002351 return(MagickFalse);
2352 }
2353 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2354 {
2355 PixelChannel
2356 channel;
2357
cristye2a912b2011-12-05 20:02:07 +00002358 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002359 pixel[channel]=p[i];
2360 }
cristy2036f5c2010-09-19 21:18:17 +00002361 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002362}
2363
2364/*
2365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2366% %
2367% %
2368% %
2369+ 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 %
2370% %
2371% %
2372% %
2373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2374%
2375% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2376% specified (x,y) location. The image background color is returned if an
2377% error occurs.
2378%
2379% The format of the GetOneVirtualPixelFromCache() method is:
2380%
2381% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002382% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002383% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002384%
2385% A description of each parameter follows:
2386%
2387% o image: the image.
2388%
2389% o virtual_pixel_method: the virtual pixel method.
2390%
2391% o x,y: These values define the location of the pixel to return.
2392%
2393% o pixel: return a pixel at the specified (x,y) location.
2394%
2395% o exception: return any errors or warnings in this structure.
2396%
2397*/
2398static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002399 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002400 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002401{
cristy0158a4b2010-09-20 13:59:45 +00002402 CacheInfo
2403 *cache_info;
2404
2405 const int
2406 id = GetOpenMPThreadId();
2407
cristy4c08aed2011-07-01 19:47:50 +00002408 const Quantum
2409 *p;
cristy3ed852e2009-09-05 21:47:34 +00002410
cristy2ed42f62011-10-02 19:49:57 +00002411 register ssize_t
2412 i;
2413
cristye7cc7cf2010-09-21 13:26:47 +00002414 assert(image != (const Image *) NULL);
2415 assert(image->signature == MagickSignature);
2416 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002417 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002418 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002419 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002420 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002422 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002423 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002424 {
cristy9e0719b2011-12-29 03:45:45 +00002425 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2426 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2427 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2428 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2429 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002430 return(MagickFalse);
2431 }
2432 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2433 {
2434 PixelChannel
2435 channel;
2436
cristye2a912b2011-12-05 20:02:07 +00002437 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002438 pixel[channel]=p[i];
2439 }
cristy3ed852e2009-09-05 21:47:34 +00002440 return(MagickTrue);
2441}
2442
2443/*
2444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2445% %
2446% %
2447% %
cristy3aa93752011-12-18 15:54:24 +00002448% G e t O n e V i r t u a l P i x e l I n f o %
2449% %
2450% %
2451% %
2452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2453%
2454% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2455% location. The image background color is returned if an error occurs. If
2456% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2457%
2458% The format of the GetOneVirtualPixelInfo() method is:
2459%
2460% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2461% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2462% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2463%
2464% A description of each parameter follows:
2465%
2466% o image: the image.
2467%
2468% o virtual_pixel_method: the virtual pixel method.
2469%
2470% o x,y: these values define the location of the pixel to return.
2471%
2472% o pixel: return a pixel at the specified (x,y) location.
2473%
2474% o exception: return any errors or warnings in this structure.
2475%
2476*/
2477MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2478 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2479 PixelInfo *pixel,ExceptionInfo *exception)
2480{
2481 CacheInfo
2482 *cache_info;
2483
2484 const int
2485 id = GetOpenMPThreadId();
2486
2487 register const Quantum
2488 *p;
2489
2490 assert(image != (const Image *) NULL);
2491 assert(image->signature == MagickSignature);
2492 assert(image->cache != (Cache) NULL);
2493 cache_info=(CacheInfo *) image->cache;
2494 assert(cache_info->signature == MagickSignature);
2495 assert(id < (int) cache_info->number_threads);
2496 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2497 cache_info->nexus_info[id],exception);
2498 GetPixelInfo(image,pixel);
2499 if (p == (const Quantum *) NULL)
2500 return(MagickFalse);
2501 GetPixelInfoPixel(image,p,pixel);
2502 return(MagickTrue);
2503}
2504
2505/*
2506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2507% %
2508% %
2509% %
cristy3ed852e2009-09-05 21:47:34 +00002510+ G e t P i x e l C a c h e C o l o r s p a c e %
2511% %
2512% %
2513% %
2514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2515%
2516% GetPixelCacheColorspace() returns the class type of the pixel cache.
2517%
2518% The format of the GetPixelCacheColorspace() method is:
2519%
2520% Colorspace GetPixelCacheColorspace(Cache cache)
2521%
2522% A description of each parameter follows:
2523%
2524% o cache: the pixel cache.
2525%
2526*/
cristya6577ff2011-09-02 19:54:26 +00002527MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002528{
2529 CacheInfo
2530 *cache_info;
2531
2532 assert(cache != (Cache) NULL);
2533 cache_info=(CacheInfo *) cache;
2534 assert(cache_info->signature == MagickSignature);
2535 if (cache_info->debug != MagickFalse)
2536 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2537 cache_info->filename);
2538 return(cache_info->colorspace);
2539}
2540
2541/*
2542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543% %
2544% %
2545% %
2546+ G e t P i x e l C a c h e M e t h o d s %
2547% %
2548% %
2549% %
2550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551%
2552% GetPixelCacheMethods() initializes the CacheMethods structure.
2553%
2554% The format of the GetPixelCacheMethods() method is:
2555%
2556% void GetPixelCacheMethods(CacheMethods *cache_methods)
2557%
2558% A description of each parameter follows:
2559%
2560% o cache_methods: Specifies a pointer to a CacheMethods structure.
2561%
2562*/
cristya6577ff2011-09-02 19:54:26 +00002563MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002564{
2565 assert(cache_methods != (CacheMethods *) NULL);
2566 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2567 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2568 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002569 cache_methods->get_virtual_metacontent_from_handler=
2570 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002571 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2572 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002573 cache_methods->get_authentic_metacontent_from_handler=
2574 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002575 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2576 cache_methods->get_one_authentic_pixel_from_handler=
2577 GetOneAuthenticPixelFromCache;
2578 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2579 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2580 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2581}
2582
2583/*
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585% %
2586% %
2587% %
2588+ G e t P i x e l C a c h e N e x u s E x t e n t %
2589% %
2590% %
2591% %
2592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593%
cristy4c08aed2011-07-01 19:47:50 +00002594% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2595% corresponding with the last call to SetPixelCacheNexusPixels() or
2596% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002597%
2598% The format of the GetPixelCacheNexusExtent() method is:
2599%
2600% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2601% NexusInfo *nexus_info)
2602%
2603% A description of each parameter follows:
2604%
2605% o nexus_info: the nexus info.
2606%
2607*/
cristya6577ff2011-09-02 19:54:26 +00002608MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002609 NexusInfo *nexus_info)
2610{
2611 CacheInfo
2612 *cache_info;
2613
2614 MagickSizeType
2615 extent;
2616
cristy9f027d12011-09-21 01:17:17 +00002617 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002618 cache_info=(CacheInfo *) cache;
2619 assert(cache_info->signature == MagickSignature);
2620 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2621 if (extent == 0)
2622 return((MagickSizeType) cache_info->columns*cache_info->rows);
2623 return(extent);
2624}
2625
2626/*
2627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2628% %
2629% %
2630% %
cristy4c08aed2011-07-01 19:47:50 +00002631+ 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 +00002632% %
2633% %
2634% %
2635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2636%
cristy4c08aed2011-07-01 19:47:50 +00002637% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2638% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002639%
cristy4c08aed2011-07-01 19:47:50 +00002640% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002641%
cristy4c08aed2011-07-01 19:47:50 +00002642% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002643% NexusInfo *nexus_info)
2644%
2645% A description of each parameter follows:
2646%
2647% o cache: the pixel cache.
2648%
cristy4c08aed2011-07-01 19:47:50 +00002649% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002650%
2651*/
cristya6577ff2011-09-02 19:54:26 +00002652MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002653 NexusInfo *nexus_info)
2654{
2655 CacheInfo
2656 *cache_info;
2657
cristy9f027d12011-09-21 01:17:17 +00002658 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002659 cache_info=(CacheInfo *) cache;
2660 assert(cache_info->signature == MagickSignature);
2661 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002662 return((void *) NULL);
2663 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002664}
2665
2666/*
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668% %
2669% %
2670% %
2671+ G e t P i x e l C a c h e N e x u s P i x e l s %
2672% %
2673% %
2674% %
2675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676%
2677% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2678% cache nexus.
2679%
2680% The format of the GetPixelCacheNexusPixels() method is:
2681%
cristy4c08aed2011-07-01 19:47:50 +00002682% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002683% NexusInfo *nexus_info)
2684%
2685% A description of each parameter follows:
2686%
2687% o cache: the pixel cache.
2688%
2689% o nexus_info: the cache nexus to return the pixels.
2690%
2691*/
cristya6577ff2011-09-02 19:54:26 +00002692MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002693 NexusInfo *nexus_info)
2694{
2695 CacheInfo
2696 *cache_info;
2697
cristy9f027d12011-09-21 01:17:17 +00002698 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002699 cache_info=(CacheInfo *) cache;
2700 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002701 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002702 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002703 return(nexus_info->pixels);
2704}
2705
2706/*
2707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2708% %
2709% %
2710% %
cristy056ba772010-01-02 23:33:54 +00002711+ G e t P i x e l C a c h e P i x e l s %
2712% %
2713% %
2714% %
2715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716%
2717% GetPixelCachePixels() returns the pixels associated with the specified image.
2718%
2719% The format of the GetPixelCachePixels() method is:
2720%
cristyf84a1932010-01-03 18:00:18 +00002721% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2722% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002723%
2724% A description of each parameter follows:
2725%
2726% o image: the image.
2727%
2728% o length: the pixel cache length.
2729%
cristyf84a1932010-01-03 18:00:18 +00002730% o exception: return any errors or warnings in this structure.
2731%
cristy056ba772010-01-02 23:33:54 +00002732*/
cristyd1dd6e42011-09-04 01:46:08 +00002733MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002734 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002735{
2736 CacheInfo
2737 *cache_info;
2738
2739 assert(image != (const Image *) NULL);
2740 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002741 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002742 assert(length != (MagickSizeType *) NULL);
2743 assert(exception != (ExceptionInfo *) NULL);
2744 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002745 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002746 assert(cache_info->signature == MagickSignature);
2747 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002748 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002749 return((void *) NULL);
2750 *length=cache_info->length;
2751 return((void *) cache_info->pixels);
2752}
2753
2754/*
2755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2756% %
2757% %
2758% %
cristyb32b90a2009-09-07 21:45:48 +00002759+ 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 +00002760% %
2761% %
2762% %
2763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2764%
2765% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2766%
2767% The format of the GetPixelCacheStorageClass() method is:
2768%
2769% ClassType GetPixelCacheStorageClass(Cache cache)
2770%
2771% A description of each parameter follows:
2772%
2773% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2774%
2775% o cache: the pixel cache.
2776%
2777*/
cristya6577ff2011-09-02 19:54:26 +00002778MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002779{
2780 CacheInfo
2781 *cache_info;
2782
2783 assert(cache != (Cache) NULL);
2784 cache_info=(CacheInfo *) cache;
2785 assert(cache_info->signature == MagickSignature);
2786 if (cache_info->debug != MagickFalse)
2787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2788 cache_info->filename);
2789 return(cache_info->storage_class);
2790}
2791
2792/*
2793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794% %
2795% %
2796% %
cristyb32b90a2009-09-07 21:45:48 +00002797+ G e t P i x e l C a c h e T i l e S i z e %
2798% %
2799% %
2800% %
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802%
2803% GetPixelCacheTileSize() returns the pixel cache tile size.
2804%
2805% The format of the GetPixelCacheTileSize() method is:
2806%
cristybb503372010-05-27 20:51:26 +00002807% void GetPixelCacheTileSize(const Image *image,size_t *width,
2808% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002809%
2810% A description of each parameter follows:
2811%
2812% o image: the image.
2813%
2814% o width: the optimize cache tile width in pixels.
2815%
2816% o height: the optimize cache tile height in pixels.
2817%
2818*/
cristya6577ff2011-09-02 19:54:26 +00002819MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002820 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002821{
cristy4c08aed2011-07-01 19:47:50 +00002822 CacheInfo
2823 *cache_info;
2824
cristyb32b90a2009-09-07 21:45:48 +00002825 assert(image != (Image *) NULL);
2826 assert(image->signature == MagickSignature);
2827 if (image->debug != MagickFalse)
2828 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002829 cache_info=(CacheInfo *) image->cache;
2830 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002831 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002832 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002833 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002834 *height=(*width);
2835}
2836
2837/*
2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839% %
2840% %
2841% %
2842+ G e t P i x e l C a c h e T y p e %
2843% %
2844% %
2845% %
2846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847%
2848% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2849%
2850% The format of the GetPixelCacheType() method is:
2851%
2852% CacheType GetPixelCacheType(const Image *image)
2853%
2854% A description of each parameter follows:
2855%
2856% o image: the image.
2857%
2858*/
cristya6577ff2011-09-02 19:54:26 +00002859MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002860{
2861 CacheInfo
2862 *cache_info;
2863
2864 assert(image != (Image *) NULL);
2865 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002866 assert(image->cache != (Cache) NULL);
2867 cache_info=(CacheInfo *) image->cache;
2868 assert(cache_info->signature == MagickSignature);
2869 return(cache_info->type);
2870}
2871
2872/*
2873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874% %
2875% %
2876% %
cristy3ed852e2009-09-05 21:47:34 +00002877+ 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 %
2878% %
2879% %
2880% %
2881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882%
2883% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2884% pixel cache. A virtual pixel is any pixel access that is outside the
2885% boundaries of the image cache.
2886%
2887% The format of the GetPixelCacheVirtualMethod() method is:
2888%
2889% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2890%
2891% A description of each parameter follows:
2892%
2893% o image: the image.
2894%
2895*/
cristyd1dd6e42011-09-04 01:46:08 +00002896MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002897{
2898 CacheInfo
2899 *cache_info;
2900
2901 assert(image != (Image *) NULL);
2902 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002903 assert(image->cache != (Cache) NULL);
2904 cache_info=(CacheInfo *) image->cache;
2905 assert(cache_info->signature == MagickSignature);
2906 return(cache_info->virtual_pixel_method);
2907}
2908
2909/*
2910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911% %
2912% %
2913% %
cristy4c08aed2011-07-01 19:47:50 +00002914+ G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00002915% %
2916% %
2917% %
2918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919%
cristy4c08aed2011-07-01 19:47:50 +00002920% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2921% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002922%
cristy4c08aed2011-07-01 19:47:50 +00002923% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002924%
cristy4c08aed2011-07-01 19:47:50 +00002925% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002926%
2927% A description of each parameter follows:
2928%
2929% o image: the image.
2930%
2931*/
cristy4c08aed2011-07-01 19:47:50 +00002932static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002933{
2934 CacheInfo
2935 *cache_info;
2936
cristy5c9e6f22010-09-17 17:31:01 +00002937 const int
2938 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002939
cristy4c08aed2011-07-01 19:47:50 +00002940 const void
2941 *metacontent;
2942
cristye7cc7cf2010-09-21 13:26:47 +00002943 assert(image != (const Image *) NULL);
2944 assert(image->signature == MagickSignature);
2945 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002946 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002947 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002948 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002949 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2950 cache_info->nexus_info[id]);
2951 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002952}
2953
2954/*
2955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2956% %
2957% %
2958% %
cristy4c08aed2011-07-01 19:47:50 +00002959+ 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 +00002960% %
2961% %
2962% %
2963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964%
cristy4c08aed2011-07-01 19:47:50 +00002965% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2966% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002967%
cristy4c08aed2011-07-01 19:47:50 +00002968% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002969%
cristy4c08aed2011-07-01 19:47:50 +00002970% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002971% NexusInfo *nexus_info)
2972%
2973% A description of each parameter follows:
2974%
2975% o cache: the pixel cache.
2976%
cristy4c08aed2011-07-01 19:47:50 +00002977% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002978%
2979*/
cristya6577ff2011-09-02 19:54:26 +00002980MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002981 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002982{
2983 CacheInfo
2984 *cache_info;
2985
cristye7cc7cf2010-09-21 13:26:47 +00002986 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002987 cache_info=(CacheInfo *) cache;
2988 assert(cache_info->signature == MagickSignature);
2989 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002990 return((void *) NULL);
2991 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002992}
2993
2994/*
2995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2996% %
2997% %
2998% %
cristy4c08aed2011-07-01 19:47:50 +00002999% 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 +00003000% %
3001% %
3002% %
3003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004%
cristy4c08aed2011-07-01 19:47:50 +00003005% GetVirtualMetacontent() returns the virtual metacontent corresponding with
3006% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3007% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003008%
cristy4c08aed2011-07-01 19:47:50 +00003009% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003010%
cristy4c08aed2011-07-01 19:47:50 +00003011% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003012%
3013% A description of each parameter follows:
3014%
3015% o image: the image.
3016%
3017*/
cristy4c08aed2011-07-01 19:47:50 +00003018MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003019{
3020 CacheInfo
3021 *cache_info;
3022
cristy2036f5c2010-09-19 21:18:17 +00003023 const int
3024 id = GetOpenMPThreadId();
3025
cristy4c08aed2011-07-01 19:47:50 +00003026 const void
3027 *metacontent;
3028
cristy3ed852e2009-09-05 21:47:34 +00003029 assert(image != (const Image *) NULL);
3030 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003031 assert(image->cache != (Cache) NULL);
3032 cache_info=(CacheInfo *) image->cache;
3033 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003034 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3035 (GetVirtualMetacontentFromHandler) NULL)
3036 {
3037 metacontent=cache_info->methods.
3038 get_virtual_metacontent_from_handler(image);
3039 return(metacontent);
3040 }
cristy2036f5c2010-09-19 21:18:17 +00003041 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003042 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3043 cache_info->nexus_info[id]);
3044 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003045}
3046
3047/*
3048%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049% %
3050% %
3051% %
3052+ 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 %
3053% %
3054% %
3055% %
3056%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3057%
3058% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3059% pixel cache as defined by the geometry parameters. A pointer to the pixels
3060% is returned if the pixels are transferred, otherwise a NULL is returned.
3061%
3062% The format of the GetVirtualPixelsFromNexus() method is:
3063%
cristy4c08aed2011-07-01 19:47:50 +00003064% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003065% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003066% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3067% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003068%
3069% A description of each parameter follows:
3070%
3071% o image: the image.
3072%
3073% o virtual_pixel_method: the virtual pixel method.
3074%
3075% o x,y,columns,rows: These values define the perimeter of a region of
3076% pixels.
3077%
3078% o nexus_info: the cache nexus to acquire.
3079%
3080% o exception: return any errors or warnings in this structure.
3081%
3082*/
3083
cristybb503372010-05-27 20:51:26 +00003084static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003085 DitherMatrix[64] =
3086 {
3087 0, 48, 12, 60, 3, 51, 15, 63,
3088 32, 16, 44, 28, 35, 19, 47, 31,
3089 8, 56, 4, 52, 11, 59, 7, 55,
3090 40, 24, 36, 20, 43, 27, 39, 23,
3091 2, 50, 14, 62, 1, 49, 13, 61,
3092 34, 18, 46, 30, 33, 17, 45, 29,
3093 10, 58, 6, 54, 9, 57, 5, 53,
3094 42, 26, 38, 22, 41, 25, 37, 21
3095 };
3096
cristybb503372010-05-27 20:51:26 +00003097static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003098{
cristybb503372010-05-27 20:51:26 +00003099 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003100 index;
3101
3102 index=x+DitherMatrix[x & 0x07]-32L;
3103 if (index < 0L)
3104 return(0L);
cristybb503372010-05-27 20:51:26 +00003105 if (index >= (ssize_t) columns)
3106 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003107 return(index);
3108}
3109
cristybb503372010-05-27 20:51:26 +00003110static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003111{
cristybb503372010-05-27 20:51:26 +00003112 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003113 index;
3114
3115 index=y+DitherMatrix[y & 0x07]-32L;
3116 if (index < 0L)
3117 return(0L);
cristybb503372010-05-27 20:51:26 +00003118 if (index >= (ssize_t) rows)
3119 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003120 return(index);
3121}
3122
cristybb503372010-05-27 20:51:26 +00003123static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003124{
3125 if (x < 0L)
3126 return(0L);
cristybb503372010-05-27 20:51:26 +00003127 if (x >= (ssize_t) columns)
3128 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003129 return(x);
3130}
3131
cristybb503372010-05-27 20:51:26 +00003132static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003133{
3134 if (y < 0L)
3135 return(0L);
cristybb503372010-05-27 20:51:26 +00003136 if (y >= (ssize_t) rows)
3137 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003138 return(y);
3139}
3140
cristybb503372010-05-27 20:51:26 +00003141static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003142{
cristybb503372010-05-27 20:51:26 +00003143 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003144}
3145
cristybb503372010-05-27 20:51:26 +00003146static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003147{
cristybb503372010-05-27 20:51:26 +00003148 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003149}
3150
cristybb503372010-05-27 20:51:26 +00003151static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3152 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003153{
3154 MagickModulo
3155 modulo;
3156
cristy6162bb42011-07-18 11:34:09 +00003157 /*
3158 Compute the remainder of dividing offset by extent. It returns not only
3159 the quotient (tile the offset falls in) but also the positive remainer
3160 within that tile such that 0 <= remainder < extent. This method is
3161 essentially a ldiv() using a floored modulo division rather than the
3162 normal default truncated modulo division.
3163 */
cristybb503372010-05-27 20:51:26 +00003164 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003165 if (offset < 0L)
3166 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003167 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003168 return(modulo);
3169}
3170
cristya6577ff2011-09-02 19:54:26 +00003171MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003172 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3173 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003174 ExceptionInfo *exception)
3175{
3176 CacheInfo
3177 *cache_info;
3178
3179 MagickOffsetType
3180 offset;
3181
3182 MagickSizeType
3183 length,
3184 number_pixels;
3185
3186 NexusInfo
3187 **virtual_nexus;
3188
cristy4c08aed2011-07-01 19:47:50 +00003189 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003190 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003191 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003192
3193 RectangleInfo
3194 region;
3195
cristy4c08aed2011-07-01 19:47:50 +00003196 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003197 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003198
cristy4c08aed2011-07-01 19:47:50 +00003199 register const void
3200 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003201
cristy4c08aed2011-07-01 19:47:50 +00003202 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003203 *restrict q;
3204
cristybb503372010-05-27 20:51:26 +00003205 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003206 i,
3207 u;
cristy3ed852e2009-09-05 21:47:34 +00003208
cristy4c08aed2011-07-01 19:47:50 +00003209 register unsigned char
3210 *restrict s;
3211
cristy105ba3c2011-07-18 02:28:38 +00003212 ssize_t
3213 v;
3214
cristy4c08aed2011-07-01 19:47:50 +00003215 void
cristy105ba3c2011-07-18 02:28:38 +00003216 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003217
cristy3ed852e2009-09-05 21:47:34 +00003218 /*
3219 Acquire pixels.
3220 */
cristye7cc7cf2010-09-21 13:26:47 +00003221 assert(image != (const Image *) NULL);
3222 assert(image->signature == MagickSignature);
3223 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003224 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003225 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003226 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003227 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003228 region.x=x;
3229 region.y=y;
3230 region.width=columns;
3231 region.height=rows;
3232 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003233 if (pixels == (Quantum *) NULL)
3234 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003235 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003236 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3237 nexus_info->region.x;
3238 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3239 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003240 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3241 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003242 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3243 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003244 {
3245 MagickBooleanType
3246 status;
3247
3248 /*
3249 Pixel request is inside cache extents.
3250 */
cristy4c08aed2011-07-01 19:47:50 +00003251 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003252 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003253 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3254 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003255 return((const Quantum *) NULL);
3256 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003257 {
cristy4c08aed2011-07-01 19:47:50 +00003258 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003259 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003260 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003261 }
cristyacd2ed22011-08-30 01:44:23 +00003262 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003263 }
3264 /*
3265 Pixel request is outside cache extents.
3266 */
cristy4c08aed2011-07-01 19:47:50 +00003267 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003268 virtual_nexus=AcquirePixelCacheNexus(1);
3269 if (virtual_nexus == (NexusInfo **) NULL)
3270 {
cristy4c08aed2011-07-01 19:47:50 +00003271 if (virtual_nexus != (NexusInfo **) NULL)
3272 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003273 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3274 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003275 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003276 }
cristy105ba3c2011-07-18 02:28:38 +00003277 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3278 sizeof(*virtual_pixel));
3279 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003280 switch (virtual_pixel_method)
3281 {
cristy4c08aed2011-07-01 19:47:50 +00003282 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003283 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003284 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003285 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003286 case MaskVirtualPixelMethod:
3287 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003288 case EdgeVirtualPixelMethod:
3289 case CheckerTileVirtualPixelMethod:
3290 case HorizontalTileVirtualPixelMethod:
3291 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003292 {
cristy4c08aed2011-07-01 19:47:50 +00003293 if (cache_info->metacontent_extent != 0)
3294 {
cristy6162bb42011-07-18 11:34:09 +00003295 /*
3296 Acquire a metacontent buffer.
3297 */
cristya64b85d2011-09-14 01:02:31 +00003298 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003299 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003300 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003301 {
cristy4c08aed2011-07-01 19:47:50 +00003302 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3303 (void) ThrowMagickException(exception,GetMagickModule(),
3304 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3305 return((const Quantum *) NULL);
3306 }
cristy105ba3c2011-07-18 02:28:38 +00003307 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003308 cache_info->metacontent_extent);
3309 }
3310 switch (virtual_pixel_method)
3311 {
3312 case BlackVirtualPixelMethod:
3313 {
cristy30301712011-07-18 15:06:51 +00003314 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3315 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003316 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3317 break;
3318 }
3319 case GrayVirtualPixelMethod:
3320 {
cristy30301712011-07-18 15:06:51 +00003321 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003322 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3323 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003324 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3325 break;
3326 }
3327 case TransparentVirtualPixelMethod:
3328 {
cristy30301712011-07-18 15:06:51 +00003329 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3330 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003331 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3332 break;
3333 }
3334 case MaskVirtualPixelMethod:
3335 case WhiteVirtualPixelMethod:
3336 {
cristy30301712011-07-18 15:06:51 +00003337 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3338 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003339 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3340 break;
3341 }
3342 default:
3343 {
cristy9e0719b2011-12-29 03:45:45 +00003344 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3345 virtual_pixel);
3346 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3347 virtual_pixel);
3348 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3349 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003350 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003351 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3352 virtual_pixel);
3353 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3354 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003355 break;
3356 }
3357 }
cristy3ed852e2009-09-05 21:47:34 +00003358 break;
3359 }
3360 default:
cristy3ed852e2009-09-05 21:47:34 +00003361 break;
cristy3ed852e2009-09-05 21:47:34 +00003362 }
cristybb503372010-05-27 20:51:26 +00003363 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003364 {
cristybb503372010-05-27 20:51:26 +00003365 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003366 {
3367 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003368 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003369 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3370 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003371 {
3372 MagickModulo
3373 x_modulo,
3374 y_modulo;
3375
3376 /*
3377 Transfer a single pixel.
3378 */
3379 length=(MagickSizeType) 1;
3380 switch (virtual_pixel_method)
3381 {
cristy3ed852e2009-09-05 21:47:34 +00003382 default:
3383 {
3384 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003385 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003386 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003387 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003388 break;
3389 }
3390 case RandomVirtualPixelMethod:
3391 {
3392 if (cache_info->random_info == (RandomInfo *) NULL)
3393 cache_info->random_info=AcquireRandomInfo();
3394 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003395 RandomX(cache_info->random_info,cache_info->columns),
3396 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003397 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003398 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003399 break;
3400 }
3401 case DitherVirtualPixelMethod:
3402 {
3403 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003404 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003405 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003406 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003407 break;
3408 }
3409 case TileVirtualPixelMethod:
3410 {
3411 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3412 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3413 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003414 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003415 exception);
cristy4c08aed2011-07-01 19:47:50 +00003416 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003417 break;
3418 }
3419 case MirrorVirtualPixelMethod:
3420 {
3421 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3422 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003423 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003424 x_modulo.remainder-1L;
3425 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3426 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003427 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003428 y_modulo.remainder-1L;
3429 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003430 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003431 exception);
cristy4c08aed2011-07-01 19:47:50 +00003432 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003433 break;
3434 }
3435 case HorizontalTileEdgeVirtualPixelMethod:
3436 {
3437 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003439 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003440 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003441 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003442 break;
3443 }
3444 case VerticalTileEdgeVirtualPixelMethod:
3445 {
3446 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3447 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003448 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003449 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003450 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3451 break;
3452 }
3453 case BackgroundVirtualPixelMethod:
3454 case BlackVirtualPixelMethod:
3455 case GrayVirtualPixelMethod:
3456 case TransparentVirtualPixelMethod:
3457 case MaskVirtualPixelMethod:
3458 case WhiteVirtualPixelMethod:
3459 {
3460 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003461 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003462 break;
3463 }
3464 case EdgeVirtualPixelMethod:
3465 case CheckerTileVirtualPixelMethod:
3466 {
3467 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3468 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3469 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3470 {
3471 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003472 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003473 break;
3474 }
3475 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3476 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3477 exception);
3478 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3479 break;
3480 }
3481 case HorizontalTileVirtualPixelMethod:
3482 {
3483 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3484 {
3485 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003486 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003487 break;
3488 }
3489 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3490 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3491 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3492 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3493 exception);
3494 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3495 break;
3496 }
3497 case VerticalTileVirtualPixelMethod:
3498 {
3499 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3500 {
3501 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003502 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003503 break;
3504 }
3505 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3506 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3507 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3508 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3509 exception);
3510 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003511 break;
3512 }
3513 }
cristy4c08aed2011-07-01 19:47:50 +00003514 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003515 break;
cristyed231572011-07-14 02:18:59 +00003516 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003517 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003518 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003519 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003520 {
3521 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3522 s+=cache_info->metacontent_extent;
3523 }
cristy3ed852e2009-09-05 21:47:34 +00003524 continue;
3525 }
3526 /*
3527 Transfer a run of pixels.
3528 */
cristy4c08aed2011-07-01 19:47:50 +00003529 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3530 length,1UL,*virtual_nexus,exception);
3531 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003532 break;
cristy4c08aed2011-07-01 19:47:50 +00003533 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003534 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3535 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003536 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003537 {
cristy4c08aed2011-07-01 19:47:50 +00003538 (void) memcpy(s,r,(size_t) length);
3539 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003540 }
3541 }
3542 }
cristy4c08aed2011-07-01 19:47:50 +00003543 /*
3544 Free resources.
3545 */
cristy105ba3c2011-07-18 02:28:38 +00003546 if (virtual_metacontent != (void *) NULL)
3547 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003548 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3549 return(pixels);
3550}
3551
3552/*
3553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3554% %
3555% %
3556% %
3557+ G e t V i r t u a l P i x e l C a c h e %
3558% %
3559% %
3560% %
3561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562%
3563% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3564% cache as defined by the geometry parameters. A pointer to the pixels
3565% is returned if the pixels are transferred, otherwise a NULL is returned.
3566%
3567% The format of the GetVirtualPixelCache() method is:
3568%
cristy4c08aed2011-07-01 19:47:50 +00003569% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003570% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3571% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003572% ExceptionInfo *exception)
3573%
3574% A description of each parameter follows:
3575%
3576% o image: the image.
3577%
3578% o virtual_pixel_method: the virtual pixel method.
3579%
3580% o x,y,columns,rows: These values define the perimeter of a region of
3581% pixels.
3582%
3583% o exception: return any errors or warnings in this structure.
3584%
3585*/
cristy4c08aed2011-07-01 19:47:50 +00003586static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003587 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3588 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003589{
3590 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003591 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003592
cristy5c9e6f22010-09-17 17:31:01 +00003593 const int
3594 id = GetOpenMPThreadId();
3595
cristy4c08aed2011-07-01 19:47:50 +00003596 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003597 *p;
cristy4c08aed2011-07-01 19:47:50 +00003598
cristye7cc7cf2010-09-21 13:26:47 +00003599 assert(image != (const Image *) NULL);
3600 assert(image->signature == MagickSignature);
3601 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003602 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003603 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003604 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003605 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003606 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003607 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003608}
3609
3610/*
3611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612% %
3613% %
3614% %
3615% G e t V i r t u a l P i x e l Q u e u e %
3616% %
3617% %
3618% %
3619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3620%
cristy4c08aed2011-07-01 19:47:50 +00003621% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3622% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003623%
3624% The format of the GetVirtualPixelQueue() method is:
3625%
cristy4c08aed2011-07-01 19:47:50 +00003626% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003627%
3628% A description of each parameter follows:
3629%
3630% o image: the image.
3631%
3632*/
cristy4c08aed2011-07-01 19:47:50 +00003633MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003634{
3635 CacheInfo
3636 *cache_info;
3637
cristy2036f5c2010-09-19 21:18:17 +00003638 const int
3639 id = GetOpenMPThreadId();
3640
cristy3ed852e2009-09-05 21:47:34 +00003641 assert(image != (const Image *) NULL);
3642 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003643 assert(image->cache != (Cache) NULL);
3644 cache_info=(CacheInfo *) image->cache;
3645 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003646 if (cache_info->methods.get_virtual_pixels_handler !=
3647 (GetVirtualPixelsHandler) NULL)
3648 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003649 assert(id < (int) cache_info->number_threads);
3650 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003651}
3652
3653/*
3654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3655% %
3656% %
3657% %
3658% G e t V i r t u a l P i x e l s %
3659% %
3660% %
3661% %
3662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3663%
3664% GetVirtualPixels() returns an immutable pixel region. If the
3665% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003666% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003667% copy of the pixels or it may point to the original pixels in memory.
3668% Performance is maximized if the selected region is part of one row, or one
3669% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003670% (without a copy) if the image is in memory, or in a memory-mapped file. The
3671% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003672%
3673% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003674% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3675% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3676% access the meta-content (of type void) corresponding to the the
3677% region.
cristy3ed852e2009-09-05 21:47:34 +00003678%
3679% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3680%
3681% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3682% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3683% GetCacheViewAuthenticPixels() instead.
3684%
3685% The format of the GetVirtualPixels() method is:
3686%
cristy4c08aed2011-07-01 19:47:50 +00003687% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003688% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003689% ExceptionInfo *exception)
3690%
3691% A description of each parameter follows:
3692%
3693% o image: the image.
3694%
3695% o x,y,columns,rows: These values define the perimeter of a region of
3696% pixels.
3697%
3698% o exception: return any errors or warnings in this structure.
3699%
3700*/
cristy4c08aed2011-07-01 19:47:50 +00003701MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003702 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3703 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003704{
3705 CacheInfo
3706 *cache_info;
3707
cristy2036f5c2010-09-19 21:18:17 +00003708 const int
3709 id = GetOpenMPThreadId();
3710
cristy4c08aed2011-07-01 19:47:50 +00003711 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003712 *p;
cristy4c08aed2011-07-01 19:47:50 +00003713
cristy3ed852e2009-09-05 21:47:34 +00003714 assert(image != (const Image *) NULL);
3715 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003716 assert(image->cache != (Cache) NULL);
3717 cache_info=(CacheInfo *) image->cache;
3718 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003719 if (cache_info->methods.get_virtual_pixel_handler !=
3720 (GetVirtualPixelHandler) NULL)
3721 return(cache_info->methods.get_virtual_pixel_handler(image,
3722 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003723 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003724 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003725 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003726 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003727}
3728
3729/*
3730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3731% %
3732% %
3733% %
3734+ 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 %
3735% %
3736% %
3737% %
3738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3739%
cristy4c08aed2011-07-01 19:47:50 +00003740% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3741% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003742%
3743% The format of the GetVirtualPixelsCache() method is:
3744%
cristy4c08aed2011-07-01 19:47:50 +00003745% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003746%
3747% A description of each parameter follows:
3748%
3749% o image: the image.
3750%
3751*/
cristy4c08aed2011-07-01 19:47:50 +00003752static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003753{
3754 CacheInfo
3755 *cache_info;
3756
cristy5c9e6f22010-09-17 17:31:01 +00003757 const int
3758 id = GetOpenMPThreadId();
3759
cristye7cc7cf2010-09-21 13:26:47 +00003760 assert(image != (const Image *) NULL);
3761 assert(image->signature == MagickSignature);
3762 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003763 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003764 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003765 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003766 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003767}
3768
3769/*
3770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3771% %
3772% %
3773% %
3774+ G e t V i r t u a l P i x e l s N e x u s %
3775% %
3776% %
3777% %
3778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3779%
3780% GetVirtualPixelsNexus() returns the pixels associated with the specified
3781% cache nexus.
3782%
3783% The format of the GetVirtualPixelsNexus() method is:
3784%
cristy4c08aed2011-07-01 19:47:50 +00003785% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003786% NexusInfo *nexus_info)
3787%
3788% A description of each parameter follows:
3789%
3790% o cache: the pixel cache.
3791%
3792% o nexus_info: the cache nexus to return the colormap pixels.
3793%
3794*/
cristya6577ff2011-09-02 19:54:26 +00003795MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003796 NexusInfo *nexus_info)
3797{
3798 CacheInfo
3799 *cache_info;
3800
cristye7cc7cf2010-09-21 13:26:47 +00003801 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003802 cache_info=(CacheInfo *) cache;
3803 assert(cache_info->signature == MagickSignature);
3804 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003805 return((Quantum *) NULL);
3806 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003807}
3808
3809/*
3810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3811% %
3812% %
3813% %
3814+ M a s k P i x e l C a c h e N e x u s %
3815% %
3816% %
3817% %
3818%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3819%
3820% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3821% The method returns MagickTrue if the pixel region is masked, otherwise
3822% MagickFalse.
3823%
3824% The format of the MaskPixelCacheNexus() method is:
3825%
3826% MagickBooleanType MaskPixelCacheNexus(Image *image,
3827% NexusInfo *nexus_info,ExceptionInfo *exception)
3828%
3829% A description of each parameter follows:
3830%
3831% o image: the image.
3832%
3833% o nexus_info: the cache nexus to clip.
3834%
3835% o exception: return any errors or warnings in this structure.
3836%
3837*/
3838
cristy3aa93752011-12-18 15:54:24 +00003839static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3840 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003841{
3842 MagickRealType
3843 gamma;
3844
cristyaa83c2c2011-09-21 13:36:25 +00003845 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003846 {
3847 *composite=(*q);
3848 return;
3849 }
3850 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3851 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003852 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3853 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3854 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003855 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003856 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003857}
3858
3859static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3860 ExceptionInfo *exception)
3861{
3862 CacheInfo
3863 *cache_info;
3864
cristy4c08aed2011-07-01 19:47:50 +00003865 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003866 alpha,
3867 beta;
3868
3869 MagickSizeType
3870 number_pixels;
3871
3872 NexusInfo
3873 **clip_nexus,
3874 **image_nexus;
3875
cristy4c08aed2011-07-01 19:47:50 +00003876 register const Quantum
3877 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003878 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003879
cristy4c08aed2011-07-01 19:47:50 +00003880 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003881 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003882
cristye076a6e2010-08-15 19:59:43 +00003883 register ssize_t
3884 i;
3885
cristy3ed852e2009-09-05 21:47:34 +00003886 /*
3887 Apply clip mask.
3888 */
3889 if (image->debug != MagickFalse)
3890 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3891 if (image->mask == (Image *) NULL)
3892 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003893 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003894 if (cache_info == (Cache) NULL)
3895 return(MagickFalse);
3896 image_nexus=AcquirePixelCacheNexus(1);
3897 clip_nexus=AcquirePixelCacheNexus(1);
3898 if ((image_nexus == (NexusInfo **) NULL) ||
3899 (clip_nexus == (NexusInfo **) NULL))
3900 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003901 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3902 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3903 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003904 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003905 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3906 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003907 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003908 GetPixelInfo(image,&alpha);
3909 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003910 number_pixels=(MagickSizeType) nexus_info->region.width*
3911 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003912 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003913 {
cristy4c08aed2011-07-01 19:47:50 +00003914 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003915 break;
cristy803640d2011-11-17 02:11:32 +00003916 GetPixelInfoPixel(image,p,&alpha);
3917 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003918 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003919 &alpha,alpha.alpha,&beta);
3920 SetPixelRed(image,ClampToQuantum(beta.red),q);
3921 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3922 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3923 if (cache_info->colorspace == CMYKColorspace)
3924 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3925 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003926 p++;
3927 q++;
3928 r++;
3929 }
3930 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3931 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003932 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003933 return(MagickFalse);
3934 return(MagickTrue);
3935}
3936
3937/*
3938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3939% %
3940% %
3941% %
3942+ O p e n P i x e l C a c h e %
3943% %
3944% %
3945% %
3946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3947%
3948% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3949% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003950% metacontent, and memory mapping the cache if it is disk based. The cache
3951% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003952%
3953% The format of the OpenPixelCache() method is:
3954%
3955% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3956% ExceptionInfo *exception)
3957%
3958% A description of each parameter follows:
3959%
3960% o image: the image.
3961%
3962% o mode: ReadMode, WriteMode, or IOMode.
3963%
3964% o exception: return any errors or warnings in this structure.
3965%
3966*/
3967
cristyd43a46b2010-01-21 02:13:41 +00003968static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003969{
3970 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003971 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003972 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003973 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003974 {
3975 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003976 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003977 cache_info->length);
3978 }
3979}
3980
3981static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3982{
3983 CacheInfo
3984 *cache_info;
3985
3986 MagickOffsetType
3987 count,
3988 extent,
3989 offset;
3990
3991 cache_info=(CacheInfo *) image->cache;
3992 if (image->debug != MagickFalse)
3993 {
3994 char
3995 format[MaxTextExtent],
3996 message[MaxTextExtent];
3997
cristyb9080c92009-12-01 20:13:26 +00003998 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003999 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004000 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004001 cache_info->cache_filename,cache_info->file,format);
4002 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4003 }
4004 if (length != (MagickSizeType) ((MagickOffsetType) length))
4005 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004006 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004007 if (extent < 0)
4008 return(MagickFalse);
4009 if ((MagickSizeType) extent >= length)
4010 return(MagickTrue);
4011 offset=(MagickOffsetType) length-1;
4012 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4013 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4014}
4015
4016static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4017 ExceptionInfo *exception)
4018{
cristy3ed852e2009-09-05 21:47:34 +00004019 CacheInfo
4020 *cache_info,
4021 source_info;
4022
cristyf3a6a9d2010-11-07 21:02:56 +00004023 char
4024 format[MaxTextExtent],
4025 message[MaxTextExtent];
4026
cristy4c08aed2011-07-01 19:47:50 +00004027 MagickBooleanType
4028 status;
4029
cristy3ed852e2009-09-05 21:47:34 +00004030 MagickSizeType
4031 length,
4032 number_pixels;
4033
cristy3b8fe922011-12-29 18:56:23 +00004034 PixelChannelMap
4035 *p,
4036 *q;
4037
cristy3ed852e2009-09-05 21:47:34 +00004038 size_t
cristye076a6e2010-08-15 19:59:43 +00004039 columns,
cristy3ed852e2009-09-05 21:47:34 +00004040 packet_size;
4041
cristye7cc7cf2010-09-21 13:26:47 +00004042 assert(image != (const Image *) NULL);
4043 assert(image->signature == MagickSignature);
4044 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004045 if (image->debug != MagickFalse)
4046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4047 if ((image->columns == 0) || (image->rows == 0))
4048 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4049 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004050 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004051 source_info=(*cache_info);
4052 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004053 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004054 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004055 cache_info->storage_class=image->storage_class;
4056 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004057 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004058 cache_info->rows=image->rows;
4059 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004060 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004061 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004062 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4063 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004064 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004065 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004066 if (image->ping != MagickFalse)
4067 {
cristy73724512010-04-12 14:43:14 +00004068 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004069 cache_info->pixels=(Quantum *) NULL;
4070 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004071 cache_info->length=0;
4072 return(MagickTrue);
4073 }
cristy3ed852e2009-09-05 21:47:34 +00004074 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004075 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004076 if (image->metacontent_extent != 0)
4077 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004078 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004079 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004080 if (cache_info->columns != columns)
4081 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4082 image->filename);
4083 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004084 p=cache_info->channel_map;
4085 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004086 if ((cache_info->type != UndefinedCache) &&
4087 (cache_info->columns <= source_info.columns) &&
4088 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004089 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004090 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004091 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4092 {
4093 /*
4094 Inline pixel cache clone optimization.
4095 */
4096 if ((cache_info->columns == source_info.columns) &&
4097 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004098 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004099 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004100 (cache_info->metacontent_extent == source_info.metacontent_extent))
4101 return(MagickTrue);
4102 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4103 }
cristy3ed852e2009-09-05 21:47:34 +00004104 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004105 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004106 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004107 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4108 {
4109 status=AcquireMagickResource(MemoryResource,cache_info->length);
4110 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4111 (cache_info->type == MemoryCache))
4112 {
cristyd43a46b2010-01-21 02:13:41 +00004113 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004114 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004115 cache_info->pixels=source_info.pixels;
4116 else
4117 {
4118 /*
4119 Create memory pixel cache.
4120 */
cristy4c08aed2011-07-01 19:47:50 +00004121 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004122 if (image->debug != MagickFalse)
4123 {
cristy32cacff2011-12-31 03:36:27 +00004124 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004125 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004126 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4127 cache_info->filename,cache_info->mapped != MagickFalse ?
4128 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004129 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004130 format);
cristy3ed852e2009-09-05 21:47:34 +00004131 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4132 message);
4133 }
cristy3ed852e2009-09-05 21:47:34 +00004134 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004135 cache_info->metacontent=(void *) NULL;
4136 if (cache_info->metacontent_extent != 0)
4137 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004138 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004139 if (source_info.storage_class != UndefinedClass)
4140 {
cristy4c08aed2011-07-01 19:47:50 +00004141 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004142 exception);
4143 RelinquishPixelCachePixels(&source_info);
4144 }
cristy4c08aed2011-07-01 19:47:50 +00004145 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004146 }
4147 }
4148 RelinquishMagickResource(MemoryResource,cache_info->length);
4149 }
4150 /*
4151 Create pixel cache on disk.
4152 */
4153 status=AcquireMagickResource(DiskResource,cache_info->length);
4154 if (status == MagickFalse)
4155 {
4156 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4157 "CacheResourcesExhausted","`%s'",image->filename);
4158 return(MagickFalse);
4159 }
4160 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4161 {
4162 RelinquishMagickResource(DiskResource,cache_info->length);
4163 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4164 image->filename);
4165 return(MagickFalse);
4166 }
4167 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4168 cache_info->length);
4169 if (status == MagickFalse)
4170 {
4171 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4172 image->filename);
4173 return(MagickFalse);
4174 }
cristyed231572011-07-14 02:18:59 +00004175 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004176 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004177 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004178 cache_info->type=DiskCache;
4179 else
4180 {
4181 status=AcquireMagickResource(MapResource,cache_info->length);
4182 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4183 (cache_info->type != MemoryCache))
4184 cache_info->type=DiskCache;
4185 else
4186 {
cristy4c08aed2011-07-01 19:47:50 +00004187 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004188 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004189 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004190 {
cristy3ed852e2009-09-05 21:47:34 +00004191 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004192 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004193 }
4194 else
4195 {
4196 /*
4197 Create file-backed memory-mapped pixel cache.
4198 */
cristy4c08aed2011-07-01 19:47:50 +00004199 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004200 (void) ClosePixelCacheOnDisk(cache_info);
4201 cache_info->type=MapCache;
4202 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004203 cache_info->metacontent=(void *) NULL;
4204 if (cache_info->metacontent_extent != 0)
4205 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004206 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004207 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004208 {
4209 status=ClonePixelCachePixels(cache_info,&source_info,
4210 exception);
4211 RelinquishPixelCachePixels(&source_info);
4212 }
4213 if (image->debug != MagickFalse)
4214 {
cristy97e7a572009-12-05 15:07:53 +00004215 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004216 format);
cristyb51dff52011-05-19 16:55:47 +00004217 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004218 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004219 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004220 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004221 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004222 format);
cristy3ed852e2009-09-05 21:47:34 +00004223 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4224 message);
4225 }
cristy4c08aed2011-07-01 19:47:50 +00004226 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004227 }
4228 }
4229 RelinquishMagickResource(MapResource,cache_info->length);
4230 }
cristy4c08aed2011-07-01 19:47:50 +00004231 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004232 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4233 {
4234 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4235 RelinquishPixelCachePixels(&source_info);
4236 }
4237 if (image->debug != MagickFalse)
4238 {
cristyb9080c92009-12-01 20:13:26 +00004239 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004240 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004241 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004242 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004243 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004244 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004245 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4246 }
cristy4c08aed2011-07-01 19:47:50 +00004247 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004248}
4249
4250/*
4251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4252% %
4253% %
4254% %
4255+ P e r s i s t P i x e l C a c h e %
4256% %
4257% %
4258% %
4259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4260%
4261% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4262% persistent pixel cache is one that resides on disk and is not destroyed
4263% when the program exits.
4264%
4265% The format of the PersistPixelCache() method is:
4266%
4267% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4268% const MagickBooleanType attach,MagickOffsetType *offset,
4269% ExceptionInfo *exception)
4270%
4271% A description of each parameter follows:
4272%
4273% o image: the image.
4274%
4275% o filename: the persistent pixel cache filename.
4276%
cristyf3a6a9d2010-11-07 21:02:56 +00004277% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004278%
cristy3ed852e2009-09-05 21:47:34 +00004279% o initialize: A value other than zero initializes the persistent pixel
4280% cache.
4281%
4282% o offset: the offset in the persistent cache to store pixels.
4283%
4284% o exception: return any errors or warnings in this structure.
4285%
4286*/
4287MagickExport MagickBooleanType PersistPixelCache(Image *image,
4288 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4289 ExceptionInfo *exception)
4290{
4291 CacheInfo
4292 *cache_info,
4293 *clone_info;
4294
4295 Image
4296 clone_image;
4297
cristy3ed852e2009-09-05 21:47:34 +00004298 MagickBooleanType
4299 status;
4300
cristye076a6e2010-08-15 19:59:43 +00004301 ssize_t
4302 page_size;
4303
cristy3ed852e2009-09-05 21:47:34 +00004304 assert(image != (Image *) NULL);
4305 assert(image->signature == MagickSignature);
4306 if (image->debug != MagickFalse)
4307 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4308 assert(image->cache != (void *) NULL);
4309 assert(filename != (const char *) NULL);
4310 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004311 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004312 cache_info=(CacheInfo *) image->cache;
4313 assert(cache_info->signature == MagickSignature);
4314 if (attach != MagickFalse)
4315 {
4316 /*
cristy01b7eb02009-09-10 23:10:14 +00004317 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004318 */
4319 if (image->debug != MagickFalse)
4320 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004321 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004322 (void) CopyMagickString(cache_info->cache_filename,filename,
4323 MaxTextExtent);
4324 cache_info->type=DiskCache;
4325 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004326 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004327 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004328 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004329 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004330 }
cristy01b7eb02009-09-10 23:10:14 +00004331 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4332 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004333 {
cristyf84a1932010-01-03 18:00:18 +00004334 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004335 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004336 (cache_info->reference_count == 1))
4337 {
4338 int
4339 status;
4340
4341 /*
cristy01b7eb02009-09-10 23:10:14 +00004342 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004343 */
cristy320684d2011-09-23 14:55:47 +00004344 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004345 if (status == 0)
4346 {
4347 (void) CopyMagickString(cache_info->cache_filename,filename,
4348 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004349 *offset+=cache_info->length+page_size-(cache_info->length %
4350 page_size);
cristyf84a1932010-01-03 18:00:18 +00004351 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004352 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004353 if (image->debug != MagickFalse)
4354 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4355 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004356 return(MagickTrue);
4357 }
4358 }
cristyf84a1932010-01-03 18:00:18 +00004359 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004360 }
4361 /*
cristy01b7eb02009-09-10 23:10:14 +00004362 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004363 */
4364 clone_image=(*image);
4365 clone_info=(CacheInfo *) clone_image.cache;
4366 image->cache=ClonePixelCache(cache_info);
4367 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4368 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4369 cache_info->type=DiskCache;
4370 cache_info->offset=(*offset);
4371 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004372 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004373 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004374 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004375 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004376 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4377 return(status);
4378}
4379
4380/*
4381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4382% %
4383% %
4384% %
4385+ Q u e u e A u t h e n t i c N e x u s %
4386% %
4387% %
4388% %
4389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4390%
4391% QueueAuthenticNexus() allocates an region to store image pixels as defined
4392% by the region rectangle and returns a pointer to the region. This region is
4393% subsequently transferred from the pixel cache with
4394% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4395% pixels are transferred, otherwise a NULL is returned.
4396%
4397% The format of the QueueAuthenticNexus() method is:
4398%
cristy4c08aed2011-07-01 19:47:50 +00004399% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004400% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004401% const MagickBooleanType clone,NexusInfo *nexus_info,
4402% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004403%
4404% A description of each parameter follows:
4405%
4406% o image: the image.
4407%
4408% o x,y,columns,rows: These values define the perimeter of a region of
4409% pixels.
4410%
4411% o nexus_info: the cache nexus to set.
4412%
cristy65dbf172011-10-06 17:32:04 +00004413% o clone: clone the pixel cache.
4414%
cristy3ed852e2009-09-05 21:47:34 +00004415% o exception: return any errors or warnings in this structure.
4416%
4417*/
cristya6577ff2011-09-02 19:54:26 +00004418MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004419 const ssize_t y,const size_t columns,const size_t rows,
4420 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004421{
4422 CacheInfo
4423 *cache_info;
4424
4425 MagickOffsetType
4426 offset;
4427
4428 MagickSizeType
4429 number_pixels;
4430
4431 RectangleInfo
4432 region;
4433
4434 /*
4435 Validate pixel cache geometry.
4436 */
cristye7cc7cf2010-09-21 13:26:47 +00004437 assert(image != (const Image *) NULL);
4438 assert(image->signature == MagickSignature);
4439 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004440 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004441 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004442 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004443 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004444 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4445 {
4446 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4447 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004448 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004449 }
cristybb503372010-05-27 20:51:26 +00004450 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4451 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004452 {
4453 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4454 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004455 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004456 }
4457 offset=(MagickOffsetType) y*cache_info->columns+x;
4458 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004459 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004460 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4461 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4462 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004463 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004464 /*
4465 Return pixel cache.
4466 */
4467 region.x=x;
4468 region.y=y;
4469 region.width=columns;
4470 region.height=rows;
4471 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4472}
4473
4474/*
4475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4476% %
4477% %
4478% %
4479+ 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 %
4480% %
4481% %
4482% %
4483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4484%
4485% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4486% defined by the region rectangle and returns a pointer to the region. This
4487% region is subsequently transferred from the pixel cache with
4488% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4489% pixels are transferred, otherwise a NULL is returned.
4490%
4491% The format of the QueueAuthenticPixelsCache() method is:
4492%
cristy4c08aed2011-07-01 19:47:50 +00004493% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004494% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004495% ExceptionInfo *exception)
4496%
4497% A description of each parameter follows:
4498%
4499% o image: the image.
4500%
4501% o x,y,columns,rows: These values define the perimeter of a region of
4502% pixels.
4503%
4504% o exception: return any errors or warnings in this structure.
4505%
4506*/
cristy4c08aed2011-07-01 19:47:50 +00004507static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004508 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004509 ExceptionInfo *exception)
4510{
4511 CacheInfo
4512 *cache_info;
4513
cristy5c9e6f22010-09-17 17:31:01 +00004514 const int
4515 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004516
cristy4c08aed2011-07-01 19:47:50 +00004517 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004518 *q;
cristy4c08aed2011-07-01 19:47:50 +00004519
cristye7cc7cf2010-09-21 13:26:47 +00004520 assert(image != (const Image *) NULL);
4521 assert(image->signature == MagickSignature);
4522 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004523 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004524 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004525 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004526 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4527 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004528 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004529}
4530
4531/*
4532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4533% %
4534% %
4535% %
4536% Q u e u e A u t h e n t i c P i x e l s %
4537% %
4538% %
4539% %
4540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4541%
4542% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004543% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004544% region is returned, otherwise NULL is returned. The returned pointer may
4545% point to a temporary working buffer for the pixels or it may point to the
4546% final location of the pixels in memory.
4547%
4548% Write-only access means that any existing pixel values corresponding to
4549% the region are ignored. This is useful if the initial image is being
4550% created from scratch, or if the existing pixel values are to be
4551% completely replaced without need to refer to their pre-existing values.
4552% The application is free to read and write the pixel buffer returned by
4553% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4554% initialize the pixel array values. Initializing pixel array values is the
4555% application's responsibility.
4556%
4557% Performance is maximized if the selected region is part of one row, or
4558% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004559% pixels in-place (without a copy) if the image is in memory, or in a
4560% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004561% by the user.
4562%
4563% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004564% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4565% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4566% obtain the meta-content (of type void) corresponding to the region.
4567% Once the Quantum (and/or Quantum) array has been updated, the
4568% changes must be saved back to the underlying image using
4569% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004570%
4571% The format of the QueueAuthenticPixels() method is:
4572%
cristy4c08aed2011-07-01 19:47:50 +00004573% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004574% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004575% ExceptionInfo *exception)
4576%
4577% A description of each parameter follows:
4578%
4579% o image: the image.
4580%
4581% o x,y,columns,rows: These values define the perimeter of a region of
4582% pixels.
4583%
4584% o exception: return any errors or warnings in this structure.
4585%
4586*/
cristy4c08aed2011-07-01 19:47:50 +00004587MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004588 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004589 ExceptionInfo *exception)
4590{
4591 CacheInfo
4592 *cache_info;
4593
cristy2036f5c2010-09-19 21:18:17 +00004594 const int
4595 id = GetOpenMPThreadId();
4596
cristy4c08aed2011-07-01 19:47:50 +00004597 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004598 *q;
cristy4c08aed2011-07-01 19:47:50 +00004599
cristy3ed852e2009-09-05 21:47:34 +00004600 assert(image != (Image *) NULL);
4601 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004602 assert(image->cache != (Cache) NULL);
4603 cache_info=(CacheInfo *) image->cache;
4604 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004605 if (cache_info->methods.queue_authentic_pixels_handler !=
4606 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004607 {
cristyacd2ed22011-08-30 01:44:23 +00004608 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004609 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004610 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004611 }
cristy2036f5c2010-09-19 21:18:17 +00004612 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004613 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4614 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004615 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004616}
4617
4618/*
4619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4620% %
4621% %
4622% %
cristy4c08aed2011-07-01 19:47:50 +00004623+ 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 +00004624% %
4625% %
4626% %
4627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4628%
cristy4c08aed2011-07-01 19:47:50 +00004629% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004630% the pixel cache.
4631%
cristy4c08aed2011-07-01 19:47:50 +00004632% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004633%
cristy4c08aed2011-07-01 19:47:50 +00004634% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004635% NexusInfo *nexus_info,ExceptionInfo *exception)
4636%
4637% A description of each parameter follows:
4638%
4639% o cache_info: the pixel cache.
4640%
cristy4c08aed2011-07-01 19:47:50 +00004641% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004642%
4643% o exception: return any errors or warnings in this structure.
4644%
4645*/
cristy4c08aed2011-07-01 19:47:50 +00004646static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004647 NexusInfo *nexus_info,ExceptionInfo *exception)
4648{
4649 MagickOffsetType
4650 count,
4651 offset;
4652
4653 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004654 extent,
4655 length;
cristy3ed852e2009-09-05 21:47:34 +00004656
cristybb503372010-05-27 20:51:26 +00004657 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004658 y;
4659
cristy4c08aed2011-07-01 19:47:50 +00004660 register unsigned char
4661 *restrict q;
4662
cristybb503372010-05-27 20:51:26 +00004663 size_t
cristy3ed852e2009-09-05 21:47:34 +00004664 rows;
4665
cristy4c08aed2011-07-01 19:47:50 +00004666 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004667 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004668 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004669 return(MagickTrue);
4670 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4671 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004672 length=(MagickSizeType) nexus_info->region.width*
4673 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004674 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004675 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004676 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004677 switch (cache_info->type)
4678 {
4679 case MemoryCache:
4680 case MapCache:
4681 {
cristy4c08aed2011-07-01 19:47:50 +00004682 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004683 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004684
4685 /*
cristy4c08aed2011-07-01 19:47:50 +00004686 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004687 */
cristydd341db2010-03-04 19:06:38 +00004688 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004689 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004690 {
cristy48078b12010-09-23 17:11:01 +00004691 length=extent;
cristydd341db2010-03-04 19:06:38 +00004692 rows=1UL;
4693 }
cristy4c08aed2011-07-01 19:47:50 +00004694 p=(unsigned char *) cache_info->metacontent+offset*
4695 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004696 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004697 {
cristy8f036fe2010-09-18 02:02:00 +00004698 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004699 p+=cache_info->metacontent_extent*cache_info->columns;
4700 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004701 }
4702 break;
4703 }
4704 case DiskCache:
4705 {
4706 /*
cristy4c08aed2011-07-01 19:47:50 +00004707 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004708 */
4709 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4710 {
4711 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4712 cache_info->cache_filename);
4713 return(MagickFalse);
4714 }
cristydd341db2010-03-04 19:06:38 +00004715 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004716 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004717 {
cristy48078b12010-09-23 17:11:01 +00004718 length=extent;
cristydd341db2010-03-04 19:06:38 +00004719 rows=1UL;
4720 }
cristy48078b12010-09-23 17:11:01 +00004721 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004722 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004723 {
cristy48078b12010-09-23 17:11:01 +00004724 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004725 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004726 cache_info->metacontent_extent,length,(unsigned char *) q);
4727 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004728 break;
4729 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004730 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004731 }
cristybb503372010-05-27 20:51:26 +00004732 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004733 {
4734 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4735 cache_info->cache_filename);
4736 return(MagickFalse);
4737 }
4738 break;
4739 }
4740 default:
4741 break;
4742 }
4743 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004744 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004745 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004746 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004747 nexus_info->region.width,(double) nexus_info->region.height,(double)
4748 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004749 return(MagickTrue);
4750}
4751
4752/*
4753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4754% %
4755% %
4756% %
4757+ R e a d P i x e l C a c h e P i x e l s %
4758% %
4759% %
4760% %
4761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4762%
4763% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4764% cache.
4765%
4766% The format of the ReadPixelCachePixels() method is:
4767%
4768% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4769% NexusInfo *nexus_info,ExceptionInfo *exception)
4770%
4771% A description of each parameter follows:
4772%
4773% o cache_info: the pixel cache.
4774%
4775% o nexus_info: the cache nexus to read the pixels.
4776%
4777% o exception: return any errors or warnings in this structure.
4778%
4779*/
4780static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4781 NexusInfo *nexus_info,ExceptionInfo *exception)
4782{
4783 MagickOffsetType
4784 count,
4785 offset;
4786
4787 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004788 extent,
4789 length;
cristy3ed852e2009-09-05 21:47:34 +00004790
cristy4c08aed2011-07-01 19:47:50 +00004791 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004792 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004793
cristye076a6e2010-08-15 19:59:43 +00004794 register ssize_t
4795 y;
4796
cristybb503372010-05-27 20:51:26 +00004797 size_t
cristy3ed852e2009-09-05 21:47:34 +00004798 rows;
4799
cristy4c08aed2011-07-01 19:47:50 +00004800 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004801 return(MagickTrue);
4802 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4803 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004804 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004805 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004806 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004807 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004808 q=nexus_info->pixels;
4809 switch (cache_info->type)
4810 {
4811 case MemoryCache:
4812 case MapCache:
4813 {
cristy4c08aed2011-07-01 19:47:50 +00004814 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004815 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004816
4817 /*
4818 Read pixels from memory.
4819 */
cristydd341db2010-03-04 19:06:38 +00004820 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004821 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004822 {
cristy48078b12010-09-23 17:11:01 +00004823 length=extent;
cristydd341db2010-03-04 19:06:38 +00004824 rows=1UL;
4825 }
cristyed231572011-07-14 02:18:59 +00004826 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004827 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004828 {
cristy8f036fe2010-09-18 02:02:00 +00004829 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004830 p+=cache_info->number_channels*cache_info->columns;
4831 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004832 }
4833 break;
4834 }
4835 case DiskCache:
4836 {
4837 /*
4838 Read pixels from disk.
4839 */
4840 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4841 {
4842 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4843 cache_info->cache_filename);
4844 return(MagickFalse);
4845 }
cristydd341db2010-03-04 19:06:38 +00004846 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004847 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004848 {
cristy48078b12010-09-23 17:11:01 +00004849 length=extent;
cristydd341db2010-03-04 19:06:38 +00004850 rows=1UL;
4851 }
cristybb503372010-05-27 20:51:26 +00004852 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004853 {
4854 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004855 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004856 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004857 break;
4858 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004859 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004860 }
cristybb503372010-05-27 20:51:26 +00004861 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004862 {
4863 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4864 cache_info->cache_filename);
4865 return(MagickFalse);
4866 }
4867 break;
4868 }
4869 default:
4870 break;
4871 }
4872 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004873 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004874 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004875 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004876 nexus_info->region.width,(double) nexus_info->region.height,(double)
4877 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004878 return(MagickTrue);
4879}
4880
4881/*
4882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883% %
4884% %
4885% %
4886+ R e f e r e n c e P i x e l C a c h e %
4887% %
4888% %
4889% %
4890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4891%
4892% ReferencePixelCache() increments the reference count associated with the
4893% pixel cache returning a pointer to the cache.
4894%
4895% The format of the ReferencePixelCache method is:
4896%
4897% Cache ReferencePixelCache(Cache cache_info)
4898%
4899% A description of each parameter follows:
4900%
4901% o cache_info: the pixel cache.
4902%
4903*/
cristya6577ff2011-09-02 19:54:26 +00004904MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004905{
4906 CacheInfo
4907 *cache_info;
4908
4909 assert(cache != (Cache *) NULL);
4910 cache_info=(CacheInfo *) cache;
4911 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004912 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004913 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004914 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004915 return(cache_info);
4916}
4917
4918/*
4919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4920% %
4921% %
4922% %
4923+ S e t P i x e l C a c h e M e t h o d s %
4924% %
4925% %
4926% %
4927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4928%
4929% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4930%
4931% The format of the SetPixelCacheMethods() method is:
4932%
4933% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4934%
4935% A description of each parameter follows:
4936%
4937% o cache: the pixel cache.
4938%
4939% o cache_methods: Specifies a pointer to a CacheMethods structure.
4940%
4941*/
cristya6577ff2011-09-02 19:54:26 +00004942MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004943{
4944 CacheInfo
4945 *cache_info;
4946
4947 GetOneAuthenticPixelFromHandler
4948 get_one_authentic_pixel_from_handler;
4949
4950 GetOneVirtualPixelFromHandler
4951 get_one_virtual_pixel_from_handler;
4952
4953 /*
4954 Set cache pixel methods.
4955 */
4956 assert(cache != (Cache) NULL);
4957 assert(cache_methods != (CacheMethods *) NULL);
4958 cache_info=(CacheInfo *) cache;
4959 assert(cache_info->signature == MagickSignature);
4960 if (cache_info->debug != MagickFalse)
4961 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4962 cache_info->filename);
4963 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4964 cache_info->methods.get_virtual_pixel_handler=
4965 cache_methods->get_virtual_pixel_handler;
4966 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4967 cache_info->methods.destroy_pixel_handler=
4968 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004969 if (cache_methods->get_virtual_metacontent_from_handler !=
4970 (GetVirtualMetacontentFromHandler) NULL)
4971 cache_info->methods.get_virtual_metacontent_from_handler=
4972 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004973 if (cache_methods->get_authentic_pixels_handler !=
4974 (GetAuthenticPixelsHandler) NULL)
4975 cache_info->methods.get_authentic_pixels_handler=
4976 cache_methods->get_authentic_pixels_handler;
4977 if (cache_methods->queue_authentic_pixels_handler !=
4978 (QueueAuthenticPixelsHandler) NULL)
4979 cache_info->methods.queue_authentic_pixels_handler=
4980 cache_methods->queue_authentic_pixels_handler;
4981 if (cache_methods->sync_authentic_pixels_handler !=
4982 (SyncAuthenticPixelsHandler) NULL)
4983 cache_info->methods.sync_authentic_pixels_handler=
4984 cache_methods->sync_authentic_pixels_handler;
4985 if (cache_methods->get_authentic_pixels_from_handler !=
4986 (GetAuthenticPixelsFromHandler) NULL)
4987 cache_info->methods.get_authentic_pixels_from_handler=
4988 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004989 if (cache_methods->get_authentic_metacontent_from_handler !=
4990 (GetAuthenticMetacontentFromHandler) NULL)
4991 cache_info->methods.get_authentic_metacontent_from_handler=
4992 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004993 get_one_virtual_pixel_from_handler=
4994 cache_info->methods.get_one_virtual_pixel_from_handler;
4995 if (get_one_virtual_pixel_from_handler !=
4996 (GetOneVirtualPixelFromHandler) NULL)
4997 cache_info->methods.get_one_virtual_pixel_from_handler=
4998 cache_methods->get_one_virtual_pixel_from_handler;
4999 get_one_authentic_pixel_from_handler=
5000 cache_methods->get_one_authentic_pixel_from_handler;
5001 if (get_one_authentic_pixel_from_handler !=
5002 (GetOneAuthenticPixelFromHandler) NULL)
5003 cache_info->methods.get_one_authentic_pixel_from_handler=
5004 cache_methods->get_one_authentic_pixel_from_handler;
5005}
5006
5007/*
5008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009% %
5010% %
5011% %
5012+ S e t P i x e l C a c h e N e x u s P i x e l s %
5013% %
5014% %
5015% %
5016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5017%
5018% SetPixelCacheNexusPixels() defines the region of the cache for the
5019% specified cache nexus.
5020%
5021% The format of the SetPixelCacheNexusPixels() method is:
5022%
cristy4c08aed2011-07-01 19:47:50 +00005023% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005024% const RectangleInfo *region,NexusInfo *nexus_info,
5025% ExceptionInfo *exception)
5026%
5027% A description of each parameter follows:
5028%
5029% o image: the image.
5030%
5031% o region: A pointer to the RectangleInfo structure that defines the
5032% region of this particular cache nexus.
5033%
5034% o nexus_info: the cache nexus to set.
5035%
5036% o exception: return any errors or warnings in this structure.
5037%
5038*/
cristyabd6e372010-09-15 19:11:26 +00005039
5040static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5041 NexusInfo *nexus_info,ExceptionInfo *exception)
5042{
5043 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5044 return(MagickFalse);
5045 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005046 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005047 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005048 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005049 {
5050 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005051 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005052 nexus_info->length);
5053 }
cristy4c08aed2011-07-01 19:47:50 +00005054 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005055 {
5056 (void) ThrowMagickException(exception,GetMagickModule(),
5057 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5058 cache_info->filename);
5059 return(MagickFalse);
5060 }
5061 return(MagickTrue);
5062}
5063
cristy4c08aed2011-07-01 19:47:50 +00005064static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005065 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5066{
5067 CacheInfo
5068 *cache_info;
5069
5070 MagickBooleanType
5071 status;
5072
cristy3ed852e2009-09-05 21:47:34 +00005073 MagickSizeType
5074 length,
5075 number_pixels;
5076
cristy3ed852e2009-09-05 21:47:34 +00005077 cache_info=(CacheInfo *) image->cache;
5078 assert(cache_info->signature == MagickSignature);
5079 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005080 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005081 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005082 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5083 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005084 {
cristybb503372010-05-27 20:51:26 +00005085 ssize_t
cristybad067a2010-02-15 17:20:55 +00005086 x,
5087 y;
cristy3ed852e2009-09-05 21:47:34 +00005088
cristyeaedf062010-05-29 22:36:02 +00005089 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5090 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005091 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5092 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005093 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005094 ((nexus_info->region.width == cache_info->columns) ||
5095 ((nexus_info->region.width % cache_info->columns) == 0)))))
5096 {
5097 MagickOffsetType
5098 offset;
5099
5100 /*
5101 Pixels are accessed directly from memory.
5102 */
5103 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5104 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005105 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005106 offset;
5107 nexus_info->metacontent=(void *) NULL;
5108 if (cache_info->metacontent_extent != 0)
5109 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5110 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005111 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005112 }
5113 }
5114 /*
5115 Pixels are stored in a cache region until they are synced to the cache.
5116 */
5117 number_pixels=(MagickSizeType) nexus_info->region.width*
5118 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005119 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005120 if (cache_info->metacontent_extent != 0)
5121 length+=number_pixels*cache_info->metacontent_extent;
5122 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005123 {
5124 nexus_info->length=length;
5125 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5126 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005127 {
5128 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005129 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005130 }
cristy3ed852e2009-09-05 21:47:34 +00005131 }
5132 else
5133 if (nexus_info->length != length)
5134 {
5135 RelinquishCacheNexusPixels(nexus_info);
5136 nexus_info->length=length;
5137 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5138 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005139 {
5140 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005141 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005142 }
cristy3ed852e2009-09-05 21:47:34 +00005143 }
5144 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005145 nexus_info->metacontent=(void *) NULL;
5146 if (cache_info->metacontent_extent != 0)
5147 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005148 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005149 return(nexus_info->pixels);
5150}
5151
5152/*
5153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5154% %
5155% %
5156% %
5157% 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 %
5158% %
5159% %
5160% %
5161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5162%
5163% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5164% pixel cache and returns the previous setting. A virtual pixel is any pixel
5165% access that is outside the boundaries of the image cache.
5166%
5167% The format of the SetPixelCacheVirtualMethod() method is:
5168%
5169% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5170% const VirtualPixelMethod virtual_pixel_method)
5171%
5172% A description of each parameter follows:
5173%
5174% o image: the image.
5175%
5176% o virtual_pixel_method: choose the type of virtual pixel.
5177%
5178*/
cristyd1dd6e42011-09-04 01:46:08 +00005179MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005180 const VirtualPixelMethod virtual_pixel_method)
5181{
5182 CacheInfo
5183 *cache_info;
5184
5185 VirtualPixelMethod
5186 method;
5187
5188 assert(image != (Image *) NULL);
5189 assert(image->signature == MagickSignature);
5190 if (image->debug != MagickFalse)
5191 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5192 assert(image->cache != (Cache) NULL);
5193 cache_info=(CacheInfo *) image->cache;
5194 assert(cache_info->signature == MagickSignature);
5195 method=cache_info->virtual_pixel_method;
5196 cache_info->virtual_pixel_method=virtual_pixel_method;
5197 return(method);
5198}
5199
5200/*
5201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5202% %
5203% %
5204% %
5205+ 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 %
5206% %
5207% %
5208% %
5209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5210%
5211% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5212% in-memory or disk cache. The method returns MagickTrue if the pixel region
5213% is synced, otherwise MagickFalse.
5214%
5215% The format of the SyncAuthenticPixelCacheNexus() method is:
5216%
5217% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5218% NexusInfo *nexus_info,ExceptionInfo *exception)
5219%
5220% A description of each parameter follows:
5221%
5222% o image: the image.
5223%
5224% o nexus_info: the cache nexus to sync.
5225%
5226% o exception: return any errors or warnings in this structure.
5227%
5228*/
cristya6577ff2011-09-02 19:54:26 +00005229MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005230 NexusInfo *nexus_info,ExceptionInfo *exception)
5231{
5232 CacheInfo
5233 *cache_info;
5234
5235 MagickBooleanType
5236 status;
5237
5238 /*
5239 Transfer pixels to the cache.
5240 */
5241 assert(image != (Image *) NULL);
5242 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005243 if (image->cache == (Cache) NULL)
5244 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5245 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005246 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005247 if (cache_info->type == UndefinedCache)
5248 return(MagickFalse);
5249 if ((image->clip_mask != (Image *) NULL) &&
5250 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5251 return(MagickFalse);
5252 if ((image->mask != (Image *) NULL) &&
5253 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5254 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005255 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005256 return(MagickTrue);
5257 assert(cache_info->signature == MagickSignature);
5258 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005259 if ((cache_info->metacontent_extent != 0) &&
5260 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005261 return(MagickFalse);
5262 return(status);
5263}
5264
5265/*
5266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5267% %
5268% %
5269% %
5270+ S y n c A u t h e n t i c P i x e l C a c h e %
5271% %
5272% %
5273% %
5274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5275%
5276% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5277% or disk cache. The method returns MagickTrue if the pixel region is synced,
5278% otherwise MagickFalse.
5279%
5280% The format of the SyncAuthenticPixelsCache() method is:
5281%
5282% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5283% ExceptionInfo *exception)
5284%
5285% A description of each parameter follows:
5286%
5287% o image: the image.
5288%
5289% o exception: return any errors or warnings in this structure.
5290%
5291*/
5292static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5293 ExceptionInfo *exception)
5294{
5295 CacheInfo
5296 *cache_info;
5297
cristy5c9e6f22010-09-17 17:31:01 +00005298 const int
5299 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005300
cristy4c08aed2011-07-01 19:47:50 +00005301 MagickBooleanType
5302 status;
5303
cristye7cc7cf2010-09-21 13:26:47 +00005304 assert(image != (Image *) NULL);
5305 assert(image->signature == MagickSignature);
5306 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005307 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005308 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005309 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005310 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5311 exception);
5312 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005313}
5314
5315/*
5316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5317% %
5318% %
5319% %
5320% S y n c A u t h e n t i c P i x e l s %
5321% %
5322% %
5323% %
5324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5325%
5326% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5327% The method returns MagickTrue if the pixel region is flushed, otherwise
5328% MagickFalse.
5329%
5330% The format of the SyncAuthenticPixels() method is:
5331%
5332% MagickBooleanType SyncAuthenticPixels(Image *image,
5333% ExceptionInfo *exception)
5334%
5335% A description of each parameter follows:
5336%
5337% o image: the image.
5338%
5339% o exception: return any errors or warnings in this structure.
5340%
5341*/
5342MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5343 ExceptionInfo *exception)
5344{
5345 CacheInfo
5346 *cache_info;
5347
cristy2036f5c2010-09-19 21:18:17 +00005348 const int
5349 id = GetOpenMPThreadId();
5350
cristy4c08aed2011-07-01 19:47:50 +00005351 MagickBooleanType
5352 status;
5353
cristy3ed852e2009-09-05 21:47:34 +00005354 assert(image != (Image *) NULL);
5355 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005356 assert(image->cache != (Cache) NULL);
5357 cache_info=(CacheInfo *) image->cache;
5358 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005359 if (cache_info->methods.sync_authentic_pixels_handler !=
5360 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005361 {
5362 status=cache_info->methods.sync_authentic_pixels_handler(image,
5363 exception);
5364 return(status);
5365 }
cristy2036f5c2010-09-19 21:18:17 +00005366 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005367 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5368 exception);
5369 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005370}
5371
5372/*
5373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5374% %
5375% %
5376% %
cristyd1dd6e42011-09-04 01:46:08 +00005377+ 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 +00005378% %
5379% %
5380% %
5381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5382%
5383% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5384% The method returns MagickTrue if the pixel region is flushed, otherwise
5385% MagickFalse.
5386%
5387% The format of the SyncImagePixelCache() method is:
5388%
5389% MagickBooleanType SyncImagePixelCache(Image *image,
5390% ExceptionInfo *exception)
5391%
5392% A description of each parameter follows:
5393%
5394% o image: the image.
5395%
5396% o exception: return any errors or warnings in this structure.
5397%
5398*/
cristyd1dd6e42011-09-04 01:46:08 +00005399MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005400 ExceptionInfo *exception)
5401{
5402 CacheInfo
5403 *cache_info;
5404
5405 assert(image != (Image *) NULL);
5406 assert(exception != (ExceptionInfo *) NULL);
5407 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5408 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5409}
5410
5411/*
5412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5413% %
5414% %
5415% %
cristy4c08aed2011-07-01 19:47:50 +00005416+ 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 +00005417% %
5418% %
5419% %
5420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5421%
cristy4c08aed2011-07-01 19:47:50 +00005422% WritePixelCacheMetacontent() writes the meta-content to the specified region
5423% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005424%
cristy4c08aed2011-07-01 19:47:50 +00005425% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005426%
cristy4c08aed2011-07-01 19:47:50 +00005427% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005428% NexusInfo *nexus_info,ExceptionInfo *exception)
5429%
5430% A description of each parameter follows:
5431%
5432% o cache_info: the pixel cache.
5433%
cristy4c08aed2011-07-01 19:47:50 +00005434% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005435%
5436% o exception: return any errors or warnings in this structure.
5437%
5438*/
cristy4c08aed2011-07-01 19:47:50 +00005439static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005440 NexusInfo *nexus_info,ExceptionInfo *exception)
5441{
5442 MagickOffsetType
5443 count,
5444 offset;
5445
5446 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005447 extent,
5448 length;
cristy3ed852e2009-09-05 21:47:34 +00005449
cristy4c08aed2011-07-01 19:47:50 +00005450 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005451 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005452
cristybb503372010-05-27 20:51:26 +00005453 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005454 y;
5455
cristybb503372010-05-27 20:51:26 +00005456 size_t
cristy3ed852e2009-09-05 21:47:34 +00005457 rows;
5458
cristy4c08aed2011-07-01 19:47:50 +00005459 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005460 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005461 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005462 return(MagickTrue);
5463 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5464 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005465 length=(MagickSizeType) nexus_info->region.width*
5466 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005467 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005468 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005469 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005470 switch (cache_info->type)
5471 {
5472 case MemoryCache:
5473 case MapCache:
5474 {
cristy4c08aed2011-07-01 19:47:50 +00005475 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005476 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005477
5478 /*
cristy4c08aed2011-07-01 19:47:50 +00005479 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005480 */
cristydd341db2010-03-04 19:06:38 +00005481 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005482 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005483 {
cristy48078b12010-09-23 17:11:01 +00005484 length=extent;
cristydd341db2010-03-04 19:06:38 +00005485 rows=1UL;
5486 }
cristy4c08aed2011-07-01 19:47:50 +00005487 q=(unsigned char *) cache_info->metacontent+offset*
5488 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005489 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005490 {
cristy8f036fe2010-09-18 02:02:00 +00005491 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005492 p+=nexus_info->region.width*cache_info->metacontent_extent;
5493 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005494 }
5495 break;
5496 }
5497 case DiskCache:
5498 {
5499 /*
cristy4c08aed2011-07-01 19:47:50 +00005500 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005501 */
5502 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5503 {
5504 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5505 cache_info->cache_filename);
5506 return(MagickFalse);
5507 }
cristydd341db2010-03-04 19:06:38 +00005508 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005509 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005510 {
cristy48078b12010-09-23 17:11:01 +00005511 length=extent;
cristydd341db2010-03-04 19:06:38 +00005512 rows=1UL;
5513 }
cristy48078b12010-09-23 17:11:01 +00005514 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005515 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005516 {
cristy48078b12010-09-23 17:11:01 +00005517 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005518 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005519 cache_info->metacontent_extent,length,(const unsigned char *) p);
5520 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005521 break;
cristy4c08aed2011-07-01 19:47:50 +00005522 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005523 offset+=cache_info->columns;
5524 }
cristybb503372010-05-27 20:51:26 +00005525 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005526 {
5527 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5528 cache_info->cache_filename);
5529 return(MagickFalse);
5530 }
5531 break;
5532 }
5533 default:
5534 break;
5535 }
5536 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005537 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005538 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005539 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005540 nexus_info->region.width,(double) nexus_info->region.height,(double)
5541 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005542 return(MagickTrue);
5543}
5544
5545/*
5546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5547% %
5548% %
5549% %
5550+ W r i t e C a c h e P i x e l s %
5551% %
5552% %
5553% %
5554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5555%
5556% WritePixelCachePixels() writes image pixels to the specified region of the
5557% pixel cache.
5558%
5559% The format of the WritePixelCachePixels() method is:
5560%
5561% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5562% NexusInfo *nexus_info,ExceptionInfo *exception)
5563%
5564% A description of each parameter follows:
5565%
5566% o cache_info: the pixel cache.
5567%
5568% o nexus_info: the cache nexus to write the pixels.
5569%
5570% o exception: return any errors or warnings in this structure.
5571%
5572*/
5573static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5574 NexusInfo *nexus_info,ExceptionInfo *exception)
5575{
5576 MagickOffsetType
5577 count,
5578 offset;
5579
5580 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005581 extent,
5582 length;
cristy3ed852e2009-09-05 21:47:34 +00005583
cristy4c08aed2011-07-01 19:47:50 +00005584 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005585 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005586
cristybb503372010-05-27 20:51:26 +00005587 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005588 y;
5589
cristybb503372010-05-27 20:51:26 +00005590 size_t
cristy3ed852e2009-09-05 21:47:34 +00005591 rows;
5592
cristy4c08aed2011-07-01 19:47:50 +00005593 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005594 return(MagickTrue);
5595 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5596 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005597 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005598 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005599 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005600 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005601 p=nexus_info->pixels;
5602 switch (cache_info->type)
5603 {
5604 case MemoryCache:
5605 case MapCache:
5606 {
cristy4c08aed2011-07-01 19:47:50 +00005607 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005608 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005609
5610 /*
5611 Write pixels to memory.
5612 */
cristydd341db2010-03-04 19:06:38 +00005613 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005614 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005615 {
cristy48078b12010-09-23 17:11:01 +00005616 length=extent;
cristydd341db2010-03-04 19:06:38 +00005617 rows=1UL;
5618 }
cristyed231572011-07-14 02:18:59 +00005619 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005620 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005621 {
cristy8f036fe2010-09-18 02:02:00 +00005622 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005623 p+=nexus_info->region.width*cache_info->number_channels;
5624 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005625 }
5626 break;
5627 }
5628 case DiskCache:
5629 {
5630 /*
5631 Write pixels to disk.
5632 */
5633 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5634 {
5635 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5636 cache_info->cache_filename);
5637 return(MagickFalse);
5638 }
cristydd341db2010-03-04 19:06:38 +00005639 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005640 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005641 {
cristy48078b12010-09-23 17:11:01 +00005642 length=extent;
cristydd341db2010-03-04 19:06:38 +00005643 rows=1UL;
5644 }
cristybb503372010-05-27 20:51:26 +00005645 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005646 {
5647 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005648 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005649 p);
5650 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005651 break;
cristyed231572011-07-14 02:18:59 +00005652 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005653 offset+=cache_info->columns;
5654 }
cristybb503372010-05-27 20:51:26 +00005655 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005656 {
5657 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5658 cache_info->cache_filename);
5659 return(MagickFalse);
5660 }
5661 break;
5662 }
5663 default:
5664 break;
5665 }
5666 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005667 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005668 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005669 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005670 nexus_info->region.width,(double) nexus_info->region.height,(double)
5671 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005672 return(MagickTrue);
5673}