blob: 0745074aa4ababdd776195233d89961fc81756a7 [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 }
974 if (clone_info->type == DiskCache)
975 {
cristy3dedf062011-07-02 14:07:40 +0000976 if ((cache_info->type == DiskCache) &&
977 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
978 {
979 (void) ClosePixelCacheOnDisk(clone_info);
980 *clone_info->cache_filename='\0';
981 }
982 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000983 {
cristy4c08aed2011-07-01 19:47:50 +0000984 if (cache_info->type == DiskCache)
985 (void) ClosePixelCacheOnDisk(cache_info);
986 blob=(unsigned char *) RelinquishMagickMemory(blob);
987 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
988 clone_info->cache_filename);
989 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000990 }
cristy4c08aed2011-07-01 19:47:50 +0000991 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000992 }
993 /*
cristy4c08aed2011-07-01 19:47:50 +0000994 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000995 */
cristy4c08aed2011-07-01 19:47:50 +0000996 status=MagickTrue;
997 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
cristy4c08aed2011-07-01 19:47:50 +0000999 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001000 {
cristy9e0719b2011-12-29 03:45:45 +00001001 register ssize_t
1002 i;
1003
cristy3ed852e2009-09-05 21:47:34 +00001004 /*
cristy4c08aed2011-07-01 19:47:50 +00001005 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001006 */
cristyed231572011-07-14 02:18:59 +00001007 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001008 if (cache_info->type != DiskCache)
1009 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1010 length);
cristy3ed852e2009-09-05 21:47:34 +00001011 else
1012 {
cristy4c08aed2011-07-01 19:47:50 +00001013 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1014 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001015 {
cristy4c08aed2011-07-01 19:47:50 +00001016 status=MagickFalse;
1017 break;
cristy3ed852e2009-09-05 21:47:34 +00001018 }
1019 }
cristy4c08aed2011-07-01 19:47:50 +00001020 cache_offset+=length;
1021 if ((y < (ssize_t) clone_info->rows) &&
1022 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001023 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001024 {
cristy9e0719b2011-12-29 03:45:45 +00001025 PixelChannel
1026 channel;
1027
1028 PixelTrait
1029 traits;
1030
1031 ssize_t
1032 offset;
1033
cristy4c08aed2011-07-01 19:47:50 +00001034 /*
cristy9e0719b2011-12-29 03:45:45 +00001035 Write a set of pixel channels .
cristy4c08aed2011-07-01 19:47:50 +00001036 */
cristy9e0719b2011-12-29 03:45:45 +00001037 channel=clone_info->channel_map[i].channel;
1038 traits=cache_info->channel_map[channel].traits;
1039 if (traits == UndefinedPixelTrait)
1040 {
1041 clone_offset+=sizeof(Quantum);
1042 continue;
1043 }
1044 offset=cache_info->channel_map[channel].offset;
cristy4c08aed2011-07-01 19:47:50 +00001045 if (clone_info->type != DiskCache)
1046 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristy9e0719b2011-12-29 03:45:45 +00001047 blob+offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +00001048 else
1049 {
cristy9e0719b2011-12-29 03:45:45 +00001050 count=WritePixelCacheRegion(clone_info,clone_offset,
1051 sizeof(Quantum),blob+offset*sizeof(Quantum));
1052 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +00001053 {
1054 status=MagickFalse;
1055 break;
1056 }
1057 }
cristy9e0719b2011-12-29 03:45:45 +00001058 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001059 }
1060 }
cristyed231572011-07-14 02:18:59 +00001061 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001062 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1063 for ( ; x < (ssize_t) clone_info->columns; x++)
1064 {
1065 /*
cristy9e0719b2011-12-29 03:45:45 +00001066 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001067 */
1068 if (clone_info->type != DiskCache)
1069 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1070 length);
1071 else
1072 {
1073 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1074 if ((MagickSizeType) count != length)
1075 {
1076 status=MagickFalse;
1077 break;
1078 }
1079 }
1080 clone_offset+=length;
1081 }
1082 }
cristyed231572011-07-14 02:18:59 +00001083 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001084 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1085 for ( ; y < (ssize_t) clone_info->rows; y++)
1086 {
1087 /*
cristy9e0719b2011-12-29 03:45:45 +00001088 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001089 */
1090 for (x=0; x < (ssize_t) clone_info->columns; x++)
1091 {
1092 if (clone_info->type != DiskCache)
1093 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1094 length);
1095 else
1096 {
1097 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1098 if ((MagickSizeType) count != length)
1099 {
1100 status=MagickFalse;
1101 break;
1102 }
1103 }
1104 clone_offset+=length;
1105 }
1106 }
cristy9e0719b2011-12-29 03:45:45 +00001107 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001108 (clone_info->metacontent_extent != 0))
1109 {
1110 /*
1111 Clone metacontent.
1112 */
1113 for (y=0; y < (ssize_t) cache_info->rows; y++)
1114 {
1115 for (x=0; x < (ssize_t) cache_info->columns; x++)
1116 {
1117 /*
1118 Read a set of metacontent.
1119 */
1120 length=cache_info->metacontent_extent;
1121 if (cache_info->type != DiskCache)
1122 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1123 cache_offset,length);
1124 else
1125 {
1126 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1127 if ((MagickSizeType) count != length)
1128 {
1129 status=MagickFalse;
1130 break;
1131 }
1132 }
1133 cache_offset+=length;
1134 if ((y < (ssize_t) clone_info->rows) &&
1135 (x < (ssize_t) clone_info->columns))
1136 {
1137 /*
1138 Write a set of metacontent.
1139 */
1140 length=clone_info->metacontent_extent;
1141 if (clone_info->type != DiskCache)
1142 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1143 blob,length);
1144 else
1145 {
1146 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1147 blob);
1148 if ((MagickSizeType) count != length)
1149 {
1150 status=MagickFalse;
1151 break;
1152 }
1153 }
1154 clone_offset+=length;
1155 }
1156 }
1157 length=clone_info->metacontent_extent;
1158 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1159 for ( ; x < (ssize_t) clone_info->columns; x++)
1160 {
1161 /*
cristy9e0719b2011-12-29 03:45:45 +00001162 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001163 */
1164 if (clone_info->type != DiskCache)
1165 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1166 blob,length);
1167 else
1168 {
cristy208b1002011-08-07 18:51:50 +00001169 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001170 if ((MagickSizeType) count != length)
1171 {
1172 status=MagickFalse;
1173 break;
1174 }
1175 }
1176 clone_offset+=length;
1177 }
1178 }
1179 length=clone_info->metacontent_extent;
1180 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1181 for ( ; y < (ssize_t) clone_info->rows; y++)
1182 {
1183 /*
cristy9e0719b2011-12-29 03:45:45 +00001184 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001185 */
1186 for (x=0; x < (ssize_t) clone_info->columns; x++)
1187 {
1188 if (clone_info->type != DiskCache)
1189 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1190 blob,length);
1191 else
1192 {
1193 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1194 if ((MagickSizeType) count != length)
1195 {
1196 status=MagickFalse;
1197 break;
1198 }
1199 }
1200 clone_offset+=length;
1201 }
1202 }
1203 }
1204 if (clone_info->type == DiskCache)
1205 (void) ClosePixelCacheOnDisk(clone_info);
1206 if (cache_info->type == DiskCache)
1207 (void) ClosePixelCacheOnDisk(cache_info);
1208 blob=(unsigned char *) RelinquishMagickMemory(blob);
1209 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001210}
1211
1212static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1213 CacheInfo *cache_info,ExceptionInfo *exception)
1214{
cristy3dfccb22011-12-28 21:47:20 +00001215 PixelChannelMap
1216 *p,
1217 *q;
1218
cristy5a7fbfb2010-11-06 16:10:59 +00001219 if (cache_info->type == PingCache)
1220 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001221 p=cache_info->channel_map;
1222 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001223 if ((cache_info->columns == clone_info->columns) &&
1224 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001225 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001226 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001227 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1228 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1229 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001230}
1231
1232/*
1233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1234% %
1235% %
1236% %
1237+ C l o n e P i x e l C a c h e M e t h o d s %
1238% %
1239% %
1240% %
1241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1242%
1243% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1244% another.
1245%
1246% The format of the ClonePixelCacheMethods() method is:
1247%
1248% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1249%
1250% A description of each parameter follows:
1251%
1252% o clone: Specifies a pointer to a Cache structure.
1253%
1254% o cache: the pixel cache.
1255%
1256*/
cristya6577ff2011-09-02 19:54:26 +00001257MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001258{
1259 CacheInfo
1260 *cache_info,
1261 *source_info;
1262
1263 assert(clone != (Cache) NULL);
1264 source_info=(CacheInfo *) clone;
1265 assert(source_info->signature == MagickSignature);
1266 if (source_info->debug != MagickFalse)
1267 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1268 source_info->filename);
1269 assert(cache != (Cache) NULL);
1270 cache_info=(CacheInfo *) cache;
1271 assert(cache_info->signature == MagickSignature);
1272 source_info->methods=cache_info->methods;
1273}
1274
1275/*
1276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1277% %
1278% %
1279% %
1280+ D e s t r o y I m a g e P i x e l C a c h e %
1281% %
1282% %
1283% %
1284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285%
1286% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1287%
1288% The format of the DestroyImagePixelCache() method is:
1289%
1290% void DestroyImagePixelCache(Image *image)
1291%
1292% A description of each parameter follows:
1293%
1294% o image: the image.
1295%
1296*/
1297static void DestroyImagePixelCache(Image *image)
1298{
1299 assert(image != (Image *) NULL);
1300 assert(image->signature == MagickSignature);
1301 if (image->debug != MagickFalse)
1302 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1303 if (image->cache == (void *) NULL)
1304 return;
1305 image->cache=DestroyPixelCache(image->cache);
1306}
1307
1308/*
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310% %
1311% %
1312% %
1313+ D e s t r o y I m a g e P i x e l s %
1314% %
1315% %
1316% %
1317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1318%
1319% DestroyImagePixels() deallocates memory associated with the pixel cache.
1320%
1321% The format of the DestroyImagePixels() method is:
1322%
1323% void DestroyImagePixels(Image *image)
1324%
1325% A description of each parameter follows:
1326%
1327% o image: the image.
1328%
1329*/
1330MagickExport void DestroyImagePixels(Image *image)
1331{
1332 CacheInfo
1333 *cache_info;
1334
1335 assert(image != (const Image *) NULL);
1336 assert(image->signature == MagickSignature);
1337 if (image->debug != MagickFalse)
1338 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1339 assert(image->cache != (Cache) NULL);
1340 cache_info=(CacheInfo *) image->cache;
1341 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001342 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1343 {
1344 cache_info->methods.destroy_pixel_handler(image);
1345 return;
1346 }
cristy2036f5c2010-09-19 21:18:17 +00001347 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001348}
1349
1350/*
1351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1352% %
1353% %
1354% %
1355+ D e s t r o y P i x e l C a c h e %
1356% %
1357% %
1358% %
1359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360%
1361% DestroyPixelCache() deallocates memory associated with the pixel cache.
1362%
1363% The format of the DestroyPixelCache() method is:
1364%
1365% Cache DestroyPixelCache(Cache cache)
1366%
1367% A description of each parameter follows:
1368%
1369% o cache: the pixel cache.
1370%
1371*/
1372
1373static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1374{
1375 switch (cache_info->type)
1376 {
1377 case MemoryCache:
1378 {
1379 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001380 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001381 cache_info->pixels);
1382 else
cristy4c08aed2011-07-01 19:47:50 +00001383 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001384 (size_t) cache_info->length);
1385 RelinquishMagickResource(MemoryResource,cache_info->length);
1386 break;
1387 }
1388 case MapCache:
1389 {
cristy4c08aed2011-07-01 19:47:50 +00001390 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001391 cache_info->length);
1392 RelinquishMagickResource(MapResource,cache_info->length);
1393 }
1394 case DiskCache:
1395 {
1396 if (cache_info->file != -1)
1397 (void) ClosePixelCacheOnDisk(cache_info);
1398 RelinquishMagickResource(DiskResource,cache_info->length);
1399 break;
1400 }
1401 default:
1402 break;
1403 }
1404 cache_info->type=UndefinedCache;
1405 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001406 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001407}
1408
cristya6577ff2011-09-02 19:54:26 +00001409MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001410{
1411 CacheInfo
1412 *cache_info;
1413
cristy3ed852e2009-09-05 21:47:34 +00001414 assert(cache != (Cache) NULL);
1415 cache_info=(CacheInfo *) cache;
1416 assert(cache_info->signature == MagickSignature);
1417 if (cache_info->debug != MagickFalse)
1418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1419 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001420 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001421 cache_info->reference_count--;
1422 if (cache_info->reference_count != 0)
1423 {
cristyf84a1932010-01-03 18:00:18 +00001424 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001425 return((Cache) NULL);
1426 }
cristyf84a1932010-01-03 18:00:18 +00001427 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001428 if (cache_resources != (SplayTreeInfo *) NULL)
1429 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001430 if (cache_info->debug != MagickFalse)
1431 {
1432 char
1433 message[MaxTextExtent];
1434
cristyb51dff52011-05-19 16:55:47 +00001435 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001436 cache_info->filename);
1437 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1438 }
cristyc2e1bdd2009-09-10 23:43:34 +00001439 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1440 (cache_info->type != DiskCache)))
1441 RelinquishPixelCachePixels(cache_info);
1442 else
1443 {
1444 RelinquishPixelCachePixels(cache_info);
1445 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1446 }
cristy3ed852e2009-09-05 21:47:34 +00001447 *cache_info->cache_filename='\0';
1448 if (cache_info->nexus_info != (NexusInfo **) NULL)
1449 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1450 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001451 if (cache_info->random_info != (RandomInfo *) NULL)
1452 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001453 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1454 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1455 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1456 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001457 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001458 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001459 cache=(Cache) NULL;
1460 return(cache);
1461}
1462
1463/*
1464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465% %
1466% %
1467% %
1468+ D e s t r o y P i x e l C a c h e N e x u s %
1469% %
1470% %
1471% %
1472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1473%
1474% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1475%
1476% The format of the DestroyPixelCacheNexus() method is:
1477%
1478% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001479% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001480%
1481% A description of each parameter follows:
1482%
1483% o nexus_info: the nexus to destroy.
1484%
1485% o number_threads: the number of nexus threads.
1486%
1487*/
1488
1489static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1490{
1491 if (nexus_info->mapped == MagickFalse)
1492 (void) RelinquishMagickMemory(nexus_info->cache);
1493 else
1494 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001495 nexus_info->cache=(Quantum *) NULL;
1496 nexus_info->pixels=(Quantum *) NULL;
1497 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001498 nexus_info->length=0;
1499 nexus_info->mapped=MagickFalse;
1500}
1501
cristya6577ff2011-09-02 19:54:26 +00001502MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001503 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001504{
cristybb503372010-05-27 20:51:26 +00001505 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001506 i;
1507
1508 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001509 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001510 {
cristy4c08aed2011-07-01 19:47:50 +00001511 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001512 RelinquishCacheNexusPixels(nexus_info[i]);
1513 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001514 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001515 }
cristyb41ee102010-10-04 16:46:15 +00001516 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001517 return(nexus_info);
1518}
1519
1520/*
1521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522% %
1523% %
1524% %
cristy4c08aed2011-07-01 19:47:50 +00001525% 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 +00001526% %
1527% %
1528% %
1529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1530%
cristy4c08aed2011-07-01 19:47:50 +00001531% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1532% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1533% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001534%
cristy4c08aed2011-07-01 19:47:50 +00001535% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001536%
cristy4c08aed2011-07-01 19:47:50 +00001537% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001538%
1539% A description of each parameter follows:
1540%
1541% o image: the image.
1542%
1543*/
cristy4c08aed2011-07-01 19:47:50 +00001544MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001545{
1546 CacheInfo
1547 *cache_info;
1548
cristy5c9e6f22010-09-17 17:31:01 +00001549 const int
1550 id = GetOpenMPThreadId();
1551
cristy4c08aed2011-07-01 19:47:50 +00001552 void
1553 *metacontent;
1554
cristye7cc7cf2010-09-21 13:26:47 +00001555 assert(image != (const Image *) NULL);
1556 assert(image->signature == MagickSignature);
1557 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001558 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001559 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001560 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1561 (GetAuthenticMetacontentFromHandler) NULL)
1562 {
1563 metacontent=cache_info->methods.
1564 get_authentic_metacontent_from_handler(image);
1565 return(metacontent);
1566 }
cristy6ebe97c2010-07-03 01:17:28 +00001567 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001568 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1569 cache_info->nexus_info[id]);
1570 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001571}
1572
1573/*
1574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1575% %
1576% %
1577% %
cristy4c08aed2011-07-01 19:47:50 +00001578+ 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 +00001579% %
1580% %
1581% %
1582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583%
cristy4c08aed2011-07-01 19:47:50 +00001584% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1585% with the last call to QueueAuthenticPixelsCache() or
1586% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001587%
cristy4c08aed2011-07-01 19:47:50 +00001588% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001589%
cristy4c08aed2011-07-01 19:47:50 +00001590% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001591%
1592% A description of each parameter follows:
1593%
1594% o image: the image.
1595%
1596*/
cristy4c08aed2011-07-01 19:47:50 +00001597static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001598{
1599 CacheInfo
1600 *cache_info;
1601
cristy2036f5c2010-09-19 21:18:17 +00001602 const int
1603 id = GetOpenMPThreadId();
1604
cristy4c08aed2011-07-01 19:47:50 +00001605 void
1606 *metacontent;
1607
cristy3ed852e2009-09-05 21:47:34 +00001608 assert(image != (const Image *) NULL);
1609 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001610 assert(image->cache != (Cache) NULL);
1611 cache_info=(CacheInfo *) image->cache;
1612 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001613 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001614 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1615 cache_info->nexus_info[id]);
1616 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001617}
1618
1619/*
1620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621% %
1622% %
1623% %
1624+ 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 %
1625% %
1626% %
1627% %
1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629%
1630% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1631% disk pixel cache as defined by the geometry parameters. A pointer to the
1632% pixels is returned if the pixels are transferred, otherwise a NULL is
1633% returned.
1634%
1635% The format of the GetAuthenticPixelCacheNexus() method is:
1636%
cristy4c08aed2011-07-01 19:47:50 +00001637% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001638% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001639% NexusInfo *nexus_info,ExceptionInfo *exception)
1640%
1641% A description of each parameter follows:
1642%
1643% o image: the image.
1644%
1645% o x,y,columns,rows: These values define the perimeter of a region of
1646% pixels.
1647%
1648% o nexus_info: the cache nexus to return.
1649%
1650% o exception: return any errors or warnings in this structure.
1651%
1652*/
1653
cristy4c08aed2011-07-01 19:47:50 +00001654static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001655 NexusInfo *nexus_info)
1656{
cristy4c08aed2011-07-01 19:47:50 +00001657 MagickBooleanType
1658 status;
1659
cristy3ed852e2009-09-05 21:47:34 +00001660 MagickOffsetType
1661 offset;
1662
cristy73724512010-04-12 14:43:14 +00001663 if (cache_info->type == PingCache)
1664 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001665 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1666 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001667 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001668 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001669 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001670}
1671
cristya6577ff2011-09-02 19:54:26 +00001672MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001673 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001674 NexusInfo *nexus_info,ExceptionInfo *exception)
1675{
1676 CacheInfo
1677 *cache_info;
1678
cristy4c08aed2011-07-01 19:47:50 +00001679 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001680 *q;
cristy3ed852e2009-09-05 21:47:34 +00001681
1682 /*
1683 Transfer pixels from the cache.
1684 */
1685 assert(image != (Image *) NULL);
1686 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001687 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001688 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001689 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001690 cache_info=(CacheInfo *) image->cache;
1691 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001692 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001693 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001694 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001695 return((Quantum *) NULL);
1696 if (cache_info->metacontent_extent != 0)
1697 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1698 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001699 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001700}
1701
1702/*
1703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1704% %
1705% %
1706% %
1707+ 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 %
1708% %
1709% %
1710% %
1711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1712%
1713% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1714% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1715%
1716% The format of the GetAuthenticPixelsFromCache() method is:
1717%
cristy4c08aed2011-07-01 19:47:50 +00001718% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001719%
1720% A description of each parameter follows:
1721%
1722% o image: the image.
1723%
1724*/
cristy4c08aed2011-07-01 19:47:50 +00001725static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001726{
1727 CacheInfo
1728 *cache_info;
1729
cristy5c9e6f22010-09-17 17:31:01 +00001730 const int
1731 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001732
cristye7cc7cf2010-09-21 13:26:47 +00001733 assert(image != (const Image *) NULL);
1734 assert(image->signature == MagickSignature);
1735 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001736 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001737 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001738 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001739 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001740}
1741
1742/*
1743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744% %
1745% %
1746% %
1747% G e t A u t h e n t i c P i x e l Q u e u e %
1748% %
1749% %
1750% %
1751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1752%
cristy4c08aed2011-07-01 19:47:50 +00001753% GetAuthenticPixelQueue() returns the authentic pixels associated
1754% corresponding with the last call to QueueAuthenticPixels() or
1755% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001756%
1757% The format of the GetAuthenticPixelQueue() method is:
1758%
cristy4c08aed2011-07-01 19:47:50 +00001759% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001760%
1761% A description of each parameter follows:
1762%
1763% o image: the image.
1764%
1765*/
cristy4c08aed2011-07-01 19:47:50 +00001766MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001767{
1768 CacheInfo
1769 *cache_info;
1770
cristy2036f5c2010-09-19 21:18:17 +00001771 const int
1772 id = GetOpenMPThreadId();
1773
cristy3ed852e2009-09-05 21:47:34 +00001774 assert(image != (const Image *) NULL);
1775 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001776 assert(image->cache != (Cache) NULL);
1777 cache_info=(CacheInfo *) image->cache;
1778 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001779 if (cache_info->methods.get_authentic_pixels_from_handler !=
1780 (GetAuthenticPixelsFromHandler) NULL)
1781 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001782 assert(id < (int) cache_info->number_threads);
1783 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001784}
1785
1786/*
1787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1788% %
1789% %
1790% %
1791% G e t A u t h e n t i c P i x e l s %
1792% %
1793% %
cristy4c08aed2011-07-01 19:47:50 +00001794% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001795%
1796% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001797% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001798% representing the region is returned, otherwise NULL is returned.
1799%
1800% The returned pointer may point to a temporary working copy of the pixels
1801% or it may point to the original pixels in memory. Performance is maximized
1802% if the selected region is part of one row, or one or more full rows, since
1803% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001804% if the image is in memory, or in a memory-mapped file. The returned pointer
1805% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001806%
1807% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001808% Quantum. If the image has corresponding metacontent,call
1809% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1810% meta-content corresponding to the region. Once the Quantum array has
1811% been updated, the changes must be saved back to the underlying image using
1812% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001813%
1814% The format of the GetAuthenticPixels() method is:
1815%
cristy4c08aed2011-07-01 19:47:50 +00001816% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001817% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001818% ExceptionInfo *exception)
1819%
1820% A description of each parameter follows:
1821%
1822% o image: the image.
1823%
1824% o x,y,columns,rows: These values define the perimeter of a region of
1825% pixels.
1826%
1827% o exception: return any errors or warnings in this structure.
1828%
1829*/
cristy4c08aed2011-07-01 19:47:50 +00001830MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001831 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001832 ExceptionInfo *exception)
1833{
1834 CacheInfo
1835 *cache_info;
1836
cristy2036f5c2010-09-19 21:18:17 +00001837 const int
1838 id = GetOpenMPThreadId();
1839
cristy4c08aed2011-07-01 19:47:50 +00001840 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001841 *q;
cristy4c08aed2011-07-01 19:47:50 +00001842
cristy3ed852e2009-09-05 21:47:34 +00001843 assert(image != (Image *) NULL);
1844 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001845 assert(image->cache != (Cache) NULL);
1846 cache_info=(CacheInfo *) image->cache;
1847 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001848 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001849 (GetAuthenticPixelsHandler) NULL)
1850 {
cristyacd2ed22011-08-30 01:44:23 +00001851 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1852 exception);
1853 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001854 }
cristy2036f5c2010-09-19 21:18:17 +00001855 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001856 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001857 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001858 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001859}
1860
1861/*
1862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863% %
1864% %
1865% %
1866+ G e t A u t h e n t i c P i x e l s C a c h e %
1867% %
1868% %
1869% %
1870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1871%
1872% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1873% as defined by the geometry parameters. A pointer to the pixels is returned
1874% if the pixels are transferred, otherwise a NULL is returned.
1875%
1876% The format of the GetAuthenticPixelsCache() method is:
1877%
cristy4c08aed2011-07-01 19:47:50 +00001878% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001879% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001880% ExceptionInfo *exception)
1881%
1882% A description of each parameter follows:
1883%
1884% o image: the image.
1885%
1886% o x,y,columns,rows: These values define the perimeter of a region of
1887% pixels.
1888%
1889% o exception: return any errors or warnings in this structure.
1890%
1891*/
cristy4c08aed2011-07-01 19:47:50 +00001892static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001893 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001894 ExceptionInfo *exception)
1895{
1896 CacheInfo
1897 *cache_info;
1898
cristy5c9e6f22010-09-17 17:31:01 +00001899 const int
1900 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001901
cristy4c08aed2011-07-01 19:47:50 +00001902 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001903 *q;
cristy4c08aed2011-07-01 19:47:50 +00001904
cristye7cc7cf2010-09-21 13:26:47 +00001905 assert(image != (const Image *) NULL);
1906 assert(image->signature == MagickSignature);
1907 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001908 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001909 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001910 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001911 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001912 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001913 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001914 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001915 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001916}
1917
1918/*
1919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1920% %
1921% %
1922% %
1923+ G e t I m a g e E x t e n t %
1924% %
1925% %
1926% %
1927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1928%
cristy4c08aed2011-07-01 19:47:50 +00001929% GetImageExtent() returns the extent of the pixels associated corresponding
1930% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001931%
1932% The format of the GetImageExtent() method is:
1933%
1934% MagickSizeType GetImageExtent(const Image *image)
1935%
1936% A description of each parameter follows:
1937%
1938% o image: the image.
1939%
1940*/
1941MagickExport MagickSizeType GetImageExtent(const Image *image)
1942{
1943 CacheInfo
1944 *cache_info;
1945
cristy5c9e6f22010-09-17 17:31:01 +00001946 const int
1947 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001948
cristy3ed852e2009-09-05 21:47:34 +00001949 assert(image != (Image *) NULL);
1950 assert(image->signature == MagickSignature);
1951 if (image->debug != MagickFalse)
1952 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1953 assert(image->cache != (Cache) NULL);
1954 cache_info=(CacheInfo *) image->cache;
1955 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001956 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001957 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001958}
1959
1960/*
1961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1962% %
1963% %
1964% %
1965+ G e t I m a g e P i x e l C a c h e %
1966% %
1967% %
1968% %
1969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970%
1971% GetImagePixelCache() ensures that there is only a single reference to the
1972% pixel cache to be modified, updating the provided cache pointer to point to
1973% a clone of the original pixel cache if necessary.
1974%
1975% The format of the GetImagePixelCache method is:
1976%
1977% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1978% ExceptionInfo *exception)
1979%
1980% A description of each parameter follows:
1981%
1982% o image: the image.
1983%
1984% o clone: any value other than MagickFalse clones the cache pixels.
1985%
1986% o exception: return any errors or warnings in this structure.
1987%
1988*/
cristyaf894d72011-08-06 23:03:10 +00001989
cristy3ed852e2009-09-05 21:47:34 +00001990static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1991{
1992 CacheInfo
1993 *cache_info;
1994
cristy9e0719b2011-12-29 03:45:45 +00001995 PixelChannelMap
1996 *p,
1997 *q;
1998
cristy3ed852e2009-09-05 21:47:34 +00001999 /*
2000 Does the image match the pixel cache morphology?
2001 */
2002 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00002003 p=image->channel_map;
2004 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00002005 if ((image->storage_class != cache_info->storage_class) ||
2006 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002007 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002008 (image->columns != cache_info->columns) ||
2009 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002010 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002011 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002012 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002013 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2014 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2015 return(MagickFalse);
2016 return(MagickTrue);
2017}
2018
cristycd01fae2011-08-06 23:52:42 +00002019static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2020 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002021{
2022 CacheInfo
2023 *cache_info;
2024
cristy3ed852e2009-09-05 21:47:34 +00002025 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002026 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002027 status;
2028
cristy50a10922010-02-15 18:35:25 +00002029 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002030 cpu_throttle = 0,
2031 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002032 time_limit = 0;
2033
cristy1ea34962010-07-01 19:49:21 +00002034 static time_t
cristy208b1002011-08-07 18:51:50 +00002035 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002036
cristyc4f9f132010-03-04 18:50:01 +00002037 status=MagickTrue;
2038 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002039 if (cpu_throttle == 0)
2040 {
2041 char
2042 *limit;
2043
2044 /*
2045 Set CPU throttle in milleseconds.
2046 */
2047 cpu_throttle=MagickResourceInfinity;
2048 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2049 if (limit == (char *) NULL)
2050 limit=GetPolicyValue("throttle");
2051 if (limit != (char *) NULL)
2052 {
2053 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2054 limit=DestroyString(limit);
2055 }
2056 }
2057 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2058 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002059 if (time_limit == 0)
2060 {
cristy6ebe97c2010-07-03 01:17:28 +00002061 /*
2062 Set the exire time in seconds.
2063 */
cristy1ea34962010-07-01 19:49:21 +00002064 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002065 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002066 }
2067 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002068 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002069 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002070 assert(image->cache != (Cache) NULL);
2071 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002072 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002073 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002074 {
cristyceb55ee2010-11-06 16:05:49 +00002075 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002076 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002077 {
cristyceb55ee2010-11-06 16:05:49 +00002078 Image
2079 clone_image;
2080
2081 CacheInfo
2082 *clone_info;
2083
2084 /*
2085 Clone pixel cache.
2086 */
2087 clone_image=(*image);
2088 clone_image.semaphore=AllocateSemaphoreInfo();
2089 clone_image.reference_count=1;
2090 clone_image.cache=ClonePixelCache(cache_info);
2091 clone_info=(CacheInfo *) clone_image.cache;
2092 status=OpenPixelCache(&clone_image,IOMode,exception);
2093 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002094 {
cristy5a7fbfb2010-11-06 16:10:59 +00002095 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002096 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002097 if (status != MagickFalse)
2098 {
cristy979bf772011-08-08 00:04:15 +00002099 if (cache_info->mode == ReadMode)
2100 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002101 destroy=MagickTrue;
2102 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002103 }
2104 }
cristyceb55ee2010-11-06 16:05:49 +00002105 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002106 }
cristyceb55ee2010-11-06 16:05:49 +00002107 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002108 }
cristy4320e0e2009-09-10 15:00:08 +00002109 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002110 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002111 if (status != MagickFalse)
2112 {
2113 /*
2114 Ensure the image matches the pixel cache morphology.
2115 */
2116 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002117 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002118 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2119 status=OpenPixelCache(image,IOMode,exception);
2120 }
cristyf84a1932010-01-03 18:00:18 +00002121 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002122 if (status == MagickFalse)
2123 return((Cache) NULL);
2124 return(image->cache);
2125}
2126
2127/*
2128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2129% %
2130% %
2131% %
2132% G e t O n e A u t h e n t i c P i x e l %
2133% %
2134% %
2135% %
2136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2137%
2138% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2139% location. The image background color is returned if an error occurs.
2140%
2141% The format of the GetOneAuthenticPixel() method is:
2142%
cristybb503372010-05-27 20:51:26 +00002143% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002144% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002145%
2146% A description of each parameter follows:
2147%
2148% o image: the image.
2149%
2150% o x,y: These values define the location of the pixel to return.
2151%
2152% o pixel: return a pixel at the specified (x,y) location.
2153%
2154% o exception: return any errors or warnings in this structure.
2155%
2156*/
cristyacbbb7c2010-06-30 18:56:48 +00002157MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002158 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002159{
2160 CacheInfo
2161 *cache_info;
2162
cristy4c08aed2011-07-01 19:47:50 +00002163 register Quantum
2164 *q;
cristy2036f5c2010-09-19 21:18:17 +00002165
cristy2ed42f62011-10-02 19:49:57 +00002166 register ssize_t
2167 i;
2168
cristy3ed852e2009-09-05 21:47:34 +00002169 assert(image != (Image *) NULL);
2170 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002171 assert(image->cache != (Cache) NULL);
2172 cache_info=(CacheInfo *) image->cache;
2173 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002174 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002175 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2176 (GetOneAuthenticPixelFromHandler) NULL)
2177 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2178 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002179 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2180 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002181 {
cristy9e0719b2011-12-29 03:45:45 +00002182 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2183 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2184 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2185 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2186 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002187 return(MagickFalse);
2188 }
2189 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2190 {
2191 PixelChannel
2192 channel;
2193
cristye2a912b2011-12-05 20:02:07 +00002194 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002195 pixel[channel]=q[i];
2196 }
cristy2036f5c2010-09-19 21:18:17 +00002197 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002198}
2199
2200/*
2201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2202% %
2203% %
2204% %
2205+ 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 %
2206% %
2207% %
2208% %
2209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2210%
2211% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2212% location. The image background color is returned if an error occurs.
2213%
2214% The format of the GetOneAuthenticPixelFromCache() method is:
2215%
2216% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002217% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002218% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002219%
2220% A description of each parameter follows:
2221%
2222% o image: the image.
2223%
2224% o x,y: These values define the location of the pixel to return.
2225%
2226% o pixel: return a pixel at the specified (x,y) location.
2227%
2228% o exception: return any errors or warnings in this structure.
2229%
2230*/
2231static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002232 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002233{
cristy098f78c2010-09-23 17:28:44 +00002234 CacheInfo
2235 *cache_info;
2236
2237 const int
2238 id = GetOpenMPThreadId();
2239
cristy4c08aed2011-07-01 19:47:50 +00002240 register Quantum
2241 *q;
cristy3ed852e2009-09-05 21:47:34 +00002242
cristy2ed42f62011-10-02 19:49:57 +00002243 register ssize_t
2244 i;
2245
cristy0158a4b2010-09-20 13:59:45 +00002246 assert(image != (const Image *) NULL);
2247 assert(image->signature == MagickSignature);
2248 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002249 cache_info=(CacheInfo *) image->cache;
2250 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002251 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002252 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002253 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2254 exception);
2255 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002256 {
cristy9e0719b2011-12-29 03:45:45 +00002257 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2258 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2259 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2260 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2261 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002262 return(MagickFalse);
2263 }
2264 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2265 {
2266 PixelChannel
2267 channel;
2268
cristye2a912b2011-12-05 20:02:07 +00002269 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002270 pixel[channel]=q[i];
2271 }
cristy3ed852e2009-09-05 21:47:34 +00002272 return(MagickTrue);
2273}
2274
2275/*
2276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277% %
2278% %
2279% %
cristy3ed852e2009-09-05 21:47:34 +00002280% G e t O n e V i r t u a l P i x e l %
2281% %
2282% %
2283% %
2284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285%
2286% GetOneVirtualPixel() returns a single virtual pixel at the specified
2287% (x,y) location. The image background color is returned if an error occurs.
2288% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2289%
2290% The format of the GetOneVirtualPixel() method is:
2291%
cristybb503372010-05-27 20:51:26 +00002292% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002293% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002294%
2295% A description of each parameter follows:
2296%
2297% o image: the image.
2298%
2299% o x,y: These values define the location of the pixel to return.
2300%
2301% o pixel: return a pixel at the specified (x,y) location.
2302%
2303% o exception: return any errors or warnings in this structure.
2304%
2305*/
2306MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002307 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002308{
cristy3ed852e2009-09-05 21:47:34 +00002309 CacheInfo
2310 *cache_info;
2311
cristy0158a4b2010-09-20 13:59:45 +00002312 const int
2313 id = GetOpenMPThreadId();
2314
cristy4c08aed2011-07-01 19:47:50 +00002315 const Quantum
2316 *p;
cristy2036f5c2010-09-19 21:18:17 +00002317
cristy2ed42f62011-10-02 19:49:57 +00002318 register ssize_t
2319 i;
2320
cristy3ed852e2009-09-05 21:47:34 +00002321 assert(image != (const Image *) NULL);
2322 assert(image->signature == MagickSignature);
2323 assert(image->cache != (Cache) NULL);
2324 cache_info=(CacheInfo *) image->cache;
2325 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002326 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002327 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2328 (GetOneVirtualPixelFromHandler) NULL)
2329 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2330 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002331 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002332 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002333 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002334 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002335 {
cristy9e0719b2011-12-29 03:45:45 +00002336 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2337 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2338 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2339 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2340 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002341 return(MagickFalse);
2342 }
2343 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2344 {
2345 PixelChannel
2346 channel;
2347
cristye2a912b2011-12-05 20:02:07 +00002348 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002349 pixel[channel]=p[i];
2350 }
cristy2036f5c2010-09-19 21:18:17 +00002351 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002352}
2353
2354/*
2355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2356% %
2357% %
2358% %
2359+ 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 %
2360% %
2361% %
2362% %
2363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2364%
2365% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2366% specified (x,y) location. The image background color is returned if an
2367% error occurs.
2368%
2369% The format of the GetOneVirtualPixelFromCache() method is:
2370%
2371% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002372% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002373% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002374%
2375% A description of each parameter follows:
2376%
2377% o image: the image.
2378%
2379% o virtual_pixel_method: the virtual pixel method.
2380%
2381% o x,y: These values define the location of the pixel to return.
2382%
2383% o pixel: return a pixel at the specified (x,y) location.
2384%
2385% o exception: return any errors or warnings in this structure.
2386%
2387*/
2388static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002389 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002390 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002391{
cristy0158a4b2010-09-20 13:59:45 +00002392 CacheInfo
2393 *cache_info;
2394
2395 const int
2396 id = GetOpenMPThreadId();
2397
cristy4c08aed2011-07-01 19:47:50 +00002398 const Quantum
2399 *p;
cristy3ed852e2009-09-05 21:47:34 +00002400
cristy2ed42f62011-10-02 19:49:57 +00002401 register ssize_t
2402 i;
2403
cristye7cc7cf2010-09-21 13:26:47 +00002404 assert(image != (const Image *) NULL);
2405 assert(image->signature == MagickSignature);
2406 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002407 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002408 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002409 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002410 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002411 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002412 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002413 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002414 {
cristy9e0719b2011-12-29 03:45:45 +00002415 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2416 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2417 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2418 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2419 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002420 return(MagickFalse);
2421 }
2422 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2423 {
2424 PixelChannel
2425 channel;
2426
cristye2a912b2011-12-05 20:02:07 +00002427 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002428 pixel[channel]=p[i];
2429 }
cristy3ed852e2009-09-05 21:47:34 +00002430 return(MagickTrue);
2431}
2432
2433/*
2434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2435% %
2436% %
2437% %
cristy3aa93752011-12-18 15:54:24 +00002438% G e t O n e V i r t u a l P i x e l I n f o %
2439% %
2440% %
2441% %
2442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2443%
2444% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2445% location. The image background color is returned if an error occurs. If
2446% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2447%
2448% The format of the GetOneVirtualPixelInfo() method is:
2449%
2450% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2451% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2452% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2453%
2454% A description of each parameter follows:
2455%
2456% o image: the image.
2457%
2458% o virtual_pixel_method: the virtual pixel method.
2459%
2460% o x,y: these values define the location of the pixel to return.
2461%
2462% o pixel: return a pixel at the specified (x,y) location.
2463%
2464% o exception: return any errors or warnings in this structure.
2465%
2466*/
2467MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2468 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2469 PixelInfo *pixel,ExceptionInfo *exception)
2470{
2471 CacheInfo
2472 *cache_info;
2473
2474 const int
2475 id = GetOpenMPThreadId();
2476
2477 register const Quantum
2478 *p;
2479
2480 assert(image != (const Image *) NULL);
2481 assert(image->signature == MagickSignature);
2482 assert(image->cache != (Cache) NULL);
2483 cache_info=(CacheInfo *) image->cache;
2484 assert(cache_info->signature == MagickSignature);
2485 assert(id < (int) cache_info->number_threads);
2486 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2487 cache_info->nexus_info[id],exception);
2488 GetPixelInfo(image,pixel);
2489 if (p == (const Quantum *) NULL)
2490 return(MagickFalse);
2491 GetPixelInfoPixel(image,p,pixel);
2492 return(MagickTrue);
2493}
2494
2495/*
2496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2497% %
2498% %
2499% %
cristy3ed852e2009-09-05 21:47:34 +00002500+ G e t P i x e l C a c h e C o l o r s p a c e %
2501% %
2502% %
2503% %
2504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2505%
2506% GetPixelCacheColorspace() returns the class type of the pixel cache.
2507%
2508% The format of the GetPixelCacheColorspace() method is:
2509%
2510% Colorspace GetPixelCacheColorspace(Cache cache)
2511%
2512% A description of each parameter follows:
2513%
2514% o cache: the pixel cache.
2515%
2516*/
cristya6577ff2011-09-02 19:54:26 +00002517MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002518{
2519 CacheInfo
2520 *cache_info;
2521
2522 assert(cache != (Cache) NULL);
2523 cache_info=(CacheInfo *) cache;
2524 assert(cache_info->signature == MagickSignature);
2525 if (cache_info->debug != MagickFalse)
2526 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2527 cache_info->filename);
2528 return(cache_info->colorspace);
2529}
2530
2531/*
2532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2533% %
2534% %
2535% %
2536+ G e t P i x e l C a c h e M e t h o d s %
2537% %
2538% %
2539% %
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541%
2542% GetPixelCacheMethods() initializes the CacheMethods structure.
2543%
2544% The format of the GetPixelCacheMethods() method is:
2545%
2546% void GetPixelCacheMethods(CacheMethods *cache_methods)
2547%
2548% A description of each parameter follows:
2549%
2550% o cache_methods: Specifies a pointer to a CacheMethods structure.
2551%
2552*/
cristya6577ff2011-09-02 19:54:26 +00002553MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002554{
2555 assert(cache_methods != (CacheMethods *) NULL);
2556 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2557 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2558 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002559 cache_methods->get_virtual_metacontent_from_handler=
2560 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002561 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2562 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002563 cache_methods->get_authentic_metacontent_from_handler=
2564 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002565 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2566 cache_methods->get_one_authentic_pixel_from_handler=
2567 GetOneAuthenticPixelFromCache;
2568 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2569 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2570 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2571}
2572
2573/*
2574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2575% %
2576% %
2577% %
2578+ G e t P i x e l C a c h e N e x u s E x t e n t %
2579% %
2580% %
2581% %
2582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583%
cristy4c08aed2011-07-01 19:47:50 +00002584% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2585% corresponding with the last call to SetPixelCacheNexusPixels() or
2586% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002587%
2588% The format of the GetPixelCacheNexusExtent() method is:
2589%
2590% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2591% NexusInfo *nexus_info)
2592%
2593% A description of each parameter follows:
2594%
2595% o nexus_info: the nexus info.
2596%
2597*/
cristya6577ff2011-09-02 19:54:26 +00002598MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002599 NexusInfo *nexus_info)
2600{
2601 CacheInfo
2602 *cache_info;
2603
2604 MagickSizeType
2605 extent;
2606
cristy9f027d12011-09-21 01:17:17 +00002607 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002608 cache_info=(CacheInfo *) cache;
2609 assert(cache_info->signature == MagickSignature);
2610 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2611 if (extent == 0)
2612 return((MagickSizeType) cache_info->columns*cache_info->rows);
2613 return(extent);
2614}
2615
2616/*
2617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2618% %
2619% %
2620% %
cristy4c08aed2011-07-01 19:47:50 +00002621+ 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 +00002622% %
2623% %
2624% %
2625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2626%
cristy4c08aed2011-07-01 19:47:50 +00002627% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2628% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002629%
cristy4c08aed2011-07-01 19:47:50 +00002630% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002631%
cristy4c08aed2011-07-01 19:47:50 +00002632% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002633% NexusInfo *nexus_info)
2634%
2635% A description of each parameter follows:
2636%
2637% o cache: the pixel cache.
2638%
cristy4c08aed2011-07-01 19:47:50 +00002639% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002640%
2641*/
cristya6577ff2011-09-02 19:54:26 +00002642MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002643 NexusInfo *nexus_info)
2644{
2645 CacheInfo
2646 *cache_info;
2647
cristy9f027d12011-09-21 01:17:17 +00002648 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002649 cache_info=(CacheInfo *) cache;
2650 assert(cache_info->signature == MagickSignature);
2651 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002652 return((void *) NULL);
2653 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002654}
2655
2656/*
2657%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2658% %
2659% %
2660% %
2661+ G e t P i x e l C a c h e N e x u s P i x e l s %
2662% %
2663% %
2664% %
2665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2666%
2667% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2668% cache nexus.
2669%
2670% The format of the GetPixelCacheNexusPixels() method is:
2671%
cristy4c08aed2011-07-01 19:47:50 +00002672% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002673% NexusInfo *nexus_info)
2674%
2675% A description of each parameter follows:
2676%
2677% o cache: the pixel cache.
2678%
2679% o nexus_info: the cache nexus to return the pixels.
2680%
2681*/
cristya6577ff2011-09-02 19:54:26 +00002682MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002683 NexusInfo *nexus_info)
2684{
2685 CacheInfo
2686 *cache_info;
2687
cristy9f027d12011-09-21 01:17:17 +00002688 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002689 cache_info=(CacheInfo *) cache;
2690 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002691 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002692 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002693 return(nexus_info->pixels);
2694}
2695
2696/*
2697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2698% %
2699% %
2700% %
cristy056ba772010-01-02 23:33:54 +00002701+ G e t P i x e l C a c h e P i x e l s %
2702% %
2703% %
2704% %
2705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2706%
2707% GetPixelCachePixels() returns the pixels associated with the specified image.
2708%
2709% The format of the GetPixelCachePixels() method is:
2710%
cristyf84a1932010-01-03 18:00:18 +00002711% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2712% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002713%
2714% A description of each parameter follows:
2715%
2716% o image: the image.
2717%
2718% o length: the pixel cache length.
2719%
cristyf84a1932010-01-03 18:00:18 +00002720% o exception: return any errors or warnings in this structure.
2721%
cristy056ba772010-01-02 23:33:54 +00002722*/
cristyd1dd6e42011-09-04 01:46:08 +00002723MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002724 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002725{
2726 CacheInfo
2727 *cache_info;
2728
2729 assert(image != (const Image *) NULL);
2730 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002731 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002732 assert(length != (MagickSizeType *) NULL);
2733 assert(exception != (ExceptionInfo *) NULL);
2734 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002735 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002736 assert(cache_info->signature == MagickSignature);
2737 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002738 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002739 return((void *) NULL);
2740 *length=cache_info->length;
2741 return((void *) cache_info->pixels);
2742}
2743
2744/*
2745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2746% %
2747% %
2748% %
cristyb32b90a2009-09-07 21:45:48 +00002749+ 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 +00002750% %
2751% %
2752% %
2753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2754%
2755% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2756%
2757% The format of the GetPixelCacheStorageClass() method is:
2758%
2759% ClassType GetPixelCacheStorageClass(Cache cache)
2760%
2761% A description of each parameter follows:
2762%
2763% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2764%
2765% o cache: the pixel cache.
2766%
2767*/
cristya6577ff2011-09-02 19:54:26 +00002768MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002769{
2770 CacheInfo
2771 *cache_info;
2772
2773 assert(cache != (Cache) NULL);
2774 cache_info=(CacheInfo *) cache;
2775 assert(cache_info->signature == MagickSignature);
2776 if (cache_info->debug != MagickFalse)
2777 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2778 cache_info->filename);
2779 return(cache_info->storage_class);
2780}
2781
2782/*
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784% %
2785% %
2786% %
cristyb32b90a2009-09-07 21:45:48 +00002787+ G e t P i x e l C a c h e T i l e S i z e %
2788% %
2789% %
2790% %
2791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2792%
2793% GetPixelCacheTileSize() returns the pixel cache tile size.
2794%
2795% The format of the GetPixelCacheTileSize() method is:
2796%
cristybb503372010-05-27 20:51:26 +00002797% void GetPixelCacheTileSize(const Image *image,size_t *width,
2798% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002799%
2800% A description of each parameter follows:
2801%
2802% o image: the image.
2803%
2804% o width: the optimize cache tile width in pixels.
2805%
2806% o height: the optimize cache tile height in pixels.
2807%
2808*/
cristya6577ff2011-09-02 19:54:26 +00002809MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002810 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002811{
cristy4c08aed2011-07-01 19:47:50 +00002812 CacheInfo
2813 *cache_info;
2814
cristyb32b90a2009-09-07 21:45:48 +00002815 assert(image != (Image *) NULL);
2816 assert(image->signature == MagickSignature);
2817 if (image->debug != MagickFalse)
2818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002819 cache_info=(CacheInfo *) image->cache;
2820 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002821 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002822 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002823 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002824 *height=(*width);
2825}
2826
2827/*
2828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829% %
2830% %
2831% %
2832+ G e t P i x e l C a c h e T y p e %
2833% %
2834% %
2835% %
2836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837%
2838% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2839%
2840% The format of the GetPixelCacheType() method is:
2841%
2842% CacheType GetPixelCacheType(const Image *image)
2843%
2844% A description of each parameter follows:
2845%
2846% o image: the image.
2847%
2848*/
cristya6577ff2011-09-02 19:54:26 +00002849MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002850{
2851 CacheInfo
2852 *cache_info;
2853
2854 assert(image != (Image *) NULL);
2855 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002856 assert(image->cache != (Cache) NULL);
2857 cache_info=(CacheInfo *) image->cache;
2858 assert(cache_info->signature == MagickSignature);
2859 return(cache_info->type);
2860}
2861
2862/*
2863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2864% %
2865% %
2866% %
cristy3ed852e2009-09-05 21:47:34 +00002867+ 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 %
2868% %
2869% %
2870% %
2871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2872%
2873% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2874% pixel cache. A virtual pixel is any pixel access that is outside the
2875% boundaries of the image cache.
2876%
2877% The format of the GetPixelCacheVirtualMethod() method is:
2878%
2879% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2880%
2881% A description of each parameter follows:
2882%
2883% o image: the image.
2884%
2885*/
cristyd1dd6e42011-09-04 01:46:08 +00002886MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002887{
2888 CacheInfo
2889 *cache_info;
2890
2891 assert(image != (Image *) NULL);
2892 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002893 assert(image->cache != (Cache) NULL);
2894 cache_info=(CacheInfo *) image->cache;
2895 assert(cache_info->signature == MagickSignature);
2896 return(cache_info->virtual_pixel_method);
2897}
2898
2899/*
2900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2901% %
2902% %
2903% %
cristy4c08aed2011-07-01 19:47:50 +00002904+ 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 +00002905% %
2906% %
2907% %
2908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2909%
cristy4c08aed2011-07-01 19:47:50 +00002910% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2911% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002912%
cristy4c08aed2011-07-01 19:47:50 +00002913% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002914%
cristy4c08aed2011-07-01 19:47:50 +00002915% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002916%
2917% A description of each parameter follows:
2918%
2919% o image: the image.
2920%
2921*/
cristy4c08aed2011-07-01 19:47:50 +00002922static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002923{
2924 CacheInfo
2925 *cache_info;
2926
cristy5c9e6f22010-09-17 17:31:01 +00002927 const int
2928 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002929
cristy4c08aed2011-07-01 19:47:50 +00002930 const void
2931 *metacontent;
2932
cristye7cc7cf2010-09-21 13:26:47 +00002933 assert(image != (const Image *) NULL);
2934 assert(image->signature == MagickSignature);
2935 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002936 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002937 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002938 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002939 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2940 cache_info->nexus_info[id]);
2941 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002942}
2943
2944/*
2945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2946% %
2947% %
2948% %
cristy4c08aed2011-07-01 19:47:50 +00002949+ 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 +00002950% %
2951% %
2952% %
2953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2954%
cristy4c08aed2011-07-01 19:47:50 +00002955% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2956% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002957%
cristy4c08aed2011-07-01 19:47:50 +00002958% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002959%
cristy4c08aed2011-07-01 19:47:50 +00002960% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002961% NexusInfo *nexus_info)
2962%
2963% A description of each parameter follows:
2964%
2965% o cache: the pixel cache.
2966%
cristy4c08aed2011-07-01 19:47:50 +00002967% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002968%
2969*/
cristya6577ff2011-09-02 19:54:26 +00002970MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002971 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002972{
2973 CacheInfo
2974 *cache_info;
2975
cristye7cc7cf2010-09-21 13:26:47 +00002976 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002977 cache_info=(CacheInfo *) cache;
2978 assert(cache_info->signature == MagickSignature);
2979 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002980 return((void *) NULL);
2981 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002982}
2983
2984/*
2985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2986% %
2987% %
2988% %
cristy4c08aed2011-07-01 19:47:50 +00002989% 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 +00002990% %
2991% %
2992% %
2993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2994%
cristy4c08aed2011-07-01 19:47:50 +00002995% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2996% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2997% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002998%
cristy4c08aed2011-07-01 19:47:50 +00002999% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003000%
cristy4c08aed2011-07-01 19:47:50 +00003001% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003002%
3003% A description of each parameter follows:
3004%
3005% o image: the image.
3006%
3007*/
cristy4c08aed2011-07-01 19:47:50 +00003008MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003009{
3010 CacheInfo
3011 *cache_info;
3012
cristy2036f5c2010-09-19 21:18:17 +00003013 const int
3014 id = GetOpenMPThreadId();
3015
cristy4c08aed2011-07-01 19:47:50 +00003016 const void
3017 *metacontent;
3018
cristy3ed852e2009-09-05 21:47:34 +00003019 assert(image != (const Image *) NULL);
3020 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003021 assert(image->cache != (Cache) NULL);
3022 cache_info=(CacheInfo *) image->cache;
3023 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003024 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3025 (GetVirtualMetacontentFromHandler) NULL)
3026 {
3027 metacontent=cache_info->methods.
3028 get_virtual_metacontent_from_handler(image);
3029 return(metacontent);
3030 }
cristy2036f5c2010-09-19 21:18:17 +00003031 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003032 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3033 cache_info->nexus_info[id]);
3034 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003035}
3036
3037/*
3038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3039% %
3040% %
3041% %
3042+ 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 %
3043% %
3044% %
3045% %
3046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3047%
3048% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3049% pixel cache as defined by the geometry parameters. A pointer to the pixels
3050% is returned if the pixels are transferred, otherwise a NULL is returned.
3051%
3052% The format of the GetVirtualPixelsFromNexus() method is:
3053%
cristy4c08aed2011-07-01 19:47:50 +00003054% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003055% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003056% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3057% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003058%
3059% A description of each parameter follows:
3060%
3061% o image: the image.
3062%
3063% o virtual_pixel_method: the virtual pixel method.
3064%
3065% o x,y,columns,rows: These values define the perimeter of a region of
3066% pixels.
3067%
3068% o nexus_info: the cache nexus to acquire.
3069%
3070% o exception: return any errors or warnings in this structure.
3071%
3072*/
3073
cristybb503372010-05-27 20:51:26 +00003074static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003075 DitherMatrix[64] =
3076 {
3077 0, 48, 12, 60, 3, 51, 15, 63,
3078 32, 16, 44, 28, 35, 19, 47, 31,
3079 8, 56, 4, 52, 11, 59, 7, 55,
3080 40, 24, 36, 20, 43, 27, 39, 23,
3081 2, 50, 14, 62, 1, 49, 13, 61,
3082 34, 18, 46, 30, 33, 17, 45, 29,
3083 10, 58, 6, 54, 9, 57, 5, 53,
3084 42, 26, 38, 22, 41, 25, 37, 21
3085 };
3086
cristybb503372010-05-27 20:51:26 +00003087static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003088{
cristybb503372010-05-27 20:51:26 +00003089 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003090 index;
3091
3092 index=x+DitherMatrix[x & 0x07]-32L;
3093 if (index < 0L)
3094 return(0L);
cristybb503372010-05-27 20:51:26 +00003095 if (index >= (ssize_t) columns)
3096 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003097 return(index);
3098}
3099
cristybb503372010-05-27 20:51:26 +00003100static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003101{
cristybb503372010-05-27 20:51:26 +00003102 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003103 index;
3104
3105 index=y+DitherMatrix[y & 0x07]-32L;
3106 if (index < 0L)
3107 return(0L);
cristybb503372010-05-27 20:51:26 +00003108 if (index >= (ssize_t) rows)
3109 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003110 return(index);
3111}
3112
cristybb503372010-05-27 20:51:26 +00003113static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003114{
3115 if (x < 0L)
3116 return(0L);
cristybb503372010-05-27 20:51:26 +00003117 if (x >= (ssize_t) columns)
3118 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003119 return(x);
3120}
3121
cristybb503372010-05-27 20:51:26 +00003122static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003123{
3124 if (y < 0L)
3125 return(0L);
cristybb503372010-05-27 20:51:26 +00003126 if (y >= (ssize_t) rows)
3127 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003128 return(y);
3129}
3130
cristybb503372010-05-27 20:51:26 +00003131static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003132{
cristybb503372010-05-27 20:51:26 +00003133 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003134}
3135
cristybb503372010-05-27 20:51:26 +00003136static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003137{
cristybb503372010-05-27 20:51:26 +00003138 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003139}
3140
cristybb503372010-05-27 20:51:26 +00003141static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3142 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003143{
3144 MagickModulo
3145 modulo;
3146
cristy6162bb42011-07-18 11:34:09 +00003147 /*
3148 Compute the remainder of dividing offset by extent. It returns not only
3149 the quotient (tile the offset falls in) but also the positive remainer
3150 within that tile such that 0 <= remainder < extent. This method is
3151 essentially a ldiv() using a floored modulo division rather than the
3152 normal default truncated modulo division.
3153 */
cristybb503372010-05-27 20:51:26 +00003154 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003155 if (offset < 0L)
3156 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003157 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003158 return(modulo);
3159}
3160
cristya6577ff2011-09-02 19:54:26 +00003161MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003162 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3163 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003164 ExceptionInfo *exception)
3165{
3166 CacheInfo
3167 *cache_info;
3168
3169 MagickOffsetType
3170 offset;
3171
3172 MagickSizeType
3173 length,
3174 number_pixels;
3175
3176 NexusInfo
3177 **virtual_nexus;
3178
cristy4c08aed2011-07-01 19:47:50 +00003179 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003180 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003181 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003182
3183 RectangleInfo
3184 region;
3185
cristy4c08aed2011-07-01 19:47:50 +00003186 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003187 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003188
cristy4c08aed2011-07-01 19:47:50 +00003189 register const void
3190 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003191
cristy4c08aed2011-07-01 19:47:50 +00003192 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003193 *restrict q;
3194
cristybb503372010-05-27 20:51:26 +00003195 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003196 i,
3197 u;
cristy3ed852e2009-09-05 21:47:34 +00003198
cristy4c08aed2011-07-01 19:47:50 +00003199 register unsigned char
3200 *restrict s;
3201
cristy105ba3c2011-07-18 02:28:38 +00003202 ssize_t
3203 v;
3204
cristy4c08aed2011-07-01 19:47:50 +00003205 void
cristy105ba3c2011-07-18 02:28:38 +00003206 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003207
cristy3ed852e2009-09-05 21:47:34 +00003208 /*
3209 Acquire pixels.
3210 */
cristye7cc7cf2010-09-21 13:26:47 +00003211 assert(image != (const Image *) NULL);
3212 assert(image->signature == MagickSignature);
3213 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003214 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003215 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003216 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003217 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003218 region.x=x;
3219 region.y=y;
3220 region.width=columns;
3221 region.height=rows;
3222 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003223 if (pixels == (Quantum *) NULL)
3224 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003225 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003226 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3227 nexus_info->region.x;
3228 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3229 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003230 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3231 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003232 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3233 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003234 {
3235 MagickBooleanType
3236 status;
3237
3238 /*
3239 Pixel request is inside cache extents.
3240 */
cristy4c08aed2011-07-01 19:47:50 +00003241 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003242 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003243 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3244 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003245 return((const Quantum *) NULL);
3246 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003247 {
cristy4c08aed2011-07-01 19:47:50 +00003248 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003249 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003250 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003251 }
cristyacd2ed22011-08-30 01:44:23 +00003252 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003253 }
3254 /*
3255 Pixel request is outside cache extents.
3256 */
cristy4c08aed2011-07-01 19:47:50 +00003257 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003258 virtual_nexus=AcquirePixelCacheNexus(1);
3259 if (virtual_nexus == (NexusInfo **) NULL)
3260 {
cristy4c08aed2011-07-01 19:47:50 +00003261 if (virtual_nexus != (NexusInfo **) NULL)
3262 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003263 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3264 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003265 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003266 }
cristy105ba3c2011-07-18 02:28:38 +00003267 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3268 sizeof(*virtual_pixel));
3269 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003270 switch (virtual_pixel_method)
3271 {
cristy4c08aed2011-07-01 19:47:50 +00003272 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003273 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003274 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003275 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003276 case MaskVirtualPixelMethod:
3277 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003278 case EdgeVirtualPixelMethod:
3279 case CheckerTileVirtualPixelMethod:
3280 case HorizontalTileVirtualPixelMethod:
3281 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003282 {
cristy4c08aed2011-07-01 19:47:50 +00003283 if (cache_info->metacontent_extent != 0)
3284 {
cristy6162bb42011-07-18 11:34:09 +00003285 /*
3286 Acquire a metacontent buffer.
3287 */
cristya64b85d2011-09-14 01:02:31 +00003288 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003289 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003290 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003291 {
cristy4c08aed2011-07-01 19:47:50 +00003292 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3293 (void) ThrowMagickException(exception,GetMagickModule(),
3294 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3295 return((const Quantum *) NULL);
3296 }
cristy105ba3c2011-07-18 02:28:38 +00003297 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003298 cache_info->metacontent_extent);
3299 }
3300 switch (virtual_pixel_method)
3301 {
3302 case BlackVirtualPixelMethod:
3303 {
cristy30301712011-07-18 15:06:51 +00003304 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3305 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003306 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3307 break;
3308 }
3309 case GrayVirtualPixelMethod:
3310 {
cristy30301712011-07-18 15:06:51 +00003311 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003312 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3313 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003314 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3315 break;
3316 }
3317 case TransparentVirtualPixelMethod:
3318 {
cristy30301712011-07-18 15:06:51 +00003319 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3320 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003321 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3322 break;
3323 }
3324 case MaskVirtualPixelMethod:
3325 case WhiteVirtualPixelMethod:
3326 {
cristy30301712011-07-18 15:06:51 +00003327 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3328 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003329 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3330 break;
3331 }
3332 default:
3333 {
cristy9e0719b2011-12-29 03:45:45 +00003334 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3335 virtual_pixel);
3336 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3337 virtual_pixel);
3338 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3339 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003340 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003341 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3342 virtual_pixel);
3343 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3344 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003345 break;
3346 }
3347 }
cristy3ed852e2009-09-05 21:47:34 +00003348 break;
3349 }
3350 default:
cristy3ed852e2009-09-05 21:47:34 +00003351 break;
cristy3ed852e2009-09-05 21:47:34 +00003352 }
cristybb503372010-05-27 20:51:26 +00003353 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003354 {
cristybb503372010-05-27 20:51:26 +00003355 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003356 {
3357 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003358 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003359 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3360 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003361 {
3362 MagickModulo
3363 x_modulo,
3364 y_modulo;
3365
3366 /*
3367 Transfer a single pixel.
3368 */
3369 length=(MagickSizeType) 1;
3370 switch (virtual_pixel_method)
3371 {
cristy3ed852e2009-09-05 21:47:34 +00003372 default:
3373 {
3374 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003375 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003376 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003377 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003378 break;
3379 }
3380 case RandomVirtualPixelMethod:
3381 {
3382 if (cache_info->random_info == (RandomInfo *) NULL)
3383 cache_info->random_info=AcquireRandomInfo();
3384 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003385 RandomX(cache_info->random_info,cache_info->columns),
3386 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003387 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003388 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003389 break;
3390 }
3391 case DitherVirtualPixelMethod:
3392 {
3393 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003394 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003395 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003396 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003397 break;
3398 }
3399 case TileVirtualPixelMethod:
3400 {
3401 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3402 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3403 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003404 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003405 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 MirrorVirtualPixelMethod:
3410 {
3411 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3412 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003413 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003414 x_modulo.remainder-1L;
3415 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3416 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003417 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003418 y_modulo.remainder-1L;
3419 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003420 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003421 exception);
cristy4c08aed2011-07-01 19:47:50 +00003422 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003423 break;
3424 }
3425 case HorizontalTileEdgeVirtualPixelMethod:
3426 {
3427 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003429 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003430 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003431 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003432 break;
3433 }
3434 case VerticalTileEdgeVirtualPixelMethod:
3435 {
3436 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3437 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003438 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003439 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003440 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3441 break;
3442 }
3443 case BackgroundVirtualPixelMethod:
3444 case BlackVirtualPixelMethod:
3445 case GrayVirtualPixelMethod:
3446 case TransparentVirtualPixelMethod:
3447 case MaskVirtualPixelMethod:
3448 case WhiteVirtualPixelMethod:
3449 {
3450 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003451 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003452 break;
3453 }
3454 case EdgeVirtualPixelMethod:
3455 case CheckerTileVirtualPixelMethod:
3456 {
3457 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3458 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3459 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3460 {
3461 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003462 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003463 break;
3464 }
3465 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3466 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3467 exception);
3468 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3469 break;
3470 }
3471 case HorizontalTileVirtualPixelMethod:
3472 {
3473 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3474 {
3475 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003476 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003477 break;
3478 }
3479 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3480 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3481 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3482 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3483 exception);
3484 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3485 break;
3486 }
3487 case VerticalTileVirtualPixelMethod:
3488 {
3489 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3490 {
3491 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003492 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003493 break;
3494 }
3495 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3496 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3497 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3498 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3499 exception);
3500 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003501 break;
3502 }
3503 }
cristy4c08aed2011-07-01 19:47:50 +00003504 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003505 break;
cristyed231572011-07-14 02:18:59 +00003506 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003507 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003508 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003509 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003510 {
3511 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3512 s+=cache_info->metacontent_extent;
3513 }
cristy3ed852e2009-09-05 21:47:34 +00003514 continue;
3515 }
3516 /*
3517 Transfer a run of pixels.
3518 */
cristy4c08aed2011-07-01 19:47:50 +00003519 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3520 length,1UL,*virtual_nexus,exception);
3521 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003522 break;
cristy4c08aed2011-07-01 19:47:50 +00003523 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003524 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3525 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003526 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003527 {
cristy4c08aed2011-07-01 19:47:50 +00003528 (void) memcpy(s,r,(size_t) length);
3529 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003530 }
3531 }
3532 }
cristy4c08aed2011-07-01 19:47:50 +00003533 /*
3534 Free resources.
3535 */
cristy105ba3c2011-07-18 02:28:38 +00003536 if (virtual_metacontent != (void *) NULL)
3537 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003538 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3539 return(pixels);
3540}
3541
3542/*
3543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3544% %
3545% %
3546% %
3547+ G e t V i r t u a l P i x e l C a c h e %
3548% %
3549% %
3550% %
3551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3552%
3553% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3554% cache as defined by the geometry parameters. A pointer to the pixels
3555% is returned if the pixels are transferred, otherwise a NULL is returned.
3556%
3557% The format of the GetVirtualPixelCache() method is:
3558%
cristy4c08aed2011-07-01 19:47:50 +00003559% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003560% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3561% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003562% ExceptionInfo *exception)
3563%
3564% A description of each parameter follows:
3565%
3566% o image: the image.
3567%
3568% o virtual_pixel_method: the virtual pixel method.
3569%
3570% o x,y,columns,rows: These values define the perimeter of a region of
3571% pixels.
3572%
3573% o exception: return any errors or warnings in this structure.
3574%
3575*/
cristy4c08aed2011-07-01 19:47:50 +00003576static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003577 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3578 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003579{
3580 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003581 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003582
cristy5c9e6f22010-09-17 17:31:01 +00003583 const int
3584 id = GetOpenMPThreadId();
3585
cristy4c08aed2011-07-01 19:47:50 +00003586 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003587 *p;
cristy4c08aed2011-07-01 19:47:50 +00003588
cristye7cc7cf2010-09-21 13:26:47 +00003589 assert(image != (const Image *) NULL);
3590 assert(image->signature == MagickSignature);
3591 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003592 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003593 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003594 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003595 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003596 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003597 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003598}
3599
3600/*
3601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3602% %
3603% %
3604% %
3605% G e t V i r t u a l P i x e l Q u e u e %
3606% %
3607% %
3608% %
3609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610%
cristy4c08aed2011-07-01 19:47:50 +00003611% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3612% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003613%
3614% The format of the GetVirtualPixelQueue() method is:
3615%
cristy4c08aed2011-07-01 19:47:50 +00003616% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003617%
3618% A description of each parameter follows:
3619%
3620% o image: the image.
3621%
3622*/
cristy4c08aed2011-07-01 19:47:50 +00003623MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003624{
3625 CacheInfo
3626 *cache_info;
3627
cristy2036f5c2010-09-19 21:18:17 +00003628 const int
3629 id = GetOpenMPThreadId();
3630
cristy3ed852e2009-09-05 21:47:34 +00003631 assert(image != (const Image *) NULL);
3632 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003633 assert(image->cache != (Cache) NULL);
3634 cache_info=(CacheInfo *) image->cache;
3635 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003636 if (cache_info->methods.get_virtual_pixels_handler !=
3637 (GetVirtualPixelsHandler) NULL)
3638 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003639 assert(id < (int) cache_info->number_threads);
3640 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003641}
3642
3643/*
3644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3645% %
3646% %
3647% %
3648% G e t V i r t u a l P i x e l s %
3649% %
3650% %
3651% %
3652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3653%
3654% GetVirtualPixels() returns an immutable pixel region. If the
3655% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003656% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003657% copy of the pixels or it may point to the original pixels in memory.
3658% Performance is maximized if the selected region is part of one row, or one
3659% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003660% (without a copy) if the image is in memory, or in a memory-mapped file. The
3661% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003662%
3663% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003664% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3665% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3666% access the meta-content (of type void) corresponding to the the
3667% region.
cristy3ed852e2009-09-05 21:47:34 +00003668%
3669% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3670%
3671% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3672% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3673% GetCacheViewAuthenticPixels() instead.
3674%
3675% The format of the GetVirtualPixels() method is:
3676%
cristy4c08aed2011-07-01 19:47:50 +00003677% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003678% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003679% ExceptionInfo *exception)
3680%
3681% A description of each parameter follows:
3682%
3683% o image: the image.
3684%
3685% o x,y,columns,rows: These values define the perimeter of a region of
3686% pixels.
3687%
3688% o exception: return any errors or warnings in this structure.
3689%
3690*/
cristy4c08aed2011-07-01 19:47:50 +00003691MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003692 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3693 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003694{
3695 CacheInfo
3696 *cache_info;
3697
cristy2036f5c2010-09-19 21:18:17 +00003698 const int
3699 id = GetOpenMPThreadId();
3700
cristy4c08aed2011-07-01 19:47:50 +00003701 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003702 *p;
cristy4c08aed2011-07-01 19:47:50 +00003703
cristy3ed852e2009-09-05 21:47:34 +00003704 assert(image != (const Image *) NULL);
3705 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003706 assert(image->cache != (Cache) NULL);
3707 cache_info=(CacheInfo *) image->cache;
3708 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003709 if (cache_info->methods.get_virtual_pixel_handler !=
3710 (GetVirtualPixelHandler) NULL)
3711 return(cache_info->methods.get_virtual_pixel_handler(image,
3712 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003713 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003714 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003715 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003716 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003717}
3718
3719/*
3720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3721% %
3722% %
3723% %
3724+ 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 %
3725% %
3726% %
3727% %
3728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3729%
cristy4c08aed2011-07-01 19:47:50 +00003730% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3731% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003732%
3733% The format of the GetVirtualPixelsCache() method is:
3734%
cristy4c08aed2011-07-01 19:47:50 +00003735% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003736%
3737% A description of each parameter follows:
3738%
3739% o image: the image.
3740%
3741*/
cristy4c08aed2011-07-01 19:47:50 +00003742static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003743{
3744 CacheInfo
3745 *cache_info;
3746
cristy5c9e6f22010-09-17 17:31:01 +00003747 const int
3748 id = GetOpenMPThreadId();
3749
cristye7cc7cf2010-09-21 13:26:47 +00003750 assert(image != (const Image *) NULL);
3751 assert(image->signature == MagickSignature);
3752 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003753 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003754 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003755 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003756 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003757}
3758
3759/*
3760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3761% %
3762% %
3763% %
3764+ G e t V i r t u a l P i x e l s N e x u s %
3765% %
3766% %
3767% %
3768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3769%
3770% GetVirtualPixelsNexus() returns the pixels associated with the specified
3771% cache nexus.
3772%
3773% The format of the GetVirtualPixelsNexus() method is:
3774%
cristy4c08aed2011-07-01 19:47:50 +00003775% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003776% NexusInfo *nexus_info)
3777%
3778% A description of each parameter follows:
3779%
3780% o cache: the pixel cache.
3781%
3782% o nexus_info: the cache nexus to return the colormap pixels.
3783%
3784*/
cristya6577ff2011-09-02 19:54:26 +00003785MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003786 NexusInfo *nexus_info)
3787{
3788 CacheInfo
3789 *cache_info;
3790
cristye7cc7cf2010-09-21 13:26:47 +00003791 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003792 cache_info=(CacheInfo *) cache;
3793 assert(cache_info->signature == MagickSignature);
3794 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003795 return((Quantum *) NULL);
3796 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003797}
3798
3799/*
3800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3801% %
3802% %
3803% %
3804+ M a s k P i x e l C a c h e N e x u s %
3805% %
3806% %
3807% %
3808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3809%
3810% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3811% The method returns MagickTrue if the pixel region is masked, otherwise
3812% MagickFalse.
3813%
3814% The format of the MaskPixelCacheNexus() method is:
3815%
3816% MagickBooleanType MaskPixelCacheNexus(Image *image,
3817% NexusInfo *nexus_info,ExceptionInfo *exception)
3818%
3819% A description of each parameter follows:
3820%
3821% o image: the image.
3822%
3823% o nexus_info: the cache nexus to clip.
3824%
3825% o exception: return any errors or warnings in this structure.
3826%
3827*/
3828
cristy3aa93752011-12-18 15:54:24 +00003829static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3830 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003831{
3832 MagickRealType
3833 gamma;
3834
cristyaa83c2c2011-09-21 13:36:25 +00003835 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003836 {
3837 *composite=(*q);
3838 return;
3839 }
3840 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3841 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003842 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3843 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3844 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003845 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003846 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003847}
3848
3849static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3850 ExceptionInfo *exception)
3851{
3852 CacheInfo
3853 *cache_info;
3854
cristy4c08aed2011-07-01 19:47:50 +00003855 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003856 alpha,
3857 beta;
3858
3859 MagickSizeType
3860 number_pixels;
3861
3862 NexusInfo
3863 **clip_nexus,
3864 **image_nexus;
3865
cristy4c08aed2011-07-01 19:47:50 +00003866 register const Quantum
3867 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003868 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003869
cristy4c08aed2011-07-01 19:47:50 +00003870 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003871 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003872
cristye076a6e2010-08-15 19:59:43 +00003873 register ssize_t
3874 i;
3875
cristy3ed852e2009-09-05 21:47:34 +00003876 /*
3877 Apply clip mask.
3878 */
3879 if (image->debug != MagickFalse)
3880 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3881 if (image->mask == (Image *) NULL)
3882 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003883 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003884 if (cache_info == (Cache) NULL)
3885 return(MagickFalse);
3886 image_nexus=AcquirePixelCacheNexus(1);
3887 clip_nexus=AcquirePixelCacheNexus(1);
3888 if ((image_nexus == (NexusInfo **) NULL) ||
3889 (clip_nexus == (NexusInfo **) NULL))
3890 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003891 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3892 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3893 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003894 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003895 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3896 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003897 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003898 GetPixelInfo(image,&alpha);
3899 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003900 number_pixels=(MagickSizeType) nexus_info->region.width*
3901 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003902 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003903 {
cristy4c08aed2011-07-01 19:47:50 +00003904 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003905 break;
cristy803640d2011-11-17 02:11:32 +00003906 GetPixelInfoPixel(image,p,&alpha);
3907 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003908 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003909 &alpha,alpha.alpha,&beta);
3910 SetPixelRed(image,ClampToQuantum(beta.red),q);
3911 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3912 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3913 if (cache_info->colorspace == CMYKColorspace)
3914 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3915 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003916 p++;
3917 q++;
3918 r++;
3919 }
3920 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3921 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003922 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003923 return(MagickFalse);
3924 return(MagickTrue);
3925}
3926
3927/*
3928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3929% %
3930% %
3931% %
3932+ O p e n P i x e l C a c h e %
3933% %
3934% %
3935% %
3936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3937%
3938% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3939% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003940% metacontent, and memory mapping the cache if it is disk based. The cache
3941% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003942%
3943% The format of the OpenPixelCache() method is:
3944%
3945% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3946% ExceptionInfo *exception)
3947%
3948% A description of each parameter follows:
3949%
3950% o image: the image.
3951%
3952% o mode: ReadMode, WriteMode, or IOMode.
3953%
3954% o exception: return any errors or warnings in this structure.
3955%
3956*/
3957
cristyd43a46b2010-01-21 02:13:41 +00003958static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003959{
3960 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003961 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003962 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003963 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003964 {
3965 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003966 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003967 cache_info->length);
3968 }
3969}
3970
3971static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3972{
3973 CacheInfo
3974 *cache_info;
3975
3976 MagickOffsetType
3977 count,
3978 extent,
3979 offset;
3980
3981 cache_info=(CacheInfo *) image->cache;
3982 if (image->debug != MagickFalse)
3983 {
3984 char
3985 format[MaxTextExtent],
3986 message[MaxTextExtent];
3987
cristyb9080c92009-12-01 20:13:26 +00003988 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003989 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003990 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003991 cache_info->cache_filename,cache_info->file,format);
3992 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3993 }
3994 if (length != (MagickSizeType) ((MagickOffsetType) length))
3995 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003996 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003997 if (extent < 0)
3998 return(MagickFalse);
3999 if ((MagickSizeType) extent >= length)
4000 return(MagickTrue);
4001 offset=(MagickOffsetType) length-1;
4002 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4003 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4004}
4005
4006static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4007 ExceptionInfo *exception)
4008{
cristy3ed852e2009-09-05 21:47:34 +00004009 CacheInfo
4010 *cache_info,
4011 source_info;
4012
cristyf3a6a9d2010-11-07 21:02:56 +00004013 char
4014 format[MaxTextExtent],
4015 message[MaxTextExtent];
4016
cristy4c08aed2011-07-01 19:47:50 +00004017 MagickBooleanType
4018 status;
4019
cristy3ed852e2009-09-05 21:47:34 +00004020 MagickSizeType
4021 length,
4022 number_pixels;
4023
cristy3ed852e2009-09-05 21:47:34 +00004024 size_t
cristye076a6e2010-08-15 19:59:43 +00004025 columns,
cristy3ed852e2009-09-05 21:47:34 +00004026 packet_size;
4027
cristye7cc7cf2010-09-21 13:26:47 +00004028 assert(image != (const Image *) NULL);
4029 assert(image->signature == MagickSignature);
4030 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004031 if (image->debug != MagickFalse)
4032 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4033 if ((image->columns == 0) || (image->rows == 0))
4034 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4035 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004036 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004037 source_info=(*cache_info);
4038 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004039 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004040 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004041 cache_info->storage_class=image->storage_class;
4042 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004043 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004044 cache_info->rows=image->rows;
4045 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004046 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004047 cache_info->number_channels=GetPixelChannels(image);
cristy3dfccb22011-12-28 21:47:20 +00004048 (void) memcpy(cache_info->channel_map,image->channel_map,
cristy9e0719b2011-12-29 03:45:45 +00004049 MaxPixelChannels*sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004050 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004051 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004052 if (image->ping != MagickFalse)
4053 {
cristy73724512010-04-12 14:43:14 +00004054 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004055 cache_info->pixels=(Quantum *) NULL;
4056 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004057 cache_info->length=0;
4058 return(MagickTrue);
4059 }
cristy3ed852e2009-09-05 21:47:34 +00004060 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004061 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004062 if (image->metacontent_extent != 0)
4063 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004064 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004065 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004066 if (cache_info->columns != columns)
4067 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4068 image->filename);
4069 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004070 if ((cache_info->type != UndefinedCache) &&
4071 (cache_info->columns <= source_info.columns) &&
4072 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004073 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004074 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4075 {
4076 /*
4077 Inline pixel cache clone optimization.
4078 */
4079 if ((cache_info->columns == source_info.columns) &&
4080 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004081 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004082 (cache_info->metacontent_extent == source_info.metacontent_extent))
4083 return(MagickTrue);
4084 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4085 }
cristy3ed852e2009-09-05 21:47:34 +00004086 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004087 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004088 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004089 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4090 {
4091 status=AcquireMagickResource(MemoryResource,cache_info->length);
4092 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4093 (cache_info->type == MemoryCache))
4094 {
cristyd43a46b2010-01-21 02:13:41 +00004095 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004096 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004097 cache_info->pixels=source_info.pixels;
4098 else
4099 {
4100 /*
4101 Create memory pixel cache.
4102 */
cristy4c08aed2011-07-01 19:47:50 +00004103 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004104 if (image->debug != MagickFalse)
4105 {
cristy97e7a572009-12-05 15:07:53 +00004106 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004107 format);
cristyb51dff52011-05-19 16:55:47 +00004108 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004109 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4110 cache_info->filename,cache_info->mapped != MagickFalse ?
4111 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004112 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004113 format);
cristy3ed852e2009-09-05 21:47:34 +00004114 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4115 message);
4116 }
cristy3ed852e2009-09-05 21:47:34 +00004117 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004118 cache_info->metacontent=(void *) NULL;
4119 if (cache_info->metacontent_extent != 0)
4120 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004121 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004122 if (source_info.storage_class != UndefinedClass)
4123 {
cristy4c08aed2011-07-01 19:47:50 +00004124 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004125 exception);
4126 RelinquishPixelCachePixels(&source_info);
4127 }
cristy4c08aed2011-07-01 19:47:50 +00004128 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004129 }
4130 }
4131 RelinquishMagickResource(MemoryResource,cache_info->length);
4132 }
4133 /*
4134 Create pixel cache on disk.
4135 */
4136 status=AcquireMagickResource(DiskResource,cache_info->length);
4137 if (status == MagickFalse)
4138 {
4139 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4140 "CacheResourcesExhausted","`%s'",image->filename);
4141 return(MagickFalse);
4142 }
4143 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4144 {
4145 RelinquishMagickResource(DiskResource,cache_info->length);
4146 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4147 image->filename);
4148 return(MagickFalse);
4149 }
4150 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4151 cache_info->length);
4152 if (status == MagickFalse)
4153 {
4154 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4155 image->filename);
4156 return(MagickFalse);
4157 }
cristyed231572011-07-14 02:18:59 +00004158 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004159 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004160 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004161 cache_info->type=DiskCache;
4162 else
4163 {
4164 status=AcquireMagickResource(MapResource,cache_info->length);
4165 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4166 (cache_info->type != MemoryCache))
4167 cache_info->type=DiskCache;
4168 else
4169 {
cristy4c08aed2011-07-01 19:47:50 +00004170 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004171 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004172 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004173 {
cristy3ed852e2009-09-05 21:47:34 +00004174 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004175 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004176 }
4177 else
4178 {
4179 /*
4180 Create file-backed memory-mapped pixel cache.
4181 */
cristy4c08aed2011-07-01 19:47:50 +00004182 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004183 (void) ClosePixelCacheOnDisk(cache_info);
4184 cache_info->type=MapCache;
4185 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004186 cache_info->metacontent=(void *) NULL;
4187 if (cache_info->metacontent_extent != 0)
4188 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004189 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004190 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004191 {
4192 status=ClonePixelCachePixels(cache_info,&source_info,
4193 exception);
4194 RelinquishPixelCachePixels(&source_info);
4195 }
4196 if (image->debug != MagickFalse)
4197 {
cristy97e7a572009-12-05 15:07:53 +00004198 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004199 format);
cristyb51dff52011-05-19 16:55:47 +00004200 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004201 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004202 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004203 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004204 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004205 format);
cristy3ed852e2009-09-05 21:47:34 +00004206 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4207 message);
4208 }
cristy4c08aed2011-07-01 19:47:50 +00004209 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004210 }
4211 }
4212 RelinquishMagickResource(MapResource,cache_info->length);
4213 }
cristy4c08aed2011-07-01 19:47:50 +00004214 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004215 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4216 {
4217 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4218 RelinquishPixelCachePixels(&source_info);
4219 }
4220 if (image->debug != MagickFalse)
4221 {
cristyb9080c92009-12-01 20:13:26 +00004222 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004223 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004224 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004225 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004226 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004227 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004228 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4229 }
cristy4c08aed2011-07-01 19:47:50 +00004230 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004231}
4232
4233/*
4234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4235% %
4236% %
4237% %
4238+ P e r s i s t P i x e l C a c h e %
4239% %
4240% %
4241% %
4242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4243%
4244% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4245% persistent pixel cache is one that resides on disk and is not destroyed
4246% when the program exits.
4247%
4248% The format of the PersistPixelCache() method is:
4249%
4250% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4251% const MagickBooleanType attach,MagickOffsetType *offset,
4252% ExceptionInfo *exception)
4253%
4254% A description of each parameter follows:
4255%
4256% o image: the image.
4257%
4258% o filename: the persistent pixel cache filename.
4259%
cristyf3a6a9d2010-11-07 21:02:56 +00004260% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004261%
cristy3ed852e2009-09-05 21:47:34 +00004262% o initialize: A value other than zero initializes the persistent pixel
4263% cache.
4264%
4265% o offset: the offset in the persistent cache to store pixels.
4266%
4267% o exception: return any errors or warnings in this structure.
4268%
4269*/
4270MagickExport MagickBooleanType PersistPixelCache(Image *image,
4271 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4272 ExceptionInfo *exception)
4273{
4274 CacheInfo
4275 *cache_info,
4276 *clone_info;
4277
4278 Image
4279 clone_image;
4280
cristy3ed852e2009-09-05 21:47:34 +00004281 MagickBooleanType
4282 status;
4283
cristye076a6e2010-08-15 19:59:43 +00004284 ssize_t
4285 page_size;
4286
cristy3ed852e2009-09-05 21:47:34 +00004287 assert(image != (Image *) NULL);
4288 assert(image->signature == MagickSignature);
4289 if (image->debug != MagickFalse)
4290 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4291 assert(image->cache != (void *) NULL);
4292 assert(filename != (const char *) NULL);
4293 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004294 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004295 cache_info=(CacheInfo *) image->cache;
4296 assert(cache_info->signature == MagickSignature);
4297 if (attach != MagickFalse)
4298 {
4299 /*
cristy01b7eb02009-09-10 23:10:14 +00004300 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004301 */
4302 if (image->debug != MagickFalse)
4303 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004304 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004305 (void) CopyMagickString(cache_info->cache_filename,filename,
4306 MaxTextExtent);
4307 cache_info->type=DiskCache;
4308 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004309 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004310 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004311 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004312 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004313 }
cristy01b7eb02009-09-10 23:10:14 +00004314 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4315 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004316 {
cristyf84a1932010-01-03 18:00:18 +00004317 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004318 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004319 (cache_info->reference_count == 1))
4320 {
4321 int
4322 status;
4323
4324 /*
cristy01b7eb02009-09-10 23:10:14 +00004325 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004326 */
cristy320684d2011-09-23 14:55:47 +00004327 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004328 if (status == 0)
4329 {
4330 (void) CopyMagickString(cache_info->cache_filename,filename,
4331 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004332 *offset+=cache_info->length+page_size-(cache_info->length %
4333 page_size);
cristyf84a1932010-01-03 18:00:18 +00004334 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004335 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004336 if (image->debug != MagickFalse)
4337 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4338 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004339 return(MagickTrue);
4340 }
4341 }
cristyf84a1932010-01-03 18:00:18 +00004342 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004343 }
4344 /*
cristy01b7eb02009-09-10 23:10:14 +00004345 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004346 */
4347 clone_image=(*image);
4348 clone_info=(CacheInfo *) clone_image.cache;
4349 image->cache=ClonePixelCache(cache_info);
4350 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4351 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4352 cache_info->type=DiskCache;
4353 cache_info->offset=(*offset);
4354 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004355 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004356 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004357 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004358 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004359 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4360 return(status);
4361}
4362
4363/*
4364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4365% %
4366% %
4367% %
4368+ Q u e u e A u t h e n t i c N e x u s %
4369% %
4370% %
4371% %
4372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4373%
4374% QueueAuthenticNexus() allocates an region to store image pixels as defined
4375% by the region rectangle and returns a pointer to the region. This region is
4376% subsequently transferred from the pixel cache with
4377% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4378% pixels are transferred, otherwise a NULL is returned.
4379%
4380% The format of the QueueAuthenticNexus() method is:
4381%
cristy4c08aed2011-07-01 19:47:50 +00004382% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004383% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004384% const MagickBooleanType clone,NexusInfo *nexus_info,
4385% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004386%
4387% A description of each parameter follows:
4388%
4389% o image: the image.
4390%
4391% o x,y,columns,rows: These values define the perimeter of a region of
4392% pixels.
4393%
4394% o nexus_info: the cache nexus to set.
4395%
cristy65dbf172011-10-06 17:32:04 +00004396% o clone: clone the pixel cache.
4397%
cristy3ed852e2009-09-05 21:47:34 +00004398% o exception: return any errors or warnings in this structure.
4399%
4400*/
cristya6577ff2011-09-02 19:54:26 +00004401MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004402 const ssize_t y,const size_t columns,const size_t rows,
4403 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004404{
4405 CacheInfo
4406 *cache_info;
4407
4408 MagickOffsetType
4409 offset;
4410
4411 MagickSizeType
4412 number_pixels;
4413
4414 RectangleInfo
4415 region;
4416
4417 /*
4418 Validate pixel cache geometry.
4419 */
cristye7cc7cf2010-09-21 13:26:47 +00004420 assert(image != (const Image *) NULL);
4421 assert(image->signature == MagickSignature);
4422 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004423 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004424 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004425 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004426 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004427 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4428 {
4429 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4430 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004431 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004432 }
cristybb503372010-05-27 20:51:26 +00004433 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4434 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004435 {
4436 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4437 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004438 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004439 }
4440 offset=(MagickOffsetType) y*cache_info->columns+x;
4441 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004442 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004443 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4444 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4445 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004446 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004447 /*
4448 Return pixel cache.
4449 */
4450 region.x=x;
4451 region.y=y;
4452 region.width=columns;
4453 region.height=rows;
4454 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4455}
4456
4457/*
4458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4459% %
4460% %
4461% %
4462+ 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 %
4463% %
4464% %
4465% %
4466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4467%
4468% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4469% defined by the region rectangle and returns a pointer to the region. This
4470% region is subsequently transferred from the pixel cache with
4471% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4472% pixels are transferred, otherwise a NULL is returned.
4473%
4474% The format of the QueueAuthenticPixelsCache() method is:
4475%
cristy4c08aed2011-07-01 19:47:50 +00004476% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004477% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004478% ExceptionInfo *exception)
4479%
4480% A description of each parameter follows:
4481%
4482% o image: the image.
4483%
4484% o x,y,columns,rows: These values define the perimeter of a region of
4485% pixels.
4486%
4487% o exception: return any errors or warnings in this structure.
4488%
4489*/
cristy4c08aed2011-07-01 19:47:50 +00004490static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004491 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004492 ExceptionInfo *exception)
4493{
4494 CacheInfo
4495 *cache_info;
4496
cristy5c9e6f22010-09-17 17:31:01 +00004497 const int
4498 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004499
cristy4c08aed2011-07-01 19:47:50 +00004500 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004501 *q;
cristy4c08aed2011-07-01 19:47:50 +00004502
cristye7cc7cf2010-09-21 13:26:47 +00004503 assert(image != (const Image *) NULL);
4504 assert(image->signature == MagickSignature);
4505 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004506 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004507 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004508 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004509 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4510 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004511 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004512}
4513
4514/*
4515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4516% %
4517% %
4518% %
4519% Q u e u e A u t h e n t i c P i x e l s %
4520% %
4521% %
4522% %
4523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4524%
4525% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004526% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004527% region is returned, otherwise NULL is returned. The returned pointer may
4528% point to a temporary working buffer for the pixels or it may point to the
4529% final location of the pixels in memory.
4530%
4531% Write-only access means that any existing pixel values corresponding to
4532% the region are ignored. This is useful if the initial image is being
4533% created from scratch, or if the existing pixel values are to be
4534% completely replaced without need to refer to their pre-existing values.
4535% The application is free to read and write the pixel buffer returned by
4536% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4537% initialize the pixel array values. Initializing pixel array values is the
4538% application's responsibility.
4539%
4540% Performance is maximized if the selected region is part of one row, or
4541% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004542% pixels in-place (without a copy) if the image is in memory, or in a
4543% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004544% by the user.
4545%
4546% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004547% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4548% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4549% obtain the meta-content (of type void) corresponding to the region.
4550% Once the Quantum (and/or Quantum) array has been updated, the
4551% changes must be saved back to the underlying image using
4552% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004553%
4554% The format of the QueueAuthenticPixels() method is:
4555%
cristy4c08aed2011-07-01 19:47:50 +00004556% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004557% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004558% ExceptionInfo *exception)
4559%
4560% A description of each parameter follows:
4561%
4562% o image: the image.
4563%
4564% o x,y,columns,rows: These values define the perimeter of a region of
4565% pixels.
4566%
4567% o exception: return any errors or warnings in this structure.
4568%
4569*/
cristy4c08aed2011-07-01 19:47:50 +00004570MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004571 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004572 ExceptionInfo *exception)
4573{
4574 CacheInfo
4575 *cache_info;
4576
cristy2036f5c2010-09-19 21:18:17 +00004577 const int
4578 id = GetOpenMPThreadId();
4579
cristy4c08aed2011-07-01 19:47:50 +00004580 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004581 *q;
cristy4c08aed2011-07-01 19:47:50 +00004582
cristy3ed852e2009-09-05 21:47:34 +00004583 assert(image != (Image *) NULL);
4584 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004585 assert(image->cache != (Cache) NULL);
4586 cache_info=(CacheInfo *) image->cache;
4587 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004588 if (cache_info->methods.queue_authentic_pixels_handler !=
4589 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004590 {
cristyacd2ed22011-08-30 01:44:23 +00004591 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004592 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004593 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004594 }
cristy2036f5c2010-09-19 21:18:17 +00004595 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004596 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4597 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004598 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004599}
4600
4601/*
4602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4603% %
4604% %
4605% %
cristy4c08aed2011-07-01 19:47:50 +00004606+ 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 +00004607% %
4608% %
4609% %
4610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4611%
cristy4c08aed2011-07-01 19:47:50 +00004612% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004613% the pixel cache.
4614%
cristy4c08aed2011-07-01 19:47:50 +00004615% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004616%
cristy4c08aed2011-07-01 19:47:50 +00004617% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004618% NexusInfo *nexus_info,ExceptionInfo *exception)
4619%
4620% A description of each parameter follows:
4621%
4622% o cache_info: the pixel cache.
4623%
cristy4c08aed2011-07-01 19:47:50 +00004624% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004625%
4626% o exception: return any errors or warnings in this structure.
4627%
4628*/
cristy4c08aed2011-07-01 19:47:50 +00004629static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004630 NexusInfo *nexus_info,ExceptionInfo *exception)
4631{
4632 MagickOffsetType
4633 count,
4634 offset;
4635
4636 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004637 extent,
4638 length;
cristy3ed852e2009-09-05 21:47:34 +00004639
cristybb503372010-05-27 20:51:26 +00004640 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004641 y;
4642
cristy4c08aed2011-07-01 19:47:50 +00004643 register unsigned char
4644 *restrict q;
4645
cristybb503372010-05-27 20:51:26 +00004646 size_t
cristy3ed852e2009-09-05 21:47:34 +00004647 rows;
4648
cristy4c08aed2011-07-01 19:47:50 +00004649 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004650 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004651 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004652 return(MagickTrue);
4653 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4654 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004655 length=(MagickSizeType) nexus_info->region.width*
4656 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004657 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004658 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004659 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004660 switch (cache_info->type)
4661 {
4662 case MemoryCache:
4663 case MapCache:
4664 {
cristy4c08aed2011-07-01 19:47:50 +00004665 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004666 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004667
4668 /*
cristy4c08aed2011-07-01 19:47:50 +00004669 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004670 */
cristydd341db2010-03-04 19:06:38 +00004671 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004672 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004673 {
cristy48078b12010-09-23 17:11:01 +00004674 length=extent;
cristydd341db2010-03-04 19:06:38 +00004675 rows=1UL;
4676 }
cristy4c08aed2011-07-01 19:47:50 +00004677 p=(unsigned char *) cache_info->metacontent+offset*
4678 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004679 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004680 {
cristy8f036fe2010-09-18 02:02:00 +00004681 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004682 p+=cache_info->metacontent_extent*cache_info->columns;
4683 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004684 }
4685 break;
4686 }
4687 case DiskCache:
4688 {
4689 /*
cristy4c08aed2011-07-01 19:47:50 +00004690 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004691 */
4692 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4693 {
4694 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4695 cache_info->cache_filename);
4696 return(MagickFalse);
4697 }
cristydd341db2010-03-04 19:06:38 +00004698 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004699 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004700 {
cristy48078b12010-09-23 17:11:01 +00004701 length=extent;
cristydd341db2010-03-04 19:06:38 +00004702 rows=1UL;
4703 }
cristy48078b12010-09-23 17:11:01 +00004704 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004705 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004706 {
cristy48078b12010-09-23 17:11:01 +00004707 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004708 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004709 cache_info->metacontent_extent,length,(unsigned char *) q);
4710 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004711 break;
4712 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004713 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004714 }
cristybb503372010-05-27 20:51:26 +00004715 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004716 {
4717 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4718 cache_info->cache_filename);
4719 return(MagickFalse);
4720 }
4721 break;
4722 }
4723 default:
4724 break;
4725 }
4726 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004727 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004728 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004729 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004730 nexus_info->region.width,(double) nexus_info->region.height,(double)
4731 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004732 return(MagickTrue);
4733}
4734
4735/*
4736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4737% %
4738% %
4739% %
4740+ R e a d P i x e l C a c h e P i x e l s %
4741% %
4742% %
4743% %
4744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4745%
4746% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4747% cache.
4748%
4749% The format of the ReadPixelCachePixels() method is:
4750%
4751% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4752% NexusInfo *nexus_info,ExceptionInfo *exception)
4753%
4754% A description of each parameter follows:
4755%
4756% o cache_info: the pixel cache.
4757%
4758% o nexus_info: the cache nexus to read the pixels.
4759%
4760% o exception: return any errors or warnings in this structure.
4761%
4762*/
4763static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4764 NexusInfo *nexus_info,ExceptionInfo *exception)
4765{
4766 MagickOffsetType
4767 count,
4768 offset;
4769
4770 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004771 extent,
4772 length;
cristy3ed852e2009-09-05 21:47:34 +00004773
cristy4c08aed2011-07-01 19:47:50 +00004774 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004775 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004776
cristye076a6e2010-08-15 19:59:43 +00004777 register ssize_t
4778 y;
4779
cristybb503372010-05-27 20:51:26 +00004780 size_t
cristy3ed852e2009-09-05 21:47:34 +00004781 rows;
4782
cristy4c08aed2011-07-01 19:47:50 +00004783 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004784 return(MagickTrue);
4785 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4786 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004787 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004788 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004789 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004790 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004791 q=nexus_info->pixels;
4792 switch (cache_info->type)
4793 {
4794 case MemoryCache:
4795 case MapCache:
4796 {
cristy4c08aed2011-07-01 19:47:50 +00004797 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004798 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004799
4800 /*
4801 Read pixels from memory.
4802 */
cristydd341db2010-03-04 19:06:38 +00004803 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004804 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004805 {
cristy48078b12010-09-23 17:11:01 +00004806 length=extent;
cristydd341db2010-03-04 19:06:38 +00004807 rows=1UL;
4808 }
cristyed231572011-07-14 02:18:59 +00004809 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004810 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004811 {
cristy8f036fe2010-09-18 02:02:00 +00004812 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004813 p+=cache_info->number_channels*cache_info->columns;
4814 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004815 }
4816 break;
4817 }
4818 case DiskCache:
4819 {
4820 /*
4821 Read pixels from disk.
4822 */
4823 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4824 {
4825 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4826 cache_info->cache_filename);
4827 return(MagickFalse);
4828 }
cristydd341db2010-03-04 19:06:38 +00004829 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004830 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004831 {
cristy48078b12010-09-23 17:11:01 +00004832 length=extent;
cristydd341db2010-03-04 19:06:38 +00004833 rows=1UL;
4834 }
cristybb503372010-05-27 20:51:26 +00004835 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004836 {
4837 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004838 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004839 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004840 break;
4841 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004842 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004843 }
cristybb503372010-05-27 20:51:26 +00004844 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004845 {
4846 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4847 cache_info->cache_filename);
4848 return(MagickFalse);
4849 }
4850 break;
4851 }
4852 default:
4853 break;
4854 }
4855 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004856 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004857 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004858 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004859 nexus_info->region.width,(double) nexus_info->region.height,(double)
4860 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004861 return(MagickTrue);
4862}
4863
4864/*
4865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866% %
4867% %
4868% %
4869+ R e f e r e n c e P i x e l C a c h e %
4870% %
4871% %
4872% %
4873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4874%
4875% ReferencePixelCache() increments the reference count associated with the
4876% pixel cache returning a pointer to the cache.
4877%
4878% The format of the ReferencePixelCache method is:
4879%
4880% Cache ReferencePixelCache(Cache cache_info)
4881%
4882% A description of each parameter follows:
4883%
4884% o cache_info: the pixel cache.
4885%
4886*/
cristya6577ff2011-09-02 19:54:26 +00004887MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004888{
4889 CacheInfo
4890 *cache_info;
4891
4892 assert(cache != (Cache *) NULL);
4893 cache_info=(CacheInfo *) cache;
4894 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004895 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004896 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004897 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004898 return(cache_info);
4899}
4900
4901/*
4902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4903% %
4904% %
4905% %
4906+ S e t P i x e l C a c h e M e t h o d s %
4907% %
4908% %
4909% %
4910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4911%
4912% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4913%
4914% The format of the SetPixelCacheMethods() method is:
4915%
4916% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4917%
4918% A description of each parameter follows:
4919%
4920% o cache: the pixel cache.
4921%
4922% o cache_methods: Specifies a pointer to a CacheMethods structure.
4923%
4924*/
cristya6577ff2011-09-02 19:54:26 +00004925MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004926{
4927 CacheInfo
4928 *cache_info;
4929
4930 GetOneAuthenticPixelFromHandler
4931 get_one_authentic_pixel_from_handler;
4932
4933 GetOneVirtualPixelFromHandler
4934 get_one_virtual_pixel_from_handler;
4935
4936 /*
4937 Set cache pixel methods.
4938 */
4939 assert(cache != (Cache) NULL);
4940 assert(cache_methods != (CacheMethods *) NULL);
4941 cache_info=(CacheInfo *) cache;
4942 assert(cache_info->signature == MagickSignature);
4943 if (cache_info->debug != MagickFalse)
4944 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4945 cache_info->filename);
4946 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4947 cache_info->methods.get_virtual_pixel_handler=
4948 cache_methods->get_virtual_pixel_handler;
4949 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4950 cache_info->methods.destroy_pixel_handler=
4951 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004952 if (cache_methods->get_virtual_metacontent_from_handler !=
4953 (GetVirtualMetacontentFromHandler) NULL)
4954 cache_info->methods.get_virtual_metacontent_from_handler=
4955 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004956 if (cache_methods->get_authentic_pixels_handler !=
4957 (GetAuthenticPixelsHandler) NULL)
4958 cache_info->methods.get_authentic_pixels_handler=
4959 cache_methods->get_authentic_pixels_handler;
4960 if (cache_methods->queue_authentic_pixels_handler !=
4961 (QueueAuthenticPixelsHandler) NULL)
4962 cache_info->methods.queue_authentic_pixels_handler=
4963 cache_methods->queue_authentic_pixels_handler;
4964 if (cache_methods->sync_authentic_pixels_handler !=
4965 (SyncAuthenticPixelsHandler) NULL)
4966 cache_info->methods.sync_authentic_pixels_handler=
4967 cache_methods->sync_authentic_pixels_handler;
4968 if (cache_methods->get_authentic_pixels_from_handler !=
4969 (GetAuthenticPixelsFromHandler) NULL)
4970 cache_info->methods.get_authentic_pixels_from_handler=
4971 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004972 if (cache_methods->get_authentic_metacontent_from_handler !=
4973 (GetAuthenticMetacontentFromHandler) NULL)
4974 cache_info->methods.get_authentic_metacontent_from_handler=
4975 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004976 get_one_virtual_pixel_from_handler=
4977 cache_info->methods.get_one_virtual_pixel_from_handler;
4978 if (get_one_virtual_pixel_from_handler !=
4979 (GetOneVirtualPixelFromHandler) NULL)
4980 cache_info->methods.get_one_virtual_pixel_from_handler=
4981 cache_methods->get_one_virtual_pixel_from_handler;
4982 get_one_authentic_pixel_from_handler=
4983 cache_methods->get_one_authentic_pixel_from_handler;
4984 if (get_one_authentic_pixel_from_handler !=
4985 (GetOneAuthenticPixelFromHandler) NULL)
4986 cache_info->methods.get_one_authentic_pixel_from_handler=
4987 cache_methods->get_one_authentic_pixel_from_handler;
4988}
4989
4990/*
4991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4992% %
4993% %
4994% %
4995+ S e t P i x e l C a c h e N e x u s P i x e l s %
4996% %
4997% %
4998% %
4999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5000%
5001% SetPixelCacheNexusPixels() defines the region of the cache for the
5002% specified cache nexus.
5003%
5004% The format of the SetPixelCacheNexusPixels() method is:
5005%
cristy4c08aed2011-07-01 19:47:50 +00005006% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005007% const RectangleInfo *region,NexusInfo *nexus_info,
5008% ExceptionInfo *exception)
5009%
5010% A description of each parameter follows:
5011%
5012% o image: the image.
5013%
5014% o region: A pointer to the RectangleInfo structure that defines the
5015% region of this particular cache nexus.
5016%
5017% o nexus_info: the cache nexus to set.
5018%
5019% o exception: return any errors or warnings in this structure.
5020%
5021*/
cristyabd6e372010-09-15 19:11:26 +00005022
5023static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5024 NexusInfo *nexus_info,ExceptionInfo *exception)
5025{
5026 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5027 return(MagickFalse);
5028 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005029 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005030 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005031 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005032 {
5033 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005034 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005035 nexus_info->length);
5036 }
cristy4c08aed2011-07-01 19:47:50 +00005037 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005038 {
5039 (void) ThrowMagickException(exception,GetMagickModule(),
5040 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5041 cache_info->filename);
5042 return(MagickFalse);
5043 }
5044 return(MagickTrue);
5045}
5046
cristy4c08aed2011-07-01 19:47:50 +00005047static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005048 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5049{
5050 CacheInfo
5051 *cache_info;
5052
5053 MagickBooleanType
5054 status;
5055
cristy3ed852e2009-09-05 21:47:34 +00005056 MagickSizeType
5057 length,
5058 number_pixels;
5059
cristy3ed852e2009-09-05 21:47:34 +00005060 cache_info=(CacheInfo *) image->cache;
5061 assert(cache_info->signature == MagickSignature);
5062 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005063 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005064 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005065 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5066 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005067 {
cristybb503372010-05-27 20:51:26 +00005068 ssize_t
cristybad067a2010-02-15 17:20:55 +00005069 x,
5070 y;
cristy3ed852e2009-09-05 21:47:34 +00005071
cristyeaedf062010-05-29 22:36:02 +00005072 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5073 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005074 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5075 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005076 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005077 ((nexus_info->region.width == cache_info->columns) ||
5078 ((nexus_info->region.width % cache_info->columns) == 0)))))
5079 {
5080 MagickOffsetType
5081 offset;
5082
5083 /*
5084 Pixels are accessed directly from memory.
5085 */
5086 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5087 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005088 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005089 offset;
5090 nexus_info->metacontent=(void *) NULL;
5091 if (cache_info->metacontent_extent != 0)
5092 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5093 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005094 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005095 }
5096 }
5097 /*
5098 Pixels are stored in a cache region until they are synced to the cache.
5099 */
5100 number_pixels=(MagickSizeType) nexus_info->region.width*
5101 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005102 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005103 if (cache_info->metacontent_extent != 0)
5104 length+=number_pixels*cache_info->metacontent_extent;
5105 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005106 {
5107 nexus_info->length=length;
5108 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5109 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005110 {
5111 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005112 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005113 }
cristy3ed852e2009-09-05 21:47:34 +00005114 }
5115 else
5116 if (nexus_info->length != length)
5117 {
5118 RelinquishCacheNexusPixels(nexus_info);
5119 nexus_info->length=length;
5120 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5121 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005122 {
5123 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005124 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005125 }
cristy3ed852e2009-09-05 21:47:34 +00005126 }
5127 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005128 nexus_info->metacontent=(void *) NULL;
5129 if (cache_info->metacontent_extent != 0)
5130 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005131 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005132 return(nexus_info->pixels);
5133}
5134
5135/*
5136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137% %
5138% %
5139% %
5140% 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 %
5141% %
5142% %
5143% %
5144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5145%
5146% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5147% pixel cache and returns the previous setting. A virtual pixel is any pixel
5148% access that is outside the boundaries of the image cache.
5149%
5150% The format of the SetPixelCacheVirtualMethod() method is:
5151%
5152% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5153% const VirtualPixelMethod virtual_pixel_method)
5154%
5155% A description of each parameter follows:
5156%
5157% o image: the image.
5158%
5159% o virtual_pixel_method: choose the type of virtual pixel.
5160%
5161*/
cristyd1dd6e42011-09-04 01:46:08 +00005162MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005163 const VirtualPixelMethod virtual_pixel_method)
5164{
5165 CacheInfo
5166 *cache_info;
5167
5168 VirtualPixelMethod
5169 method;
5170
5171 assert(image != (Image *) NULL);
5172 assert(image->signature == MagickSignature);
5173 if (image->debug != MagickFalse)
5174 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5175 assert(image->cache != (Cache) NULL);
5176 cache_info=(CacheInfo *) image->cache;
5177 assert(cache_info->signature == MagickSignature);
5178 method=cache_info->virtual_pixel_method;
5179 cache_info->virtual_pixel_method=virtual_pixel_method;
5180 return(method);
5181}
5182
5183/*
5184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5185% %
5186% %
5187% %
5188+ 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 %
5189% %
5190% %
5191% %
5192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5193%
5194% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5195% in-memory or disk cache. The method returns MagickTrue if the pixel region
5196% is synced, otherwise MagickFalse.
5197%
5198% The format of the SyncAuthenticPixelCacheNexus() method is:
5199%
5200% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5201% NexusInfo *nexus_info,ExceptionInfo *exception)
5202%
5203% A description of each parameter follows:
5204%
5205% o image: the image.
5206%
5207% o nexus_info: the cache nexus to sync.
5208%
5209% o exception: return any errors or warnings in this structure.
5210%
5211*/
cristya6577ff2011-09-02 19:54:26 +00005212MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005213 NexusInfo *nexus_info,ExceptionInfo *exception)
5214{
5215 CacheInfo
5216 *cache_info;
5217
5218 MagickBooleanType
5219 status;
5220
5221 /*
5222 Transfer pixels to the cache.
5223 */
5224 assert(image != (Image *) NULL);
5225 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005226 if (image->cache == (Cache) NULL)
5227 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5228 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005229 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005230 if (cache_info->type == UndefinedCache)
5231 return(MagickFalse);
5232 if ((image->clip_mask != (Image *) NULL) &&
5233 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5234 return(MagickFalse);
5235 if ((image->mask != (Image *) NULL) &&
5236 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5237 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005238 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005239 return(MagickTrue);
5240 assert(cache_info->signature == MagickSignature);
5241 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005242 if ((cache_info->metacontent_extent != 0) &&
5243 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005244 return(MagickFalse);
5245 return(status);
5246}
5247
5248/*
5249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5250% %
5251% %
5252% %
5253+ S y n c A u t h e n t i c P i x e l C a c h e %
5254% %
5255% %
5256% %
5257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258%
5259% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5260% or disk cache. The method returns MagickTrue if the pixel region is synced,
5261% otherwise MagickFalse.
5262%
5263% The format of the SyncAuthenticPixelsCache() method is:
5264%
5265% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5266% ExceptionInfo *exception)
5267%
5268% A description of each parameter follows:
5269%
5270% o image: the image.
5271%
5272% o exception: return any errors or warnings in this structure.
5273%
5274*/
5275static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5276 ExceptionInfo *exception)
5277{
5278 CacheInfo
5279 *cache_info;
5280
cristy5c9e6f22010-09-17 17:31:01 +00005281 const int
5282 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005283
cristy4c08aed2011-07-01 19:47:50 +00005284 MagickBooleanType
5285 status;
5286
cristye7cc7cf2010-09-21 13:26:47 +00005287 assert(image != (Image *) NULL);
5288 assert(image->signature == MagickSignature);
5289 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005290 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005291 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005292 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005293 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5294 exception);
5295 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005296}
5297
5298/*
5299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5300% %
5301% %
5302% %
5303% S y n c A u t h e n t i c P i x e l s %
5304% %
5305% %
5306% %
5307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5308%
5309% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5310% The method returns MagickTrue if the pixel region is flushed, otherwise
5311% MagickFalse.
5312%
5313% The format of the SyncAuthenticPixels() method is:
5314%
5315% MagickBooleanType SyncAuthenticPixels(Image *image,
5316% ExceptionInfo *exception)
5317%
5318% A description of each parameter follows:
5319%
5320% o image: the image.
5321%
5322% o exception: return any errors or warnings in this structure.
5323%
5324*/
5325MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5326 ExceptionInfo *exception)
5327{
5328 CacheInfo
5329 *cache_info;
5330
cristy2036f5c2010-09-19 21:18:17 +00005331 const int
5332 id = GetOpenMPThreadId();
5333
cristy4c08aed2011-07-01 19:47:50 +00005334 MagickBooleanType
5335 status;
5336
cristy3ed852e2009-09-05 21:47:34 +00005337 assert(image != (Image *) NULL);
5338 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005339 assert(image->cache != (Cache) NULL);
5340 cache_info=(CacheInfo *) image->cache;
5341 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005342 if (cache_info->methods.sync_authentic_pixels_handler !=
5343 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005344 {
5345 status=cache_info->methods.sync_authentic_pixels_handler(image,
5346 exception);
5347 return(status);
5348 }
cristy2036f5c2010-09-19 21:18:17 +00005349 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005350 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5351 exception);
5352 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005353}
5354
5355/*
5356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5357% %
5358% %
5359% %
cristyd1dd6e42011-09-04 01:46:08 +00005360+ 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 +00005361% %
5362% %
5363% %
5364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5365%
5366% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5367% The method returns MagickTrue if the pixel region is flushed, otherwise
5368% MagickFalse.
5369%
5370% The format of the SyncImagePixelCache() method is:
5371%
5372% MagickBooleanType SyncImagePixelCache(Image *image,
5373% ExceptionInfo *exception)
5374%
5375% A description of each parameter follows:
5376%
5377% o image: the image.
5378%
5379% o exception: return any errors or warnings in this structure.
5380%
5381*/
cristyd1dd6e42011-09-04 01:46:08 +00005382MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005383 ExceptionInfo *exception)
5384{
5385 CacheInfo
5386 *cache_info;
5387
5388 assert(image != (Image *) NULL);
5389 assert(exception != (ExceptionInfo *) NULL);
5390 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5391 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5392}
5393
5394/*
5395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5396% %
5397% %
5398% %
cristy4c08aed2011-07-01 19:47:50 +00005399+ 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 +00005400% %
5401% %
5402% %
5403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5404%
cristy4c08aed2011-07-01 19:47:50 +00005405% WritePixelCacheMetacontent() writes the meta-content to the specified region
5406% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005407%
cristy4c08aed2011-07-01 19:47:50 +00005408% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005409%
cristy4c08aed2011-07-01 19:47:50 +00005410% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005411% NexusInfo *nexus_info,ExceptionInfo *exception)
5412%
5413% A description of each parameter follows:
5414%
5415% o cache_info: the pixel cache.
5416%
cristy4c08aed2011-07-01 19:47:50 +00005417% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005418%
5419% o exception: return any errors or warnings in this structure.
5420%
5421*/
cristy4c08aed2011-07-01 19:47:50 +00005422static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005423 NexusInfo *nexus_info,ExceptionInfo *exception)
5424{
5425 MagickOffsetType
5426 count,
5427 offset;
5428
5429 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005430 extent,
5431 length;
cristy3ed852e2009-09-05 21:47:34 +00005432
cristy4c08aed2011-07-01 19:47:50 +00005433 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005434 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005435
cristybb503372010-05-27 20:51:26 +00005436 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005437 y;
5438
cristybb503372010-05-27 20:51:26 +00005439 size_t
cristy3ed852e2009-09-05 21:47:34 +00005440 rows;
5441
cristy4c08aed2011-07-01 19:47:50 +00005442 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005443 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005444 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005445 return(MagickTrue);
5446 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5447 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005448 length=(MagickSizeType) nexus_info->region.width*
5449 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005450 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005451 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005452 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005453 switch (cache_info->type)
5454 {
5455 case MemoryCache:
5456 case MapCache:
5457 {
cristy4c08aed2011-07-01 19:47:50 +00005458 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005459 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005460
5461 /*
cristy4c08aed2011-07-01 19:47:50 +00005462 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005463 */
cristydd341db2010-03-04 19:06:38 +00005464 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005465 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005466 {
cristy48078b12010-09-23 17:11:01 +00005467 length=extent;
cristydd341db2010-03-04 19:06:38 +00005468 rows=1UL;
5469 }
cristy4c08aed2011-07-01 19:47:50 +00005470 q=(unsigned char *) cache_info->metacontent+offset*
5471 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005472 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005473 {
cristy8f036fe2010-09-18 02:02:00 +00005474 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005475 p+=nexus_info->region.width*cache_info->metacontent_extent;
5476 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005477 }
5478 break;
5479 }
5480 case DiskCache:
5481 {
5482 /*
cristy4c08aed2011-07-01 19:47:50 +00005483 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005484 */
5485 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5486 {
5487 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5488 cache_info->cache_filename);
5489 return(MagickFalse);
5490 }
cristydd341db2010-03-04 19:06:38 +00005491 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005492 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005493 {
cristy48078b12010-09-23 17:11:01 +00005494 length=extent;
cristydd341db2010-03-04 19:06:38 +00005495 rows=1UL;
5496 }
cristy48078b12010-09-23 17:11:01 +00005497 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005498 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005499 {
cristy48078b12010-09-23 17:11:01 +00005500 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005501 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005502 cache_info->metacontent_extent,length,(const unsigned char *) p);
5503 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005504 break;
cristy4c08aed2011-07-01 19:47:50 +00005505 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005506 offset+=cache_info->columns;
5507 }
cristybb503372010-05-27 20:51:26 +00005508 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005509 {
5510 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5511 cache_info->cache_filename);
5512 return(MagickFalse);
5513 }
5514 break;
5515 }
5516 default:
5517 break;
5518 }
5519 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005520 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005521 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005522 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005523 nexus_info->region.width,(double) nexus_info->region.height,(double)
5524 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005525 return(MagickTrue);
5526}
5527
5528/*
5529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5530% %
5531% %
5532% %
5533+ W r i t e C a c h e P i x e l s %
5534% %
5535% %
5536% %
5537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5538%
5539% WritePixelCachePixels() writes image pixels to the specified region of the
5540% pixel cache.
5541%
5542% The format of the WritePixelCachePixels() method is:
5543%
5544% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5545% NexusInfo *nexus_info,ExceptionInfo *exception)
5546%
5547% A description of each parameter follows:
5548%
5549% o cache_info: the pixel cache.
5550%
5551% o nexus_info: the cache nexus to write the pixels.
5552%
5553% o exception: return any errors or warnings in this structure.
5554%
5555*/
5556static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5557 NexusInfo *nexus_info,ExceptionInfo *exception)
5558{
5559 MagickOffsetType
5560 count,
5561 offset;
5562
5563 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005564 extent,
5565 length;
cristy3ed852e2009-09-05 21:47:34 +00005566
cristy4c08aed2011-07-01 19:47:50 +00005567 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005568 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005569
cristybb503372010-05-27 20:51:26 +00005570 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005571 y;
5572
cristybb503372010-05-27 20:51:26 +00005573 size_t
cristy3ed852e2009-09-05 21:47:34 +00005574 rows;
5575
cristy4c08aed2011-07-01 19:47:50 +00005576 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005577 return(MagickTrue);
5578 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5579 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005580 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005581 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005582 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005583 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005584 p=nexus_info->pixels;
5585 switch (cache_info->type)
5586 {
5587 case MemoryCache:
5588 case MapCache:
5589 {
cristy4c08aed2011-07-01 19:47:50 +00005590 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005591 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005592
5593 /*
5594 Write pixels to memory.
5595 */
cristydd341db2010-03-04 19:06:38 +00005596 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005597 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005598 {
cristy48078b12010-09-23 17:11:01 +00005599 length=extent;
cristydd341db2010-03-04 19:06:38 +00005600 rows=1UL;
5601 }
cristyed231572011-07-14 02:18:59 +00005602 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005603 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005604 {
cristy8f036fe2010-09-18 02:02:00 +00005605 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005606 p+=nexus_info->region.width*cache_info->number_channels;
5607 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005608 }
5609 break;
5610 }
5611 case DiskCache:
5612 {
5613 /*
5614 Write pixels to disk.
5615 */
5616 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5617 {
5618 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5619 cache_info->cache_filename);
5620 return(MagickFalse);
5621 }
cristydd341db2010-03-04 19:06:38 +00005622 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005623 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005624 {
cristy48078b12010-09-23 17:11:01 +00005625 length=extent;
cristydd341db2010-03-04 19:06:38 +00005626 rows=1UL;
5627 }
cristybb503372010-05-27 20:51:26 +00005628 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005629 {
5630 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005631 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005632 p);
5633 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005634 break;
cristyed231572011-07-14 02:18:59 +00005635 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005636 offset+=cache_info->columns;
5637 }
cristybb503372010-05-27 20:51:26 +00005638 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005639 {
5640 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5641 cache_info->cache_filename);
5642 return(MagickFalse);
5643 }
5644 break;
5645 }
5646 default:
5647 break;
5648 }
5649 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005650 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005651 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005652 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005653 nexus_info->region.width,(double) nexus_info->region.height,(double)
5654 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005655 return(MagickTrue);
5656}