blob: f5b23fcfa40488c3263e36b0e662e459336039d9 [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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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 {
cristy3ed852e2009-09-05 21:47:34 +00001001 /*
cristy4c08aed2011-07-01 19:47:50 +00001002 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001003 */
cristyed231572011-07-14 02:18:59 +00001004 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001005 if (cache_info->type != DiskCache)
1006 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1007 length);
cristy3ed852e2009-09-05 21:47:34 +00001008 else
1009 {
cristy4c08aed2011-07-01 19:47:50 +00001010 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1011 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001012 {
cristy4c08aed2011-07-01 19:47:50 +00001013 status=MagickFalse;
1014 break;
cristy3ed852e2009-09-05 21:47:34 +00001015 }
1016 }
cristy4c08aed2011-07-01 19:47:50 +00001017 cache_offset+=length;
1018 if ((y < (ssize_t) clone_info->rows) &&
1019 (x < (ssize_t) clone_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00001020 {
cristy4c08aed2011-07-01 19:47:50 +00001021 /*
1022 Write a set of pixel channels.
1023 */
cristyed231572011-07-14 02:18:59 +00001024 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001025 if (clone_info->type != DiskCache)
1026 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1027 blob,length);
1028 else
1029 {
cristy208b1002011-08-07 18:51:50 +00001030 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001031 if ((MagickSizeType) count != length)
1032 {
1033 status=MagickFalse;
1034 break;
1035 }
1036 }
1037 clone_offset+=length;
cristy3ed852e2009-09-05 21:47:34 +00001038 }
1039 }
cristyed231572011-07-14 02:18:59 +00001040 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001041 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1042 for ( ; x < (ssize_t) clone_info->columns; x++)
1043 {
1044 /*
1045 Set remaining columns with transparent pixel channels.
1046 */
1047 if (clone_info->type != DiskCache)
1048 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1049 length);
1050 else
1051 {
1052 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1053 if ((MagickSizeType) count != length)
1054 {
1055 status=MagickFalse;
1056 break;
1057 }
1058 }
1059 clone_offset+=length;
1060 }
1061 }
cristyed231572011-07-14 02:18:59 +00001062 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001063 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1064 for ( ; y < (ssize_t) clone_info->rows; y++)
1065 {
1066 /*
1067 Set remaining rows with transparent pixels.
1068 */
1069 for (x=0; x < (ssize_t) clone_info->columns; x++)
1070 {
1071 if (clone_info->type != DiskCache)
1072 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1073 length);
1074 else
1075 {
1076 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1077 if ((MagickSizeType) count != length)
1078 {
1079 status=MagickFalse;
1080 break;
1081 }
1082 }
1083 clone_offset+=length;
1084 }
1085 }
1086 if ((cache_info->metacontent_extent != 0) &&
1087 (clone_info->metacontent_extent != 0))
1088 {
1089 /*
1090 Clone metacontent.
1091 */
1092 for (y=0; y < (ssize_t) cache_info->rows; y++)
1093 {
1094 for (x=0; x < (ssize_t) cache_info->columns; x++)
1095 {
1096 /*
1097 Read a set of metacontent.
1098 */
1099 length=cache_info->metacontent_extent;
1100 if (cache_info->type != DiskCache)
1101 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1102 cache_offset,length);
1103 else
1104 {
1105 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1106 if ((MagickSizeType) count != length)
1107 {
1108 status=MagickFalse;
1109 break;
1110 }
1111 }
1112 cache_offset+=length;
1113 if ((y < (ssize_t) clone_info->rows) &&
1114 (x < (ssize_t) clone_info->columns))
1115 {
1116 /*
1117 Write a set of metacontent.
1118 */
1119 length=clone_info->metacontent_extent;
1120 if (clone_info->type != DiskCache)
1121 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1122 blob,length);
1123 else
1124 {
1125 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1126 blob);
1127 if ((MagickSizeType) count != length)
1128 {
1129 status=MagickFalse;
1130 break;
1131 }
1132 }
1133 clone_offset+=length;
1134 }
1135 }
1136 length=clone_info->metacontent_extent;
1137 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1138 for ( ; x < (ssize_t) clone_info->columns; x++)
1139 {
1140 /*
1141 Set remaining columns with metacontent.
1142 */
1143 if (clone_info->type != DiskCache)
1144 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1145 blob,length);
1146 else
1147 {
cristy208b1002011-08-07 18:51:50 +00001148 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001149 if ((MagickSizeType) count != length)
1150 {
1151 status=MagickFalse;
1152 break;
1153 }
1154 }
1155 clone_offset+=length;
1156 }
1157 }
1158 length=clone_info->metacontent_extent;
1159 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1160 for ( ; y < (ssize_t) clone_info->rows; y++)
1161 {
1162 /*
1163 Set remaining rows with metacontent.
1164 */
1165 for (x=0; x < (ssize_t) clone_info->columns; x++)
1166 {
1167 if (clone_info->type != DiskCache)
1168 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1169 blob,length);
1170 else
1171 {
1172 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1173 if ((MagickSizeType) count != length)
1174 {
1175 status=MagickFalse;
1176 break;
1177 }
1178 }
1179 clone_offset+=length;
1180 }
1181 }
1182 }
1183 if (clone_info->type == DiskCache)
1184 (void) ClosePixelCacheOnDisk(clone_info);
1185 if (cache_info->type == DiskCache)
1186 (void) ClosePixelCacheOnDisk(cache_info);
1187 blob=(unsigned char *) RelinquishMagickMemory(blob);
1188 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001189}
1190
1191static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1192 CacheInfo *cache_info,ExceptionInfo *exception)
1193{
cristy5a7fbfb2010-11-06 16:10:59 +00001194 if (cache_info->type == PingCache)
1195 return(MagickTrue);
cristy4c08aed2011-07-01 19:47:50 +00001196 if ((cache_info->columns == clone_info->columns) &&
1197 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001198 (cache_info->number_channels == clone_info->number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00001199 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1200 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1201 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001202}
1203
1204/*
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206% %
1207% %
1208% %
1209+ C l o n e P i x e l C a c h e M e t h o d s %
1210% %
1211% %
1212% %
1213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214%
1215% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1216% another.
1217%
1218% The format of the ClonePixelCacheMethods() method is:
1219%
1220% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1221%
1222% A description of each parameter follows:
1223%
1224% o clone: Specifies a pointer to a Cache structure.
1225%
1226% o cache: the pixel cache.
1227%
1228*/
cristya6577ff2011-09-02 19:54:26 +00001229MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001230{
1231 CacheInfo
1232 *cache_info,
1233 *source_info;
1234
1235 assert(clone != (Cache) NULL);
1236 source_info=(CacheInfo *) clone;
1237 assert(source_info->signature == MagickSignature);
1238 if (source_info->debug != MagickFalse)
1239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1240 source_info->filename);
1241 assert(cache != (Cache) NULL);
1242 cache_info=(CacheInfo *) cache;
1243 assert(cache_info->signature == MagickSignature);
1244 source_info->methods=cache_info->methods;
1245}
1246
1247/*
1248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249% %
1250% %
1251% %
1252+ D e s t r o y I m a g e P i x e l C a c h e %
1253% %
1254% %
1255% %
1256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257%
1258% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1259%
1260% The format of the DestroyImagePixelCache() method is:
1261%
1262% void DestroyImagePixelCache(Image *image)
1263%
1264% A description of each parameter follows:
1265%
1266% o image: the image.
1267%
1268*/
1269static void DestroyImagePixelCache(Image *image)
1270{
1271 assert(image != (Image *) NULL);
1272 assert(image->signature == MagickSignature);
1273 if (image->debug != MagickFalse)
1274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1275 if (image->cache == (void *) NULL)
1276 return;
1277 image->cache=DestroyPixelCache(image->cache);
1278}
1279
1280/*
1281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282% %
1283% %
1284% %
1285+ D e s t r o y I m a g e P i x e l s %
1286% %
1287% %
1288% %
1289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290%
1291% DestroyImagePixels() deallocates memory associated with the pixel cache.
1292%
1293% The format of the DestroyImagePixels() method is:
1294%
1295% void DestroyImagePixels(Image *image)
1296%
1297% A description of each parameter follows:
1298%
1299% o image: the image.
1300%
1301*/
1302MagickExport void DestroyImagePixels(Image *image)
1303{
1304 CacheInfo
1305 *cache_info;
1306
1307 assert(image != (const Image *) NULL);
1308 assert(image->signature == MagickSignature);
1309 if (image->debug != MagickFalse)
1310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1311 assert(image->cache != (Cache) NULL);
1312 cache_info=(CacheInfo *) image->cache;
1313 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001314 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1315 {
1316 cache_info->methods.destroy_pixel_handler(image);
1317 return;
1318 }
cristy2036f5c2010-09-19 21:18:17 +00001319 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001320}
1321
1322/*
1323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324% %
1325% %
1326% %
1327+ D e s t r o y P i x e l C a c h e %
1328% %
1329% %
1330% %
1331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332%
1333% DestroyPixelCache() deallocates memory associated with the pixel cache.
1334%
1335% The format of the DestroyPixelCache() method is:
1336%
1337% Cache DestroyPixelCache(Cache cache)
1338%
1339% A description of each parameter follows:
1340%
1341% o cache: the pixel cache.
1342%
1343*/
1344
1345static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1346{
1347 switch (cache_info->type)
1348 {
1349 case MemoryCache:
1350 {
1351 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001352 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001353 cache_info->pixels);
1354 else
cristy4c08aed2011-07-01 19:47:50 +00001355 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001356 (size_t) cache_info->length);
1357 RelinquishMagickResource(MemoryResource,cache_info->length);
1358 break;
1359 }
1360 case MapCache:
1361 {
cristy4c08aed2011-07-01 19:47:50 +00001362 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001363 cache_info->length);
1364 RelinquishMagickResource(MapResource,cache_info->length);
1365 }
1366 case DiskCache:
1367 {
1368 if (cache_info->file != -1)
1369 (void) ClosePixelCacheOnDisk(cache_info);
1370 RelinquishMagickResource(DiskResource,cache_info->length);
1371 break;
1372 }
1373 default:
1374 break;
1375 }
1376 cache_info->type=UndefinedCache;
1377 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001378 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001379}
1380
cristya6577ff2011-09-02 19:54:26 +00001381MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001382{
1383 CacheInfo
1384 *cache_info;
1385
cristy3ed852e2009-09-05 21:47:34 +00001386 assert(cache != (Cache) NULL);
1387 cache_info=(CacheInfo *) cache;
1388 assert(cache_info->signature == MagickSignature);
1389 if (cache_info->debug != MagickFalse)
1390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1391 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001392 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001393 cache_info->reference_count--;
1394 if (cache_info->reference_count != 0)
1395 {
cristyf84a1932010-01-03 18:00:18 +00001396 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001397 return((Cache) NULL);
1398 }
cristyf84a1932010-01-03 18:00:18 +00001399 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001400 if (cache_resources != (SplayTreeInfo *) NULL)
1401 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001402 if (cache_info->debug != MagickFalse)
1403 {
1404 char
1405 message[MaxTextExtent];
1406
cristyb51dff52011-05-19 16:55:47 +00001407 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001408 cache_info->filename);
1409 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1410 }
cristyc2e1bdd2009-09-10 23:43:34 +00001411 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1412 (cache_info->type != DiskCache)))
1413 RelinquishPixelCachePixels(cache_info);
1414 else
1415 {
1416 RelinquishPixelCachePixels(cache_info);
1417 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1418 }
cristy3ed852e2009-09-05 21:47:34 +00001419 *cache_info->cache_filename='\0';
1420 if (cache_info->nexus_info != (NexusInfo **) NULL)
1421 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1422 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001423 if (cache_info->random_info != (RandomInfo *) NULL)
1424 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001425 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1426 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1427 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1428 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001429 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001430 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001431 cache=(Cache) NULL;
1432 return(cache);
1433}
1434
1435/*
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437% %
1438% %
1439% %
1440+ D e s t r o y P i x e l C a c h e N e x u s %
1441% %
1442% %
1443% %
1444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445%
1446% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1447%
1448% The format of the DestroyPixelCacheNexus() method is:
1449%
1450% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001451% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001452%
1453% A description of each parameter follows:
1454%
1455% o nexus_info: the nexus to destroy.
1456%
1457% o number_threads: the number of nexus threads.
1458%
1459*/
1460
1461static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1462{
1463 if (nexus_info->mapped == MagickFalse)
1464 (void) RelinquishMagickMemory(nexus_info->cache);
1465 else
1466 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001467 nexus_info->cache=(Quantum *) NULL;
1468 nexus_info->pixels=(Quantum *) NULL;
1469 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001470 nexus_info->length=0;
1471 nexus_info->mapped=MagickFalse;
1472}
1473
cristya6577ff2011-09-02 19:54:26 +00001474MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001475 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001476{
cristybb503372010-05-27 20:51:26 +00001477 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001478 i;
1479
1480 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001481 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001482 {
cristy4c08aed2011-07-01 19:47:50 +00001483 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001484 RelinquishCacheNexusPixels(nexus_info[i]);
1485 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001486 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001487 }
cristyb41ee102010-10-04 16:46:15 +00001488 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001489 return(nexus_info);
1490}
1491
1492/*
1493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494% %
1495% %
1496% %
cristy4c08aed2011-07-01 19:47:50 +00001497% 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 +00001498% %
1499% %
1500% %
1501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502%
cristy4c08aed2011-07-01 19:47:50 +00001503% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1504% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1505% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001506%
cristy4c08aed2011-07-01 19:47:50 +00001507% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001508%
cristy4c08aed2011-07-01 19:47:50 +00001509% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001510%
1511% A description of each parameter follows:
1512%
1513% o image: the image.
1514%
1515*/
cristy4c08aed2011-07-01 19:47:50 +00001516MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001517{
1518 CacheInfo
1519 *cache_info;
1520
cristy5c9e6f22010-09-17 17:31:01 +00001521 const int
1522 id = GetOpenMPThreadId();
1523
cristy4c08aed2011-07-01 19:47:50 +00001524 void
1525 *metacontent;
1526
cristye7cc7cf2010-09-21 13:26:47 +00001527 assert(image != (const Image *) NULL);
1528 assert(image->signature == MagickSignature);
1529 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001530 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001531 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001532 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1533 (GetAuthenticMetacontentFromHandler) NULL)
1534 {
1535 metacontent=cache_info->methods.
1536 get_authentic_metacontent_from_handler(image);
1537 return(metacontent);
1538 }
cristy6ebe97c2010-07-03 01:17:28 +00001539 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001540 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1541 cache_info->nexus_info[id]);
1542 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001543}
1544
1545/*
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547% %
1548% %
1549% %
cristy4c08aed2011-07-01 19:47:50 +00001550+ 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 +00001551% %
1552% %
1553% %
1554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555%
cristy4c08aed2011-07-01 19:47:50 +00001556% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1557% with the last call to QueueAuthenticPixelsCache() or
1558% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001559%
cristy4c08aed2011-07-01 19:47:50 +00001560% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001561%
cristy4c08aed2011-07-01 19:47:50 +00001562% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001563%
1564% A description of each parameter follows:
1565%
1566% o image: the image.
1567%
1568*/
cristy4c08aed2011-07-01 19:47:50 +00001569static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001570{
1571 CacheInfo
1572 *cache_info;
1573
cristy2036f5c2010-09-19 21:18:17 +00001574 const int
1575 id = GetOpenMPThreadId();
1576
cristy4c08aed2011-07-01 19:47:50 +00001577 void
1578 *metacontent;
1579
cristy3ed852e2009-09-05 21:47:34 +00001580 assert(image != (const Image *) NULL);
1581 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001582 assert(image->cache != (Cache) NULL);
1583 cache_info=(CacheInfo *) image->cache;
1584 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001585 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001586 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1587 cache_info->nexus_info[id]);
1588 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001589}
1590
1591/*
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593% %
1594% %
1595% %
1596+ 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 %
1597% %
1598% %
1599% %
1600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601%
1602% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1603% disk pixel cache as defined by the geometry parameters. A pointer to the
1604% pixels is returned if the pixels are transferred, otherwise a NULL is
1605% returned.
1606%
1607% The format of the GetAuthenticPixelCacheNexus() method is:
1608%
cristy4c08aed2011-07-01 19:47:50 +00001609% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001610% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001611% NexusInfo *nexus_info,ExceptionInfo *exception)
1612%
1613% A description of each parameter follows:
1614%
1615% o image: the image.
1616%
1617% o x,y,columns,rows: These values define the perimeter of a region of
1618% pixels.
1619%
1620% o nexus_info: the cache nexus to return.
1621%
1622% o exception: return any errors or warnings in this structure.
1623%
1624*/
1625
cristy4c08aed2011-07-01 19:47:50 +00001626static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001627 NexusInfo *nexus_info)
1628{
cristy4c08aed2011-07-01 19:47:50 +00001629 MagickBooleanType
1630 status;
1631
cristy3ed852e2009-09-05 21:47:34 +00001632 MagickOffsetType
1633 offset;
1634
cristy73724512010-04-12 14:43:14 +00001635 if (cache_info->type == PingCache)
1636 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001637 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1638 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001639 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001640 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001641 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001642}
1643
cristya6577ff2011-09-02 19:54:26 +00001644MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001645 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001646 NexusInfo *nexus_info,ExceptionInfo *exception)
1647{
1648 CacheInfo
1649 *cache_info;
1650
cristy4c08aed2011-07-01 19:47:50 +00001651 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001652 *q;
cristy3ed852e2009-09-05 21:47:34 +00001653
1654 /*
1655 Transfer pixels from the cache.
1656 */
1657 assert(image != (Image *) NULL);
1658 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001659 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001660 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001661 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001662 cache_info=(CacheInfo *) image->cache;
1663 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001664 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001665 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001666 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001667 return((Quantum *) NULL);
1668 if (cache_info->metacontent_extent != 0)
1669 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1670 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001671 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001672}
1673
1674/*
1675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676% %
1677% %
1678% %
1679+ 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 %
1680% %
1681% %
1682% %
1683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684%
1685% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1686% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1687%
1688% The format of the GetAuthenticPixelsFromCache() method is:
1689%
cristy4c08aed2011-07-01 19:47:50 +00001690% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001691%
1692% A description of each parameter follows:
1693%
1694% o image: the image.
1695%
1696*/
cristy4c08aed2011-07-01 19:47:50 +00001697static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001698{
1699 CacheInfo
1700 *cache_info;
1701
cristy5c9e6f22010-09-17 17:31:01 +00001702 const int
1703 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001704
cristye7cc7cf2010-09-21 13:26:47 +00001705 assert(image != (const Image *) NULL);
1706 assert(image->signature == MagickSignature);
1707 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001708 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001709 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001710 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001711 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001712}
1713
1714/*
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716% %
1717% %
1718% %
1719% G e t A u t h e n t i c P i x e l Q u e u e %
1720% %
1721% %
1722% %
1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724%
cristy4c08aed2011-07-01 19:47:50 +00001725% GetAuthenticPixelQueue() returns the authentic pixels associated
1726% corresponding with the last call to QueueAuthenticPixels() or
1727% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001728%
1729% The format of the GetAuthenticPixelQueue() method is:
1730%
cristy4c08aed2011-07-01 19:47:50 +00001731% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001732%
1733% A description of each parameter follows:
1734%
1735% o image: the image.
1736%
1737*/
cristy4c08aed2011-07-01 19:47:50 +00001738MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001739{
1740 CacheInfo
1741 *cache_info;
1742
cristy2036f5c2010-09-19 21:18:17 +00001743 const int
1744 id = GetOpenMPThreadId();
1745
cristy3ed852e2009-09-05 21:47:34 +00001746 assert(image != (const Image *) NULL);
1747 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001748 assert(image->cache != (Cache) NULL);
1749 cache_info=(CacheInfo *) image->cache;
1750 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001751 if (cache_info->methods.get_authentic_pixels_from_handler !=
1752 (GetAuthenticPixelsFromHandler) NULL)
1753 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001754 assert(id < (int) cache_info->number_threads);
1755 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001756}
1757
1758/*
1759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760% %
1761% %
1762% %
1763% G e t A u t h e n t i c P i x e l s %
1764% %
1765% %
cristy4c08aed2011-07-01 19:47:50 +00001766% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001767%
1768% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001769% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001770% representing the region is returned, otherwise NULL is returned.
1771%
1772% The returned pointer may point to a temporary working copy of the pixels
1773% or it may point to the original pixels in memory. Performance is maximized
1774% if the selected region is part of one row, or one or more full rows, since
1775% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001776% if the image is in memory, or in a memory-mapped file. The returned pointer
1777% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001778%
1779% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001780% Quantum. If the image has corresponding metacontent,call
1781% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1782% meta-content corresponding to the region. Once the Quantum array has
1783% been updated, the changes must be saved back to the underlying image using
1784% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001785%
1786% The format of the GetAuthenticPixels() method is:
1787%
cristy4c08aed2011-07-01 19:47:50 +00001788% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001789% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001790% ExceptionInfo *exception)
1791%
1792% A description of each parameter follows:
1793%
1794% o image: the image.
1795%
1796% o x,y,columns,rows: These values define the perimeter of a region of
1797% pixels.
1798%
1799% o exception: return any errors or warnings in this structure.
1800%
1801*/
cristy4c08aed2011-07-01 19:47:50 +00001802MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001803 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001804 ExceptionInfo *exception)
1805{
1806 CacheInfo
1807 *cache_info;
1808
cristy2036f5c2010-09-19 21:18:17 +00001809 const int
1810 id = GetOpenMPThreadId();
1811
cristy4c08aed2011-07-01 19:47:50 +00001812 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001813 *q;
cristy4c08aed2011-07-01 19:47:50 +00001814
cristy3ed852e2009-09-05 21:47:34 +00001815 assert(image != (Image *) NULL);
1816 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001817 assert(image->cache != (Cache) NULL);
1818 cache_info=(CacheInfo *) image->cache;
1819 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001820 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001821 (GetAuthenticPixelsHandler) NULL)
1822 {
cristyacd2ed22011-08-30 01:44:23 +00001823 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1824 exception);
1825 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001826 }
cristy2036f5c2010-09-19 21:18:17 +00001827 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001828 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001829 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001830 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001831}
1832
1833/*
1834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835% %
1836% %
1837% %
1838+ G e t A u t h e n t i c P i x e l s C a c h e %
1839% %
1840% %
1841% %
1842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1843%
1844% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1845% as defined by the geometry parameters. A pointer to the pixels is returned
1846% if the pixels are transferred, otherwise a NULL is returned.
1847%
1848% The format of the GetAuthenticPixelsCache() method is:
1849%
cristy4c08aed2011-07-01 19:47:50 +00001850% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001851% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001852% ExceptionInfo *exception)
1853%
1854% A description of each parameter follows:
1855%
1856% o image: the image.
1857%
1858% o x,y,columns,rows: These values define the perimeter of a region of
1859% pixels.
1860%
1861% o exception: return any errors or warnings in this structure.
1862%
1863*/
cristy4c08aed2011-07-01 19:47:50 +00001864static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001865 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001866 ExceptionInfo *exception)
1867{
1868 CacheInfo
1869 *cache_info;
1870
cristy5c9e6f22010-09-17 17:31:01 +00001871 const int
1872 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001873
cristy4c08aed2011-07-01 19:47:50 +00001874 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001875 *q;
cristy4c08aed2011-07-01 19:47:50 +00001876
cristye7cc7cf2010-09-21 13:26:47 +00001877 assert(image != (const Image *) NULL);
1878 assert(image->signature == MagickSignature);
1879 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001880 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001881 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001882 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001883 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001884 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001885 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001886 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001887 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001888}
1889
1890/*
1891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892% %
1893% %
1894% %
1895+ G e t I m a g e E x t e n t %
1896% %
1897% %
1898% %
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900%
cristy4c08aed2011-07-01 19:47:50 +00001901% GetImageExtent() returns the extent of the pixels associated corresponding
1902% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001903%
1904% The format of the GetImageExtent() method is:
1905%
1906% MagickSizeType GetImageExtent(const Image *image)
1907%
1908% A description of each parameter follows:
1909%
1910% o image: the image.
1911%
1912*/
1913MagickExport MagickSizeType GetImageExtent(const Image *image)
1914{
1915 CacheInfo
1916 *cache_info;
1917
cristy5c9e6f22010-09-17 17:31:01 +00001918 const int
1919 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001920
cristy3ed852e2009-09-05 21:47:34 +00001921 assert(image != (Image *) NULL);
1922 assert(image->signature == MagickSignature);
1923 if (image->debug != MagickFalse)
1924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1925 assert(image->cache != (Cache) NULL);
1926 cache_info=(CacheInfo *) image->cache;
1927 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001928 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001929 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001930}
1931
1932/*
1933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1934% %
1935% %
1936% %
1937+ G e t I m a g e P i x e l C a c h e %
1938% %
1939% %
1940% %
1941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942%
1943% GetImagePixelCache() ensures that there is only a single reference to the
1944% pixel cache to be modified, updating the provided cache pointer to point to
1945% a clone of the original pixel cache if necessary.
1946%
1947% The format of the GetImagePixelCache method is:
1948%
1949% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1950% ExceptionInfo *exception)
1951%
1952% A description of each parameter follows:
1953%
1954% o image: the image.
1955%
1956% o clone: any value other than MagickFalse clones the cache pixels.
1957%
1958% o exception: return any errors or warnings in this structure.
1959%
1960*/
cristyaf894d72011-08-06 23:03:10 +00001961
cristy3ed852e2009-09-05 21:47:34 +00001962static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1963{
1964 CacheInfo
1965 *cache_info;
1966
1967 /*
1968 Does the image match the pixel cache morphology?
1969 */
1970 cache_info=(CacheInfo *) image->cache;
1971 if ((image->storage_class != cache_info->storage_class) ||
1972 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001973 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00001974 (image->columns != cache_info->columns) ||
1975 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001976 (image->number_channels != cache_info->number_channels) ||
cristy4c08aed2011-07-01 19:47:50 +00001977 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001978 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1979 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1980 return(MagickFalse);
1981 return(MagickTrue);
1982}
1983
cristycd01fae2011-08-06 23:52:42 +00001984static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1985 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001986{
1987 CacheInfo
1988 *cache_info;
1989
cristy3ed852e2009-09-05 21:47:34 +00001990 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001991 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001992 status;
1993
cristy50a10922010-02-15 18:35:25 +00001994 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001995 cpu_throttle = 0,
1996 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001997 time_limit = 0;
1998
cristy1ea34962010-07-01 19:49:21 +00001999 static time_t
cristy208b1002011-08-07 18:51:50 +00002000 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002001
cristyc4f9f132010-03-04 18:50:01 +00002002 status=MagickTrue;
2003 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002004 if (cpu_throttle == 0)
2005 {
2006 char
2007 *limit;
2008
2009 /*
2010 Set CPU throttle in milleseconds.
2011 */
2012 cpu_throttle=MagickResourceInfinity;
2013 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2014 if (limit == (char *) NULL)
2015 limit=GetPolicyValue("throttle");
2016 if (limit != (char *) NULL)
2017 {
2018 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2019 limit=DestroyString(limit);
2020 }
2021 }
2022 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2023 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002024 if (time_limit == 0)
2025 {
cristy6ebe97c2010-07-03 01:17:28 +00002026 /*
2027 Set the exire time in seconds.
2028 */
cristy1ea34962010-07-01 19:49:21 +00002029 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002030 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002031 }
2032 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002033 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002034 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002035 assert(image->cache != (Cache) NULL);
2036 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002037 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002038 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002039 {
cristyceb55ee2010-11-06 16:05:49 +00002040 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002041 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002042 {
cristyceb55ee2010-11-06 16:05:49 +00002043 Image
2044 clone_image;
2045
2046 CacheInfo
2047 *clone_info;
2048
2049 /*
2050 Clone pixel cache.
2051 */
2052 clone_image=(*image);
2053 clone_image.semaphore=AllocateSemaphoreInfo();
2054 clone_image.reference_count=1;
2055 clone_image.cache=ClonePixelCache(cache_info);
2056 clone_info=(CacheInfo *) clone_image.cache;
2057 status=OpenPixelCache(&clone_image,IOMode,exception);
2058 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002059 {
cristy5a7fbfb2010-11-06 16:10:59 +00002060 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002061 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002062 if (status != MagickFalse)
2063 {
cristy979bf772011-08-08 00:04:15 +00002064 if (cache_info->mode == ReadMode)
2065 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002066 destroy=MagickTrue;
2067 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002068 }
2069 }
cristyceb55ee2010-11-06 16:05:49 +00002070 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002071 }
cristyceb55ee2010-11-06 16:05:49 +00002072 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002073 }
cristy4320e0e2009-09-10 15:00:08 +00002074 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002075 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002076 if (status != MagickFalse)
2077 {
2078 /*
2079 Ensure the image matches the pixel cache morphology.
2080 */
2081 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002082 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002083 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2084 status=OpenPixelCache(image,IOMode,exception);
2085 }
cristyf84a1932010-01-03 18:00:18 +00002086 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002087 if (status == MagickFalse)
2088 return((Cache) NULL);
2089 return(image->cache);
2090}
2091
2092/*
2093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094% %
2095% %
2096% %
2097% G e t O n e A u t h e n t i c P i x e l %
2098% %
2099% %
2100% %
2101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102%
2103% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2104% location. The image background color is returned if an error occurs.
2105%
2106% The format of the GetOneAuthenticPixel() method is:
2107%
cristybb503372010-05-27 20:51:26 +00002108% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002109% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002110%
2111% A description of each parameter follows:
2112%
2113% o image: the image.
2114%
2115% o x,y: These values define the location of the pixel to return.
2116%
2117% o pixel: return a pixel at the specified (x,y) location.
2118%
2119% o exception: return any errors or warnings in this structure.
2120%
2121*/
cristyacbbb7c2010-06-30 18:56:48 +00002122MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002123 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002124{
2125 CacheInfo
2126 *cache_info;
2127
cristy4c08aed2011-07-01 19:47:50 +00002128 register Quantum
2129 *q;
cristy2036f5c2010-09-19 21:18:17 +00002130
cristy2ed42f62011-10-02 19:49:57 +00002131 register ssize_t
2132 i;
2133
cristy3ed852e2009-09-05 21:47:34 +00002134 assert(image != (Image *) NULL);
2135 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002136 assert(image->cache != (Cache) NULL);
2137 cache_info=(CacheInfo *) image->cache;
2138 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002139 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002140 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2141 (GetOneAuthenticPixelFromHandler) NULL)
2142 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2143 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002144 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2145 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002146 {
2147 pixel[RedPixelChannel]=image->background_color.red;
2148 pixel[GreenPixelChannel]=image->background_color.green;
2149 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002150 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002151 pixel[AlphaPixelChannel]=image->background_color.alpha;
2152 return(MagickFalse);
2153 }
2154 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2155 {
2156 PixelChannel
2157 channel;
2158
2159 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2160 pixel[channel]=q[i];
2161 }
cristy2036f5c2010-09-19 21:18:17 +00002162 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002163}
2164
2165/*
2166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167% %
2168% %
2169% %
2170+ 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 %
2171% %
2172% %
2173% %
2174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2175%
2176% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2177% location. The image background color is returned if an error occurs.
2178%
2179% The format of the GetOneAuthenticPixelFromCache() method is:
2180%
2181% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002182% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002183% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002184%
2185% A description of each parameter follows:
2186%
2187% o image: the image.
2188%
2189% o x,y: These values define the location of the pixel to return.
2190%
2191% o pixel: return a pixel at the specified (x,y) location.
2192%
2193% o exception: return any errors or warnings in this structure.
2194%
2195*/
2196static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002197 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002198{
cristy098f78c2010-09-23 17:28:44 +00002199 CacheInfo
2200 *cache_info;
2201
2202 const int
2203 id = GetOpenMPThreadId();
2204
cristy4c08aed2011-07-01 19:47:50 +00002205 register Quantum
2206 *q;
cristy3ed852e2009-09-05 21:47:34 +00002207
cristy2ed42f62011-10-02 19:49:57 +00002208 register ssize_t
2209 i;
2210
cristy0158a4b2010-09-20 13:59:45 +00002211 assert(image != (const Image *) NULL);
2212 assert(image->signature == MagickSignature);
2213 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002214 cache_info=(CacheInfo *) image->cache;
2215 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002216 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002217 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002218 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2219 exception);
2220 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002221 {
2222 pixel[RedPixelChannel]=image->background_color.red;
2223 pixel[GreenPixelChannel]=image->background_color.green;
2224 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002225 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002226 pixel[AlphaPixelChannel]=image->background_color.alpha;
2227 return(MagickFalse);
2228 }
2229 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2230 {
2231 PixelChannel
2232 channel;
2233
2234 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2235 pixel[channel]=q[i];
2236 }
cristy3ed852e2009-09-05 21:47:34 +00002237 return(MagickTrue);
2238}
2239
2240/*
2241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242% %
2243% %
2244% %
2245% G e t O n e V i r t u a l M a g i c k P i x e l %
2246% %
2247% %
2248% %
2249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250%
2251% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2252% location. The image background color is returned if an error occurs. If
2253% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2254%
2255% The format of the GetOneVirtualMagickPixel() method is:
2256%
2257% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristy52010022011-10-21 18:07:37 +00002258% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2259% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002260%
2261% A description of each parameter follows:
2262%
2263% o image: the image.
2264%
cristy52010022011-10-21 18:07:37 +00002265% o virtual_pixel_method: the virtual pixel method.
2266%
cristy3ed852e2009-09-05 21:47:34 +00002267% o x,y: these values define the location of the pixel to return.
2268%
2269% o pixel: return a pixel at the specified (x,y) location.
2270%
2271% o exception: return any errors or warnings in this structure.
2272%
2273*/
2274MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristy52010022011-10-21 18:07:37 +00002275 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2276 PixelInfo *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002277{
2278 CacheInfo
2279 *cache_info;
2280
cristy0158a4b2010-09-20 13:59:45 +00002281 const int
2282 id = GetOpenMPThreadId();
2283
cristy4c08aed2011-07-01 19:47:50 +00002284 register const Quantum
cristyacd2ed22011-08-30 01:44:23 +00002285 *p;
cristy3ed852e2009-09-05 21:47:34 +00002286
2287 assert(image != (const Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 assert(image->cache != (Cache) NULL);
2290 cache_info=(CacheInfo *) image->cache;
2291 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002292 assert(id < (int) cache_info->number_threads);
cristy52010022011-10-21 18:07:37 +00002293 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2294 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002295 GetPixelInfo(image,pixel);
cristyacd2ed22011-08-30 01:44:23 +00002296 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002297 return(MagickFalse);
cristyacd2ed22011-08-30 01:44:23 +00002298 SetPixelInfo(image,p,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002299 return(MagickTrue);
2300}
2301
2302/*
2303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2304% %
2305% %
2306% %
cristy3ed852e2009-09-05 21:47:34 +00002307% G e t O n e V i r t u a l P i x e l %
2308% %
2309% %
2310% %
2311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312%
2313% GetOneVirtualPixel() returns a single virtual pixel at the specified
2314% (x,y) location. The image background color is returned if an error occurs.
2315% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2316%
2317% The format of the GetOneVirtualPixel() method is:
2318%
cristybb503372010-05-27 20:51:26 +00002319% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002320% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002321%
2322% A description of each parameter follows:
2323%
2324% o image: the image.
2325%
2326% o x,y: These values define the location of the pixel to return.
2327%
2328% o pixel: return a pixel at the specified (x,y) location.
2329%
2330% o exception: return any errors or warnings in this structure.
2331%
2332*/
2333MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002334 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002335{
cristy3ed852e2009-09-05 21:47:34 +00002336 CacheInfo
2337 *cache_info;
2338
cristy0158a4b2010-09-20 13:59:45 +00002339 const int
2340 id = GetOpenMPThreadId();
2341
cristy4c08aed2011-07-01 19:47:50 +00002342 const Quantum
2343 *p;
cristy2036f5c2010-09-19 21:18:17 +00002344
cristy2ed42f62011-10-02 19:49:57 +00002345 register ssize_t
2346 i;
2347
cristy3ed852e2009-09-05 21:47:34 +00002348 assert(image != (const Image *) NULL);
2349 assert(image->signature == MagickSignature);
2350 assert(image->cache != (Cache) NULL);
2351 cache_info=(CacheInfo *) image->cache;
2352 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002353 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002354 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2355 (GetOneVirtualPixelFromHandler) NULL)
2356 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2357 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002358 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002359 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002360 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002361 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002362 {
2363 pixel[RedPixelChannel]=image->background_color.red;
2364 pixel[GreenPixelChannel]=image->background_color.green;
2365 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002366 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002367 pixel[AlphaPixelChannel]=image->background_color.alpha;
2368 return(MagickFalse);
2369 }
2370 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2371 {
2372 PixelChannel
2373 channel;
2374
2375 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2376 pixel[channel]=p[i];
2377 }
cristy2036f5c2010-09-19 21:18:17 +00002378 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002379}
2380
2381/*
2382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2383% %
2384% %
2385% %
2386+ 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 %
2387% %
2388% %
2389% %
2390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391%
2392% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2393% specified (x,y) location. The image background color is returned if an
2394% error occurs.
2395%
2396% The format of the GetOneVirtualPixelFromCache() method is:
2397%
2398% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002399% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002400% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002401%
2402% A description of each parameter follows:
2403%
2404% o image: the image.
2405%
2406% o virtual_pixel_method: the virtual pixel method.
2407%
2408% o x,y: These values define the location of the pixel to return.
2409%
2410% o pixel: return a pixel at the specified (x,y) location.
2411%
2412% o exception: return any errors or warnings in this structure.
2413%
2414*/
2415static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002416 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002417 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002418{
cristy0158a4b2010-09-20 13:59:45 +00002419 CacheInfo
2420 *cache_info;
2421
2422 const int
2423 id = GetOpenMPThreadId();
2424
cristy4c08aed2011-07-01 19:47:50 +00002425 const Quantum
2426 *p;
cristy3ed852e2009-09-05 21:47:34 +00002427
cristy2ed42f62011-10-02 19:49:57 +00002428 register ssize_t
2429 i;
2430
cristye7cc7cf2010-09-21 13:26:47 +00002431 assert(image != (const Image *) NULL);
2432 assert(image->signature == MagickSignature);
2433 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002434 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002435 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002436 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002437 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002439 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002440 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002441 {
2442 pixel[RedPixelChannel]=image->background_color.red;
2443 pixel[GreenPixelChannel]=image->background_color.green;
2444 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002445 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002446 pixel[AlphaPixelChannel]=image->background_color.alpha;
2447 return(MagickFalse);
2448 }
2449 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2450 {
2451 PixelChannel
2452 channel;
2453
2454 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2455 pixel[channel]=p[i];
2456 }
cristy3ed852e2009-09-05 21:47:34 +00002457 return(MagickTrue);
2458}
2459
2460/*
2461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462% %
2463% %
2464% %
2465+ G e t P i x e l C a c h e C o l o r s p a c e %
2466% %
2467% %
2468% %
2469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470%
2471% GetPixelCacheColorspace() returns the class type of the pixel cache.
2472%
2473% The format of the GetPixelCacheColorspace() method is:
2474%
2475% Colorspace GetPixelCacheColorspace(Cache cache)
2476%
2477% A description of each parameter follows:
2478%
2479% o cache: the pixel cache.
2480%
2481*/
cristya6577ff2011-09-02 19:54:26 +00002482MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002483{
2484 CacheInfo
2485 *cache_info;
2486
2487 assert(cache != (Cache) NULL);
2488 cache_info=(CacheInfo *) cache;
2489 assert(cache_info->signature == MagickSignature);
2490 if (cache_info->debug != MagickFalse)
2491 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2492 cache_info->filename);
2493 return(cache_info->colorspace);
2494}
2495
2496/*
2497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2498% %
2499% %
2500% %
2501+ G e t P i x e l C a c h e M e t h o d s %
2502% %
2503% %
2504% %
2505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2506%
2507% GetPixelCacheMethods() initializes the CacheMethods structure.
2508%
2509% The format of the GetPixelCacheMethods() method is:
2510%
2511% void GetPixelCacheMethods(CacheMethods *cache_methods)
2512%
2513% A description of each parameter follows:
2514%
2515% o cache_methods: Specifies a pointer to a CacheMethods structure.
2516%
2517*/
cristya6577ff2011-09-02 19:54:26 +00002518MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002519{
2520 assert(cache_methods != (CacheMethods *) NULL);
2521 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2522 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2523 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002524 cache_methods->get_virtual_metacontent_from_handler=
2525 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002526 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2527 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002528 cache_methods->get_authentic_metacontent_from_handler=
2529 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002530 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2531 cache_methods->get_one_authentic_pixel_from_handler=
2532 GetOneAuthenticPixelFromCache;
2533 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2534 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2535 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2536}
2537
2538/*
2539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2540% %
2541% %
2542% %
2543+ G e t P i x e l C a c h e N e x u s E x t e n t %
2544% %
2545% %
2546% %
2547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548%
cristy4c08aed2011-07-01 19:47:50 +00002549% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2550% corresponding with the last call to SetPixelCacheNexusPixels() or
2551% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002552%
2553% The format of the GetPixelCacheNexusExtent() method is:
2554%
2555% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2556% NexusInfo *nexus_info)
2557%
2558% A description of each parameter follows:
2559%
2560% o nexus_info: the nexus info.
2561%
2562*/
cristya6577ff2011-09-02 19:54:26 +00002563MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002564 NexusInfo *nexus_info)
2565{
2566 CacheInfo
2567 *cache_info;
2568
2569 MagickSizeType
2570 extent;
2571
cristy9f027d12011-09-21 01:17:17 +00002572 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002573 cache_info=(CacheInfo *) cache;
2574 assert(cache_info->signature == MagickSignature);
2575 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2576 if (extent == 0)
2577 return((MagickSizeType) cache_info->columns*cache_info->rows);
2578 return(extent);
2579}
2580
2581/*
2582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583% %
2584% %
2585% %
cristy4c08aed2011-07-01 19:47:50 +00002586+ 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 +00002587% %
2588% %
2589% %
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591%
cristy4c08aed2011-07-01 19:47:50 +00002592% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2593% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002594%
cristy4c08aed2011-07-01 19:47:50 +00002595% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002596%
cristy4c08aed2011-07-01 19:47:50 +00002597% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002598% NexusInfo *nexus_info)
2599%
2600% A description of each parameter follows:
2601%
2602% o cache: the pixel cache.
2603%
cristy4c08aed2011-07-01 19:47:50 +00002604% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002605%
2606*/
cristya6577ff2011-09-02 19:54:26 +00002607MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002608 NexusInfo *nexus_info)
2609{
2610 CacheInfo
2611 *cache_info;
2612
cristy9f027d12011-09-21 01:17:17 +00002613 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002614 cache_info=(CacheInfo *) cache;
2615 assert(cache_info->signature == MagickSignature);
2616 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002617 return((void *) NULL);
2618 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002619}
2620
2621/*
2622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2623% %
2624% %
2625% %
2626+ G e t P i x e l C a c h e N e x u s P i x e l s %
2627% %
2628% %
2629% %
2630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2631%
2632% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2633% cache nexus.
2634%
2635% The format of the GetPixelCacheNexusPixels() method is:
2636%
cristy4c08aed2011-07-01 19:47:50 +00002637% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002638% NexusInfo *nexus_info)
2639%
2640% A description of each parameter follows:
2641%
2642% o cache: the pixel cache.
2643%
2644% o nexus_info: the cache nexus to return the pixels.
2645%
2646*/
cristya6577ff2011-09-02 19:54:26 +00002647MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002648 NexusInfo *nexus_info)
2649{
2650 CacheInfo
2651 *cache_info;
2652
cristy9f027d12011-09-21 01:17:17 +00002653 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002654 cache_info=(CacheInfo *) cache;
2655 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002656 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002657 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002658 return(nexus_info->pixels);
2659}
2660
2661/*
2662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2663% %
2664% %
2665% %
cristy056ba772010-01-02 23:33:54 +00002666+ G e t P i x e l C a c h e P i x e l s %
2667% %
2668% %
2669% %
2670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671%
2672% GetPixelCachePixels() returns the pixels associated with the specified image.
2673%
2674% The format of the GetPixelCachePixels() method is:
2675%
cristyf84a1932010-01-03 18:00:18 +00002676% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2677% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002678%
2679% A description of each parameter follows:
2680%
2681% o image: the image.
2682%
2683% o length: the pixel cache length.
2684%
cristyf84a1932010-01-03 18:00:18 +00002685% o exception: return any errors or warnings in this structure.
2686%
cristy056ba772010-01-02 23:33:54 +00002687*/
cristyd1dd6e42011-09-04 01:46:08 +00002688MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002689 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002690{
2691 CacheInfo
2692 *cache_info;
2693
2694 assert(image != (const Image *) NULL);
2695 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002696 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002697 assert(length != (MagickSizeType *) NULL);
2698 assert(exception != (ExceptionInfo *) NULL);
2699 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002700 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002701 assert(cache_info->signature == MagickSignature);
2702 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002703 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002704 return((void *) NULL);
2705 *length=cache_info->length;
2706 return((void *) cache_info->pixels);
2707}
2708
2709/*
2710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711% %
2712% %
2713% %
cristyb32b90a2009-09-07 21:45:48 +00002714+ 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 +00002715% %
2716% %
2717% %
2718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719%
2720% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2721%
2722% The format of the GetPixelCacheStorageClass() method is:
2723%
2724% ClassType GetPixelCacheStorageClass(Cache cache)
2725%
2726% A description of each parameter follows:
2727%
2728% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2729%
2730% o cache: the pixel cache.
2731%
2732*/
cristya6577ff2011-09-02 19:54:26 +00002733MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002734{
2735 CacheInfo
2736 *cache_info;
2737
2738 assert(cache != (Cache) NULL);
2739 cache_info=(CacheInfo *) cache;
2740 assert(cache_info->signature == MagickSignature);
2741 if (cache_info->debug != MagickFalse)
2742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2743 cache_info->filename);
2744 return(cache_info->storage_class);
2745}
2746
2747/*
2748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749% %
2750% %
2751% %
cristyb32b90a2009-09-07 21:45:48 +00002752+ G e t P i x e l C a c h e T i l e S i z e %
2753% %
2754% %
2755% %
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757%
2758% GetPixelCacheTileSize() returns the pixel cache tile size.
2759%
2760% The format of the GetPixelCacheTileSize() method is:
2761%
cristybb503372010-05-27 20:51:26 +00002762% void GetPixelCacheTileSize(const Image *image,size_t *width,
2763% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002764%
2765% A description of each parameter follows:
2766%
2767% o image: the image.
2768%
2769% o width: the optimize cache tile width in pixels.
2770%
2771% o height: the optimize cache tile height in pixels.
2772%
2773*/
cristya6577ff2011-09-02 19:54:26 +00002774MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002775 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002776{
cristy4c08aed2011-07-01 19:47:50 +00002777 CacheInfo
2778 *cache_info;
2779
cristyb32b90a2009-09-07 21:45:48 +00002780 assert(image != (Image *) NULL);
2781 assert(image->signature == MagickSignature);
2782 if (image->debug != MagickFalse)
2783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002784 cache_info=(CacheInfo *) image->cache;
2785 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002786 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002787 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002788 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002789 *height=(*width);
2790}
2791
2792/*
2793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794% %
2795% %
2796% %
2797+ G e t P i x e l C a c h e T y p e %
2798% %
2799% %
2800% %
2801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802%
2803% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2804%
2805% The format of the GetPixelCacheType() method is:
2806%
2807% CacheType GetPixelCacheType(const Image *image)
2808%
2809% A description of each parameter follows:
2810%
2811% o image: the image.
2812%
2813*/
cristya6577ff2011-09-02 19:54:26 +00002814MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002815{
2816 CacheInfo
2817 *cache_info;
2818
2819 assert(image != (Image *) NULL);
2820 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002821 assert(image->cache != (Cache) NULL);
2822 cache_info=(CacheInfo *) image->cache;
2823 assert(cache_info->signature == MagickSignature);
2824 return(cache_info->type);
2825}
2826
2827/*
2828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829% %
2830% %
2831% %
cristy3ed852e2009-09-05 21:47:34 +00002832+ 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 %
2833% %
2834% %
2835% %
2836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837%
2838% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2839% pixel cache. A virtual pixel is any pixel access that is outside the
2840% boundaries of the image cache.
2841%
2842% The format of the GetPixelCacheVirtualMethod() method is:
2843%
2844% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2845%
2846% A description of each parameter follows:
2847%
2848% o image: the image.
2849%
2850*/
cristyd1dd6e42011-09-04 01:46:08 +00002851MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002852{
2853 CacheInfo
2854 *cache_info;
2855
2856 assert(image != (Image *) NULL);
2857 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002858 assert(image->cache != (Cache) NULL);
2859 cache_info=(CacheInfo *) image->cache;
2860 assert(cache_info->signature == MagickSignature);
2861 return(cache_info->virtual_pixel_method);
2862}
2863
2864/*
2865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866% %
2867% %
2868% %
cristy4c08aed2011-07-01 19:47:50 +00002869+ 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 +00002870% %
2871% %
2872% %
2873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874%
cristy4c08aed2011-07-01 19:47:50 +00002875% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2876% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002877%
cristy4c08aed2011-07-01 19:47:50 +00002878% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002879%
cristy4c08aed2011-07-01 19:47:50 +00002880% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002881%
2882% A description of each parameter follows:
2883%
2884% o image: the image.
2885%
2886*/
cristy4c08aed2011-07-01 19:47:50 +00002887static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002888{
2889 CacheInfo
2890 *cache_info;
2891
cristy5c9e6f22010-09-17 17:31:01 +00002892 const int
2893 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002894
cristy4c08aed2011-07-01 19:47:50 +00002895 const void
2896 *metacontent;
2897
cristye7cc7cf2010-09-21 13:26:47 +00002898 assert(image != (const Image *) NULL);
2899 assert(image->signature == MagickSignature);
2900 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002901 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002902 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002903 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002904 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2905 cache_info->nexus_info[id]);
2906 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002907}
2908
2909/*
2910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911% %
2912% %
2913% %
cristy4c08aed2011-07-01 19:47:50 +00002914+ G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00002915% %
2916% %
2917% %
2918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919%
cristy4c08aed2011-07-01 19:47:50 +00002920% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2921% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002922%
cristy4c08aed2011-07-01 19:47:50 +00002923% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002924%
cristy4c08aed2011-07-01 19:47:50 +00002925% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002926% NexusInfo *nexus_info)
2927%
2928% A description of each parameter follows:
2929%
2930% o cache: the pixel cache.
2931%
cristy4c08aed2011-07-01 19:47:50 +00002932% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002933%
2934*/
cristya6577ff2011-09-02 19:54:26 +00002935MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002936 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002937{
2938 CacheInfo
2939 *cache_info;
2940
cristye7cc7cf2010-09-21 13:26:47 +00002941 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002942 cache_info=(CacheInfo *) cache;
2943 assert(cache_info->signature == MagickSignature);
2944 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002945 return((void *) NULL);
2946 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002947}
2948
2949/*
2950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2951% %
2952% %
2953% %
cristy4c08aed2011-07-01 19:47:50 +00002954% 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 +00002955% %
2956% %
2957% %
2958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2959%
cristy4c08aed2011-07-01 19:47:50 +00002960% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2961% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2962% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002963%
cristy4c08aed2011-07-01 19:47:50 +00002964% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002965%
cristy4c08aed2011-07-01 19:47:50 +00002966% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002967%
2968% A description of each parameter follows:
2969%
2970% o image: the image.
2971%
2972*/
cristy4c08aed2011-07-01 19:47:50 +00002973MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002974{
2975 CacheInfo
2976 *cache_info;
2977
cristy2036f5c2010-09-19 21:18:17 +00002978 const int
2979 id = GetOpenMPThreadId();
2980
cristy4c08aed2011-07-01 19:47:50 +00002981 const void
2982 *metacontent;
2983
cristy3ed852e2009-09-05 21:47:34 +00002984 assert(image != (const Image *) NULL);
2985 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002986 assert(image->cache != (Cache) NULL);
2987 cache_info=(CacheInfo *) image->cache;
2988 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002989 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2990 (GetVirtualMetacontentFromHandler) NULL)
2991 {
2992 metacontent=cache_info->methods.
2993 get_virtual_metacontent_from_handler(image);
2994 return(metacontent);
2995 }
cristy2036f5c2010-09-19 21:18:17 +00002996 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002997 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2998 cache_info->nexus_info[id]);
2999 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003000}
3001
3002/*
3003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004% %
3005% %
3006% %
3007+ 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 %
3008% %
3009% %
3010% %
3011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3012%
3013% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3014% pixel cache as defined by the geometry parameters. A pointer to the pixels
3015% is returned if the pixels are transferred, otherwise a NULL is returned.
3016%
3017% The format of the GetVirtualPixelsFromNexus() method is:
3018%
cristy4c08aed2011-07-01 19:47:50 +00003019% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003020% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003021% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3022% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003023%
3024% A description of each parameter follows:
3025%
3026% o image: the image.
3027%
3028% o virtual_pixel_method: the virtual pixel method.
3029%
3030% o x,y,columns,rows: These values define the perimeter of a region of
3031% pixels.
3032%
3033% o nexus_info: the cache nexus to acquire.
3034%
3035% o exception: return any errors or warnings in this structure.
3036%
3037*/
3038
cristybb503372010-05-27 20:51:26 +00003039static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003040 DitherMatrix[64] =
3041 {
3042 0, 48, 12, 60, 3, 51, 15, 63,
3043 32, 16, 44, 28, 35, 19, 47, 31,
3044 8, 56, 4, 52, 11, 59, 7, 55,
3045 40, 24, 36, 20, 43, 27, 39, 23,
3046 2, 50, 14, 62, 1, 49, 13, 61,
3047 34, 18, 46, 30, 33, 17, 45, 29,
3048 10, 58, 6, 54, 9, 57, 5, 53,
3049 42, 26, 38, 22, 41, 25, 37, 21
3050 };
3051
cristybb503372010-05-27 20:51:26 +00003052static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003053{
cristybb503372010-05-27 20:51:26 +00003054 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003055 index;
3056
3057 index=x+DitherMatrix[x & 0x07]-32L;
3058 if (index < 0L)
3059 return(0L);
cristybb503372010-05-27 20:51:26 +00003060 if (index >= (ssize_t) columns)
3061 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003062 return(index);
3063}
3064
cristybb503372010-05-27 20:51:26 +00003065static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003066{
cristybb503372010-05-27 20:51:26 +00003067 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003068 index;
3069
3070 index=y+DitherMatrix[y & 0x07]-32L;
3071 if (index < 0L)
3072 return(0L);
cristybb503372010-05-27 20:51:26 +00003073 if (index >= (ssize_t) rows)
3074 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003075 return(index);
3076}
3077
cristybb503372010-05-27 20:51:26 +00003078static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003079{
3080 if (x < 0L)
3081 return(0L);
cristybb503372010-05-27 20:51:26 +00003082 if (x >= (ssize_t) columns)
3083 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003084 return(x);
3085}
3086
cristybb503372010-05-27 20:51:26 +00003087static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003088{
3089 if (y < 0L)
3090 return(0L);
cristybb503372010-05-27 20:51:26 +00003091 if (y >= (ssize_t) rows)
3092 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003093 return(y);
3094}
3095
cristybb503372010-05-27 20:51:26 +00003096static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003097{
cristybb503372010-05-27 20:51:26 +00003098 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003099}
3100
cristybb503372010-05-27 20:51:26 +00003101static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003102{
cristybb503372010-05-27 20:51:26 +00003103 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003104}
3105
cristybb503372010-05-27 20:51:26 +00003106static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3107 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003108{
3109 MagickModulo
3110 modulo;
3111
cristy6162bb42011-07-18 11:34:09 +00003112 /*
3113 Compute the remainder of dividing offset by extent. It returns not only
3114 the quotient (tile the offset falls in) but also the positive remainer
3115 within that tile such that 0 <= remainder < extent. This method is
3116 essentially a ldiv() using a floored modulo division rather than the
3117 normal default truncated modulo division.
3118 */
cristybb503372010-05-27 20:51:26 +00003119 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003120 if (offset < 0L)
3121 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003122 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003123 return(modulo);
3124}
3125
cristya6577ff2011-09-02 19:54:26 +00003126MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003127 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3128 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003129 ExceptionInfo *exception)
3130{
3131 CacheInfo
3132 *cache_info;
3133
3134 MagickOffsetType
3135 offset;
3136
3137 MagickSizeType
3138 length,
3139 number_pixels;
3140
3141 NexusInfo
3142 **virtual_nexus;
3143
cristy4c08aed2011-07-01 19:47:50 +00003144 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003145 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003146 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003147
3148 RectangleInfo
3149 region;
3150
cristy4c08aed2011-07-01 19:47:50 +00003151 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003152 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003153
cristy4c08aed2011-07-01 19:47:50 +00003154 register const void
3155 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003156
cristy4c08aed2011-07-01 19:47:50 +00003157 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003158 *restrict q;
3159
cristybb503372010-05-27 20:51:26 +00003160 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003161 i,
3162 u;
cristy3ed852e2009-09-05 21:47:34 +00003163
cristy4c08aed2011-07-01 19:47:50 +00003164 register unsigned char
3165 *restrict s;
3166
cristy105ba3c2011-07-18 02:28:38 +00003167 ssize_t
3168 v;
3169
cristy4c08aed2011-07-01 19:47:50 +00003170 void
cristy105ba3c2011-07-18 02:28:38 +00003171 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003172
cristy3ed852e2009-09-05 21:47:34 +00003173 /*
3174 Acquire pixels.
3175 */
cristye7cc7cf2010-09-21 13:26:47 +00003176 assert(image != (const Image *) NULL);
3177 assert(image->signature == MagickSignature);
3178 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003179 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003180 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003181 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003182 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003183 region.x=x;
3184 region.y=y;
3185 region.width=columns;
3186 region.height=rows;
3187 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003188 if (pixels == (Quantum *) NULL)
3189 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003190 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003191 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3192 nexus_info->region.x;
3193 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3194 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003195 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3196 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003197 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3198 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003199 {
3200 MagickBooleanType
3201 status;
3202
3203 /*
3204 Pixel request is inside cache extents.
3205 */
cristy4c08aed2011-07-01 19:47:50 +00003206 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003207 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003208 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3209 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003210 return((const Quantum *) NULL);
3211 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003212 {
cristy4c08aed2011-07-01 19:47:50 +00003213 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003214 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003215 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003216 }
cristyacd2ed22011-08-30 01:44:23 +00003217 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003218 }
3219 /*
3220 Pixel request is outside cache extents.
3221 */
cristy4c08aed2011-07-01 19:47:50 +00003222 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003223 virtual_nexus=AcquirePixelCacheNexus(1);
3224 if (virtual_nexus == (NexusInfo **) NULL)
3225 {
cristy4c08aed2011-07-01 19:47:50 +00003226 if (virtual_nexus != (NexusInfo **) NULL)
3227 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003228 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3229 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003230 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003231 }
cristy105ba3c2011-07-18 02:28:38 +00003232 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3233 sizeof(*virtual_pixel));
3234 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003235 switch (virtual_pixel_method)
3236 {
cristy4c08aed2011-07-01 19:47:50 +00003237 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003238 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003239 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003240 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003241 case MaskVirtualPixelMethod:
3242 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003243 case EdgeVirtualPixelMethod:
3244 case CheckerTileVirtualPixelMethod:
3245 case HorizontalTileVirtualPixelMethod:
3246 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003247 {
cristy4c08aed2011-07-01 19:47:50 +00003248 if (cache_info->metacontent_extent != 0)
3249 {
cristy6162bb42011-07-18 11:34:09 +00003250 /*
3251 Acquire a metacontent buffer.
3252 */
cristya64b85d2011-09-14 01:02:31 +00003253 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003254 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003255 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003256 {
cristy4c08aed2011-07-01 19:47:50 +00003257 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3258 (void) ThrowMagickException(exception,GetMagickModule(),
3259 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3260 return((const Quantum *) NULL);
3261 }
cristy105ba3c2011-07-18 02:28:38 +00003262 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003263 cache_info->metacontent_extent);
3264 }
3265 switch (virtual_pixel_method)
3266 {
3267 case BlackVirtualPixelMethod:
3268 {
cristy30301712011-07-18 15:06:51 +00003269 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3270 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003271 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3272 break;
3273 }
3274 case GrayVirtualPixelMethod:
3275 {
cristy30301712011-07-18 15:06:51 +00003276 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003277 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3278 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003279 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3280 break;
3281 }
3282 case TransparentVirtualPixelMethod:
3283 {
cristy30301712011-07-18 15:06:51 +00003284 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3285 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003286 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3287 break;
3288 }
3289 case MaskVirtualPixelMethod:
3290 case WhiteVirtualPixelMethod:
3291 {
cristy30301712011-07-18 15:06:51 +00003292 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3293 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003294 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3295 break;
3296 }
3297 default:
3298 {
3299 SetPixelRed(image,image->background_color.red,virtual_pixel);
3300 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3301 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003302 if (image->colorspace == CMYKColorspace)
3303 SetPixelBlack(image,image->background_color.black,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003304 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3305 break;
3306 }
3307 }
cristy3ed852e2009-09-05 21:47:34 +00003308 break;
3309 }
3310 default:
cristy3ed852e2009-09-05 21:47:34 +00003311 break;
cristy3ed852e2009-09-05 21:47:34 +00003312 }
cristybb503372010-05-27 20:51:26 +00003313 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003314 {
cristybb503372010-05-27 20:51:26 +00003315 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003316 {
3317 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003318 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003319 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3320 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003321 {
3322 MagickModulo
3323 x_modulo,
3324 y_modulo;
3325
3326 /*
3327 Transfer a single pixel.
3328 */
3329 length=(MagickSizeType) 1;
3330 switch (virtual_pixel_method)
3331 {
cristy3ed852e2009-09-05 21:47:34 +00003332 default:
3333 {
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003335 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003336 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003338 break;
3339 }
3340 case RandomVirtualPixelMethod:
3341 {
3342 if (cache_info->random_info == (RandomInfo *) NULL)
3343 cache_info->random_info=AcquireRandomInfo();
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003345 RandomX(cache_info->random_info,cache_info->columns),
3346 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003347 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003348 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003349 break;
3350 }
3351 case DitherVirtualPixelMethod:
3352 {
3353 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003354 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003355 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003356 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003357 break;
3358 }
3359 case TileVirtualPixelMethod:
3360 {
3361 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3362 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003364 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003365 exception);
cristy4c08aed2011-07-01 19:47:50 +00003366 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
3368 }
3369 case MirrorVirtualPixelMethod:
3370 {
3371 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3372 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003373 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003374 x_modulo.remainder-1L;
3375 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3376 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003377 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003378 y_modulo.remainder-1L;
3379 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003380 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003381 exception);
cristy4c08aed2011-07-01 19:47:50 +00003382 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003383 break;
3384 }
3385 case HorizontalTileEdgeVirtualPixelMethod:
3386 {
3387 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3388 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003389 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003390 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003391 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003392 break;
3393 }
3394 case VerticalTileEdgeVirtualPixelMethod:
3395 {
3396 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3397 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003398 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003399 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003400 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3401 break;
3402 }
3403 case BackgroundVirtualPixelMethod:
3404 case BlackVirtualPixelMethod:
3405 case GrayVirtualPixelMethod:
3406 case TransparentVirtualPixelMethod:
3407 case MaskVirtualPixelMethod:
3408 case WhiteVirtualPixelMethod:
3409 {
3410 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003411 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003412 break;
3413 }
3414 case EdgeVirtualPixelMethod:
3415 case CheckerTileVirtualPixelMethod:
3416 {
3417 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3418 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3419 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3420 {
3421 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003422 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003423 break;
3424 }
3425 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3426 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3427 exception);
3428 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3429 break;
3430 }
3431 case HorizontalTileVirtualPixelMethod:
3432 {
3433 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3434 {
3435 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003436 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003437 break;
3438 }
3439 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3440 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3441 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3442 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3443 exception);
3444 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3445 break;
3446 }
3447 case VerticalTileVirtualPixelMethod:
3448 {
3449 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3450 {
3451 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003452 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003453 break;
3454 }
3455 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3456 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3457 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3458 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3459 exception);
3460 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003461 break;
3462 }
3463 }
cristy4c08aed2011-07-01 19:47:50 +00003464 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003465 break;
cristyed231572011-07-14 02:18:59 +00003466 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003467 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003468 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003469 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003470 {
3471 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3472 s+=cache_info->metacontent_extent;
3473 }
cristy3ed852e2009-09-05 21:47:34 +00003474 continue;
3475 }
3476 /*
3477 Transfer a run of pixels.
3478 */
cristy4c08aed2011-07-01 19:47:50 +00003479 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3480 length,1UL,*virtual_nexus,exception);
3481 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003482 break;
cristy4c08aed2011-07-01 19:47:50 +00003483 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003484 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3485 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003486 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003487 {
cristy4c08aed2011-07-01 19:47:50 +00003488 (void) memcpy(s,r,(size_t) length);
3489 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003490 }
3491 }
3492 }
cristy4c08aed2011-07-01 19:47:50 +00003493 /*
3494 Free resources.
3495 */
cristy105ba3c2011-07-18 02:28:38 +00003496 if (virtual_metacontent != (void *) NULL)
3497 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003498 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3499 return(pixels);
3500}
3501
3502/*
3503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3504% %
3505% %
3506% %
3507+ G e t V i r t u a l P i x e l C a c h e %
3508% %
3509% %
3510% %
3511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3512%
3513% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3514% cache as defined by the geometry parameters. A pointer to the pixels
3515% is returned if the pixels are transferred, otherwise a NULL is returned.
3516%
3517% The format of the GetVirtualPixelCache() method is:
3518%
cristy4c08aed2011-07-01 19:47:50 +00003519% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003520% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3521% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003522% ExceptionInfo *exception)
3523%
3524% A description of each parameter follows:
3525%
3526% o image: the image.
3527%
3528% o virtual_pixel_method: the virtual pixel method.
3529%
3530% o x,y,columns,rows: These values define the perimeter of a region of
3531% pixels.
3532%
3533% o exception: return any errors or warnings in this structure.
3534%
3535*/
cristy4c08aed2011-07-01 19:47:50 +00003536static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003537 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3538 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003539{
3540 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003541 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003542
cristy5c9e6f22010-09-17 17:31:01 +00003543 const int
3544 id = GetOpenMPThreadId();
3545
cristy4c08aed2011-07-01 19:47:50 +00003546 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003547 *p;
cristy4c08aed2011-07-01 19:47:50 +00003548
cristye7cc7cf2010-09-21 13:26:47 +00003549 assert(image != (const Image *) NULL);
3550 assert(image->signature == MagickSignature);
3551 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003552 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003553 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003554 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003555 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003556 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003557 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003558}
3559
3560/*
3561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562% %
3563% %
3564% %
3565% G e t V i r t u a l P i x e l Q u e u e %
3566% %
3567% %
3568% %
3569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3570%
cristy4c08aed2011-07-01 19:47:50 +00003571% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3572% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003573%
3574% The format of the GetVirtualPixelQueue() method is:
3575%
cristy4c08aed2011-07-01 19:47:50 +00003576% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003577%
3578% A description of each parameter follows:
3579%
3580% o image: the image.
3581%
3582*/
cristy4c08aed2011-07-01 19:47:50 +00003583MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003584{
3585 CacheInfo
3586 *cache_info;
3587
cristy2036f5c2010-09-19 21:18:17 +00003588 const int
3589 id = GetOpenMPThreadId();
3590
cristy3ed852e2009-09-05 21:47:34 +00003591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003593 assert(image->cache != (Cache) NULL);
3594 cache_info=(CacheInfo *) image->cache;
3595 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003596 if (cache_info->methods.get_virtual_pixels_handler !=
3597 (GetVirtualPixelsHandler) NULL)
3598 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003599 assert(id < (int) cache_info->number_threads);
3600 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003601}
3602
3603/*
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605% %
3606% %
3607% %
3608% G e t V i r t u a l P i x e l s %
3609% %
3610% %
3611% %
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613%
3614% GetVirtualPixels() returns an immutable pixel region. If the
3615% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003616% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003617% copy of the pixels or it may point to the original pixels in memory.
3618% Performance is maximized if the selected region is part of one row, or one
3619% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003620% (without a copy) if the image is in memory, or in a memory-mapped file. The
3621% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003622%
3623% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003624% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3625% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3626% access the meta-content (of type void) corresponding to the the
3627% region.
cristy3ed852e2009-09-05 21:47:34 +00003628%
3629% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3630%
3631% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3632% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3633% GetCacheViewAuthenticPixels() instead.
3634%
3635% The format of the GetVirtualPixels() method is:
3636%
cristy4c08aed2011-07-01 19:47:50 +00003637% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003638% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003639% ExceptionInfo *exception)
3640%
3641% A description of each parameter follows:
3642%
3643% o image: the image.
3644%
3645% o x,y,columns,rows: These values define the perimeter of a region of
3646% pixels.
3647%
3648% o exception: return any errors or warnings in this structure.
3649%
3650*/
cristy4c08aed2011-07-01 19:47:50 +00003651MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003652 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3653 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003654{
3655 CacheInfo
3656 *cache_info;
3657
cristy2036f5c2010-09-19 21:18:17 +00003658 const int
3659 id = GetOpenMPThreadId();
3660
cristy4c08aed2011-07-01 19:47:50 +00003661 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003662 *p;
cristy4c08aed2011-07-01 19:47:50 +00003663
cristy3ed852e2009-09-05 21:47:34 +00003664 assert(image != (const Image *) NULL);
3665 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003666 assert(image->cache != (Cache) NULL);
3667 cache_info=(CacheInfo *) image->cache;
3668 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003669 if (cache_info->methods.get_virtual_pixel_handler !=
3670 (GetVirtualPixelHandler) NULL)
3671 return(cache_info->methods.get_virtual_pixel_handler(image,
3672 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003673 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003674 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003675 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003676 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003677}
3678
3679/*
3680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3681% %
3682% %
3683% %
3684+ 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 %
3685% %
3686% %
3687% %
3688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3689%
cristy4c08aed2011-07-01 19:47:50 +00003690% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3691% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003692%
3693% The format of the GetVirtualPixelsCache() method is:
3694%
cristy4c08aed2011-07-01 19:47:50 +00003695% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003696%
3697% A description of each parameter follows:
3698%
3699% o image: the image.
3700%
3701*/
cristy4c08aed2011-07-01 19:47:50 +00003702static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003703{
3704 CacheInfo
3705 *cache_info;
3706
cristy5c9e6f22010-09-17 17:31:01 +00003707 const int
3708 id = GetOpenMPThreadId();
3709
cristye7cc7cf2010-09-21 13:26:47 +00003710 assert(image != (const Image *) NULL);
3711 assert(image->signature == MagickSignature);
3712 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003713 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003714 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003715 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003716 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
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 N e x u s %
3725% %
3726% %
3727% %
3728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3729%
3730% GetVirtualPixelsNexus() returns the pixels associated with the specified
3731% cache nexus.
3732%
3733% The format of the GetVirtualPixelsNexus() method is:
3734%
cristy4c08aed2011-07-01 19:47:50 +00003735% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003736% NexusInfo *nexus_info)
3737%
3738% A description of each parameter follows:
3739%
3740% o cache: the pixel cache.
3741%
3742% o nexus_info: the cache nexus to return the colormap pixels.
3743%
3744*/
cristya6577ff2011-09-02 19:54:26 +00003745MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003746 NexusInfo *nexus_info)
3747{
3748 CacheInfo
3749 *cache_info;
3750
cristye7cc7cf2010-09-21 13:26:47 +00003751 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003752 cache_info=(CacheInfo *) cache;
3753 assert(cache_info->signature == MagickSignature);
3754 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003755 return((Quantum *) NULL);
3756 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003757}
3758
3759/*
3760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3761% %
3762% %
3763% %
3764+ M a s k P i x e l C a c h e N e x u s %
3765% %
3766% %
3767% %
3768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3769%
3770% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3771% The method returns MagickTrue if the pixel region is masked, otherwise
3772% MagickFalse.
3773%
3774% The format of the MaskPixelCacheNexus() method is:
3775%
3776% MagickBooleanType MaskPixelCacheNexus(Image *image,
3777% NexusInfo *nexus_info,ExceptionInfo *exception)
3778%
3779% A description of each parameter follows:
3780%
3781% o image: the image.
3782%
3783% o nexus_info: the cache nexus to clip.
3784%
3785% o exception: return any errors or warnings in this structure.
3786%
3787*/
3788
cristy4c08aed2011-07-01 19:47:50 +00003789static inline void MagickPixelCompositeMask(const PixelInfo *p,
3790 const MagickRealType alpha,const PixelInfo *q,
3791 const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003792{
3793 MagickRealType
3794 gamma;
3795
cristyaa83c2c2011-09-21 13:36:25 +00003796 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003797 {
3798 *composite=(*q);
3799 return;
3800 }
3801 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3802 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003803 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3804 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3805 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003806 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003807 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003808}
3809
3810static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3811 ExceptionInfo *exception)
3812{
3813 CacheInfo
3814 *cache_info;
3815
cristy4c08aed2011-07-01 19:47:50 +00003816 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003817 alpha,
3818 beta;
3819
3820 MagickSizeType
3821 number_pixels;
3822
3823 NexusInfo
3824 **clip_nexus,
3825 **image_nexus;
3826
cristy4c08aed2011-07-01 19:47:50 +00003827 register const Quantum
3828 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003829 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003830
cristy4c08aed2011-07-01 19:47:50 +00003831 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003832 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003833
cristye076a6e2010-08-15 19:59:43 +00003834 register ssize_t
3835 i;
3836
cristy3ed852e2009-09-05 21:47:34 +00003837 /*
3838 Apply clip mask.
3839 */
3840 if (image->debug != MagickFalse)
3841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3842 if (image->mask == (Image *) NULL)
3843 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003844 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003845 if (cache_info == (Cache) NULL)
3846 return(MagickFalse);
3847 image_nexus=AcquirePixelCacheNexus(1);
3848 clip_nexus=AcquirePixelCacheNexus(1);
3849 if ((image_nexus == (NexusInfo **) NULL) ||
3850 (clip_nexus == (NexusInfo **) NULL))
3851 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003852 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3853 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3854 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003855 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003856 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3857 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003858 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003859 GetPixelInfo(image,&alpha);
3860 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003861 number_pixels=(MagickSizeType) nexus_info->region.width*
3862 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003863 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003864 {
cristy4c08aed2011-07-01 19:47:50 +00003865 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003866 break;
cristy4c08aed2011-07-01 19:47:50 +00003867 SetPixelInfo(image,p,&alpha);
3868 SetPixelInfo(image,q,&beta);
3869 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3870 &alpha,alpha.alpha,&beta);
3871 SetPixelRed(image,ClampToQuantum(beta.red),q);
3872 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3873 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3874 if (cache_info->colorspace == CMYKColorspace)
3875 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3876 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003877 p++;
3878 q++;
3879 r++;
3880 }
3881 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3882 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003883 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003884 return(MagickFalse);
3885 return(MagickTrue);
3886}
3887
3888/*
3889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3890% %
3891% %
3892% %
3893+ O p e n P i x e l C a c h e %
3894% %
3895% %
3896% %
3897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3898%
3899% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3900% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003901% metacontent, and memory mapping the cache if it is disk based. The cache
3902% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003903%
3904% The format of the OpenPixelCache() method is:
3905%
3906% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3907% ExceptionInfo *exception)
3908%
3909% A description of each parameter follows:
3910%
3911% o image: the image.
3912%
3913% o mode: ReadMode, WriteMode, or IOMode.
3914%
3915% o exception: return any errors or warnings in this structure.
3916%
3917*/
3918
cristyd43a46b2010-01-21 02:13:41 +00003919static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003920{
3921 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003922 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003923 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003924 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003925 {
3926 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003927 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003928 cache_info->length);
3929 }
3930}
3931
3932static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3933{
3934 CacheInfo
3935 *cache_info;
3936
3937 MagickOffsetType
3938 count,
3939 extent,
3940 offset;
3941
3942 cache_info=(CacheInfo *) image->cache;
3943 if (image->debug != MagickFalse)
3944 {
3945 char
3946 format[MaxTextExtent],
3947 message[MaxTextExtent];
3948
cristyb9080c92009-12-01 20:13:26 +00003949 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003950 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003951 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003952 cache_info->cache_filename,cache_info->file,format);
3953 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3954 }
3955 if (length != (MagickSizeType) ((MagickOffsetType) length))
3956 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003957 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003958 if (extent < 0)
3959 return(MagickFalse);
3960 if ((MagickSizeType) extent >= length)
3961 return(MagickTrue);
3962 offset=(MagickOffsetType) length-1;
3963 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3964 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3965}
3966
3967static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3968 ExceptionInfo *exception)
3969{
cristy3ed852e2009-09-05 21:47:34 +00003970 CacheInfo
3971 *cache_info,
3972 source_info;
3973
cristyf3a6a9d2010-11-07 21:02:56 +00003974 char
3975 format[MaxTextExtent],
3976 message[MaxTextExtent];
3977
cristy4c08aed2011-07-01 19:47:50 +00003978 MagickBooleanType
3979 status;
3980
cristy3ed852e2009-09-05 21:47:34 +00003981 MagickSizeType
3982 length,
3983 number_pixels;
3984
cristy3ed852e2009-09-05 21:47:34 +00003985 size_t
cristye076a6e2010-08-15 19:59:43 +00003986 columns,
cristy3ed852e2009-09-05 21:47:34 +00003987 packet_size;
3988
cristye7cc7cf2010-09-21 13:26:47 +00003989 assert(image != (const Image *) NULL);
3990 assert(image->signature == MagickSignature);
3991 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003992 if (image->debug != MagickFalse)
3993 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3994 if ((image->columns == 0) || (image->rows == 0))
3995 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3996 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003997 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003998 source_info=(*cache_info);
3999 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004000 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004001 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004002 cache_info->storage_class=image->storage_class;
4003 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004004 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004005 cache_info->rows=image->rows;
4006 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004007 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004008 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004009 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004010 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004011 if (image->ping != MagickFalse)
4012 {
cristy73724512010-04-12 14:43:14 +00004013 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004014 cache_info->pixels=(Quantum *) NULL;
4015 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004016 cache_info->length=0;
4017 return(MagickTrue);
4018 }
cristy3ed852e2009-09-05 21:47:34 +00004019 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004020 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004021 if (image->metacontent_extent != 0)
4022 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004023 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004024 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004025 if (cache_info->columns != columns)
4026 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4027 image->filename);
4028 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004029 if ((cache_info->type != UndefinedCache) &&
4030 (cache_info->columns <= source_info.columns) &&
4031 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004032 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004033 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4034 {
4035 /*
4036 Inline pixel cache clone optimization.
4037 */
4038 if ((cache_info->columns == source_info.columns) &&
4039 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004040 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004041 (cache_info->metacontent_extent == source_info.metacontent_extent))
4042 return(MagickTrue);
4043 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4044 }
cristy3ed852e2009-09-05 21:47:34 +00004045 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004046 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004047 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004048 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4049 {
4050 status=AcquireMagickResource(MemoryResource,cache_info->length);
4051 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4052 (cache_info->type == MemoryCache))
4053 {
cristyd43a46b2010-01-21 02:13:41 +00004054 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004055 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004056 cache_info->pixels=source_info.pixels;
4057 else
4058 {
4059 /*
4060 Create memory pixel cache.
4061 */
cristy4c08aed2011-07-01 19:47:50 +00004062 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004063 if (image->debug != MagickFalse)
4064 {
cristy97e7a572009-12-05 15:07:53 +00004065 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004066 format);
cristyb51dff52011-05-19 16:55:47 +00004067 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004068 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4069 cache_info->filename,cache_info->mapped != MagickFalse ?
4070 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004071 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004072 format);
cristy3ed852e2009-09-05 21:47:34 +00004073 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4074 message);
4075 }
cristy3ed852e2009-09-05 21:47:34 +00004076 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004077 cache_info->metacontent=(void *) NULL;
4078 if (cache_info->metacontent_extent != 0)
4079 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004080 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004081 if (source_info.storage_class != UndefinedClass)
4082 {
cristy4c08aed2011-07-01 19:47:50 +00004083 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004084 exception);
4085 RelinquishPixelCachePixels(&source_info);
4086 }
cristy4c08aed2011-07-01 19:47:50 +00004087 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004088 }
4089 }
4090 RelinquishMagickResource(MemoryResource,cache_info->length);
4091 }
4092 /*
4093 Create pixel cache on disk.
4094 */
4095 status=AcquireMagickResource(DiskResource,cache_info->length);
4096 if (status == MagickFalse)
4097 {
4098 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4099 "CacheResourcesExhausted","`%s'",image->filename);
4100 return(MagickFalse);
4101 }
4102 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4103 {
4104 RelinquishMagickResource(DiskResource,cache_info->length);
4105 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4106 image->filename);
4107 return(MagickFalse);
4108 }
4109 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4110 cache_info->length);
4111 if (status == MagickFalse)
4112 {
4113 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4114 image->filename);
4115 return(MagickFalse);
4116 }
cristyed231572011-07-14 02:18:59 +00004117 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004118 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004119 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004120 cache_info->type=DiskCache;
4121 else
4122 {
4123 status=AcquireMagickResource(MapResource,cache_info->length);
4124 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4125 (cache_info->type != MemoryCache))
4126 cache_info->type=DiskCache;
4127 else
4128 {
cristy4c08aed2011-07-01 19:47:50 +00004129 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004130 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004131 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004132 {
cristy3ed852e2009-09-05 21:47:34 +00004133 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004134 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004135 }
4136 else
4137 {
4138 /*
4139 Create file-backed memory-mapped pixel cache.
4140 */
cristy4c08aed2011-07-01 19:47:50 +00004141 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004142 (void) ClosePixelCacheOnDisk(cache_info);
4143 cache_info->type=MapCache;
4144 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004145 cache_info->metacontent=(void *) NULL;
4146 if (cache_info->metacontent_extent != 0)
4147 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004148 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004149 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004150 {
4151 status=ClonePixelCachePixels(cache_info,&source_info,
4152 exception);
4153 RelinquishPixelCachePixels(&source_info);
4154 }
4155 if (image->debug != MagickFalse)
4156 {
cristy97e7a572009-12-05 15:07:53 +00004157 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004158 format);
cristyb51dff52011-05-19 16:55:47 +00004159 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004160 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004161 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004162 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004163 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004164 format);
cristy3ed852e2009-09-05 21:47:34 +00004165 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4166 message);
4167 }
cristy4c08aed2011-07-01 19:47:50 +00004168 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004169 }
4170 }
4171 RelinquishMagickResource(MapResource,cache_info->length);
4172 }
cristy4c08aed2011-07-01 19:47:50 +00004173 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004174 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4175 {
4176 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4177 RelinquishPixelCachePixels(&source_info);
4178 }
4179 if (image->debug != MagickFalse)
4180 {
cristyb9080c92009-12-01 20:13:26 +00004181 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004182 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004183 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004184 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004185 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004186 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004187 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4188 }
cristy4c08aed2011-07-01 19:47:50 +00004189 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004190}
4191
4192/*
4193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4194% %
4195% %
4196% %
4197+ P e r s i s t P i x e l C a c h e %
4198% %
4199% %
4200% %
4201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4202%
4203% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4204% persistent pixel cache is one that resides on disk and is not destroyed
4205% when the program exits.
4206%
4207% The format of the PersistPixelCache() method is:
4208%
4209% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4210% const MagickBooleanType attach,MagickOffsetType *offset,
4211% ExceptionInfo *exception)
4212%
4213% A description of each parameter follows:
4214%
4215% o image: the image.
4216%
4217% o filename: the persistent pixel cache filename.
4218%
cristyf3a6a9d2010-11-07 21:02:56 +00004219% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004220%
cristy3ed852e2009-09-05 21:47:34 +00004221% o initialize: A value other than zero initializes the persistent pixel
4222% cache.
4223%
4224% o offset: the offset in the persistent cache to store pixels.
4225%
4226% o exception: return any errors or warnings in this structure.
4227%
4228*/
4229MagickExport MagickBooleanType PersistPixelCache(Image *image,
4230 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4231 ExceptionInfo *exception)
4232{
4233 CacheInfo
4234 *cache_info,
4235 *clone_info;
4236
4237 Image
4238 clone_image;
4239
cristy3ed852e2009-09-05 21:47:34 +00004240 MagickBooleanType
4241 status;
4242
cristye076a6e2010-08-15 19:59:43 +00004243 ssize_t
4244 page_size;
4245
cristy3ed852e2009-09-05 21:47:34 +00004246 assert(image != (Image *) NULL);
4247 assert(image->signature == MagickSignature);
4248 if (image->debug != MagickFalse)
4249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4250 assert(image->cache != (void *) NULL);
4251 assert(filename != (const char *) NULL);
4252 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004253 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004254 cache_info=(CacheInfo *) image->cache;
4255 assert(cache_info->signature == MagickSignature);
4256 if (attach != MagickFalse)
4257 {
4258 /*
cristy01b7eb02009-09-10 23:10:14 +00004259 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004260 */
4261 if (image->debug != MagickFalse)
4262 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004263 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004264 (void) CopyMagickString(cache_info->cache_filename,filename,
4265 MaxTextExtent);
4266 cache_info->type=DiskCache;
4267 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004268 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004269 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004270 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004271 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004272 }
cristy01b7eb02009-09-10 23:10:14 +00004273 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4274 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004275 {
cristyf84a1932010-01-03 18:00:18 +00004276 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004277 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004278 (cache_info->reference_count == 1))
4279 {
4280 int
4281 status;
4282
4283 /*
cristy01b7eb02009-09-10 23:10:14 +00004284 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004285 */
cristy320684d2011-09-23 14:55:47 +00004286 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004287 if (status == 0)
4288 {
4289 (void) CopyMagickString(cache_info->cache_filename,filename,
4290 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004291 *offset+=cache_info->length+page_size-(cache_info->length %
4292 page_size);
cristyf84a1932010-01-03 18:00:18 +00004293 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004294 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004295 if (image->debug != MagickFalse)
4296 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4297 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004298 return(MagickTrue);
4299 }
4300 }
cristyf84a1932010-01-03 18:00:18 +00004301 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004302 }
4303 /*
cristy01b7eb02009-09-10 23:10:14 +00004304 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004305 */
4306 clone_image=(*image);
4307 clone_info=(CacheInfo *) clone_image.cache;
4308 image->cache=ClonePixelCache(cache_info);
4309 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4310 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4311 cache_info->type=DiskCache;
4312 cache_info->offset=(*offset);
4313 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004314 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004315 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004316 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004317 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004318 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4319 return(status);
4320}
4321
4322/*
4323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4324% %
4325% %
4326% %
4327+ Q u e u e A u t h e n t i c N e x u s %
4328% %
4329% %
4330% %
4331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4332%
4333% QueueAuthenticNexus() allocates an region to store image pixels as defined
4334% by the region rectangle and returns a pointer to the region. This region is
4335% subsequently transferred from the pixel cache with
4336% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4337% pixels are transferred, otherwise a NULL is returned.
4338%
4339% The format of the QueueAuthenticNexus() method is:
4340%
cristy4c08aed2011-07-01 19:47:50 +00004341% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004342% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004343% const MagickBooleanType clone,NexusInfo *nexus_info,
4344% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004345%
4346% A description of each parameter follows:
4347%
4348% o image: the image.
4349%
4350% o x,y,columns,rows: These values define the perimeter of a region of
4351% pixels.
4352%
4353% o nexus_info: the cache nexus to set.
4354%
cristy65dbf172011-10-06 17:32:04 +00004355% o clone: clone the pixel cache.
4356%
cristy3ed852e2009-09-05 21:47:34 +00004357% o exception: return any errors or warnings in this structure.
4358%
4359*/
cristya6577ff2011-09-02 19:54:26 +00004360MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004361 const ssize_t y,const size_t columns,const size_t rows,
4362 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004363{
4364 CacheInfo
4365 *cache_info;
4366
4367 MagickOffsetType
4368 offset;
4369
4370 MagickSizeType
4371 number_pixels;
4372
4373 RectangleInfo
4374 region;
4375
4376 /*
4377 Validate pixel cache geometry.
4378 */
cristye7cc7cf2010-09-21 13:26:47 +00004379 assert(image != (const Image *) NULL);
4380 assert(image->signature == MagickSignature);
4381 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004382 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004383 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004384 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004385 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004386 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4387 {
4388 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4389 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004390 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004391 }
cristybb503372010-05-27 20:51:26 +00004392 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4393 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004394 {
4395 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4396 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004397 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004398 }
4399 offset=(MagickOffsetType) y*cache_info->columns+x;
4400 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004401 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004402 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4403 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4404 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004405 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004406 /*
4407 Return pixel cache.
4408 */
4409 region.x=x;
4410 region.y=y;
4411 region.width=columns;
4412 region.height=rows;
4413 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4414}
4415
4416/*
4417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4418% %
4419% %
4420% %
4421+ 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 %
4422% %
4423% %
4424% %
4425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4426%
4427% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4428% defined by the region rectangle and returns a pointer to the region. This
4429% region is subsequently transferred from the pixel cache with
4430% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4431% pixels are transferred, otherwise a NULL is returned.
4432%
4433% The format of the QueueAuthenticPixelsCache() method is:
4434%
cristy4c08aed2011-07-01 19:47:50 +00004435% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004436% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004437% ExceptionInfo *exception)
4438%
4439% A description of each parameter follows:
4440%
4441% o image: the image.
4442%
4443% o x,y,columns,rows: These values define the perimeter of a region of
4444% pixels.
4445%
4446% o exception: return any errors or warnings in this structure.
4447%
4448*/
cristy4c08aed2011-07-01 19:47:50 +00004449static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004450 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004451 ExceptionInfo *exception)
4452{
4453 CacheInfo
4454 *cache_info;
4455
cristy5c9e6f22010-09-17 17:31:01 +00004456 const int
4457 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004458
cristy4c08aed2011-07-01 19:47:50 +00004459 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004460 *q;
cristy4c08aed2011-07-01 19:47:50 +00004461
cristye7cc7cf2010-09-21 13:26:47 +00004462 assert(image != (const Image *) NULL);
4463 assert(image->signature == MagickSignature);
4464 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004465 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004466 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004467 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004468 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4469 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004470 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004471}
4472
4473/*
4474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4475% %
4476% %
4477% %
4478% Q u e u e A u t h e n t i c P i x e l s %
4479% %
4480% %
4481% %
4482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4483%
4484% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004485% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004486% region is returned, otherwise NULL is returned. The returned pointer may
4487% point to a temporary working buffer for the pixels or it may point to the
4488% final location of the pixels in memory.
4489%
4490% Write-only access means that any existing pixel values corresponding to
4491% the region are ignored. This is useful if the initial image is being
4492% created from scratch, or if the existing pixel values are to be
4493% completely replaced without need to refer to their pre-existing values.
4494% The application is free to read and write the pixel buffer returned by
4495% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4496% initialize the pixel array values. Initializing pixel array values is the
4497% application's responsibility.
4498%
4499% Performance is maximized if the selected region is part of one row, or
4500% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004501% pixels in-place (without a copy) if the image is in memory, or in a
4502% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004503% by the user.
4504%
4505% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004506% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4507% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4508% obtain the meta-content (of type void) corresponding to the region.
4509% Once the Quantum (and/or Quantum) array has been updated, the
4510% changes must be saved back to the underlying image using
4511% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004512%
4513% The format of the QueueAuthenticPixels() method is:
4514%
cristy4c08aed2011-07-01 19:47:50 +00004515% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004516% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004517% ExceptionInfo *exception)
4518%
4519% A description of each parameter follows:
4520%
4521% o image: the image.
4522%
4523% o x,y,columns,rows: These values define the perimeter of a region of
4524% pixels.
4525%
4526% o exception: return any errors or warnings in this structure.
4527%
4528*/
cristy4c08aed2011-07-01 19:47:50 +00004529MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004530 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004531 ExceptionInfo *exception)
4532{
4533 CacheInfo
4534 *cache_info;
4535
cristy2036f5c2010-09-19 21:18:17 +00004536 const int
4537 id = GetOpenMPThreadId();
4538
cristy4c08aed2011-07-01 19:47:50 +00004539 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004540 *q;
cristy4c08aed2011-07-01 19:47:50 +00004541
cristy3ed852e2009-09-05 21:47:34 +00004542 assert(image != (Image *) NULL);
4543 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004544 assert(image->cache != (Cache) NULL);
4545 cache_info=(CacheInfo *) image->cache;
4546 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004547 if (cache_info->methods.queue_authentic_pixels_handler !=
4548 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004549 {
cristyacd2ed22011-08-30 01:44:23 +00004550 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004551 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004552 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004553 }
cristy2036f5c2010-09-19 21:18:17 +00004554 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004555 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4556 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004557 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004558}
4559
4560/*
4561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4562% %
4563% %
4564% %
cristy4c08aed2011-07-01 19:47:50 +00004565+ 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 +00004566% %
4567% %
4568% %
4569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4570%
cristy4c08aed2011-07-01 19:47:50 +00004571% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004572% the pixel cache.
4573%
cristy4c08aed2011-07-01 19:47:50 +00004574% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004575%
cristy4c08aed2011-07-01 19:47:50 +00004576% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004577% NexusInfo *nexus_info,ExceptionInfo *exception)
4578%
4579% A description of each parameter follows:
4580%
4581% o cache_info: the pixel cache.
4582%
cristy4c08aed2011-07-01 19:47:50 +00004583% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004584%
4585% o exception: return any errors or warnings in this structure.
4586%
4587*/
cristy4c08aed2011-07-01 19:47:50 +00004588static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004589 NexusInfo *nexus_info,ExceptionInfo *exception)
4590{
4591 MagickOffsetType
4592 count,
4593 offset;
4594
4595 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004596 extent,
4597 length;
cristy3ed852e2009-09-05 21:47:34 +00004598
cristybb503372010-05-27 20:51:26 +00004599 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004600 y;
4601
cristy4c08aed2011-07-01 19:47:50 +00004602 register unsigned char
4603 *restrict q;
4604
cristybb503372010-05-27 20:51:26 +00004605 size_t
cristy3ed852e2009-09-05 21:47:34 +00004606 rows;
4607
cristy4c08aed2011-07-01 19:47:50 +00004608 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004609 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004610 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004611 return(MagickTrue);
4612 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4613 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004614 length=(MagickSizeType) nexus_info->region.width*
4615 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004616 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004617 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004618 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004619 switch (cache_info->type)
4620 {
4621 case MemoryCache:
4622 case MapCache:
4623 {
cristy4c08aed2011-07-01 19:47:50 +00004624 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004625 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004626
4627 /*
cristy4c08aed2011-07-01 19:47:50 +00004628 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004629 */
cristydd341db2010-03-04 19:06:38 +00004630 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004631 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004632 {
cristy48078b12010-09-23 17:11:01 +00004633 length=extent;
cristydd341db2010-03-04 19:06:38 +00004634 rows=1UL;
4635 }
cristy4c08aed2011-07-01 19:47:50 +00004636 p=(unsigned char *) cache_info->metacontent+offset*
4637 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004638 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004639 {
cristy8f036fe2010-09-18 02:02:00 +00004640 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004641 p+=cache_info->metacontent_extent*cache_info->columns;
4642 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004643 }
4644 break;
4645 }
4646 case DiskCache:
4647 {
4648 /*
cristy4c08aed2011-07-01 19:47:50 +00004649 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004650 */
4651 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4652 {
4653 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4654 cache_info->cache_filename);
4655 return(MagickFalse);
4656 }
cristydd341db2010-03-04 19:06:38 +00004657 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004658 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004659 {
cristy48078b12010-09-23 17:11:01 +00004660 length=extent;
cristydd341db2010-03-04 19:06:38 +00004661 rows=1UL;
4662 }
cristy48078b12010-09-23 17:11:01 +00004663 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004664 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004665 {
cristy48078b12010-09-23 17:11:01 +00004666 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004667 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004668 cache_info->metacontent_extent,length,(unsigned char *) q);
4669 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004670 break;
4671 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004672 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004673 }
cristybb503372010-05-27 20:51:26 +00004674 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004675 {
4676 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4677 cache_info->cache_filename);
4678 return(MagickFalse);
4679 }
4680 break;
4681 }
4682 default:
4683 break;
4684 }
4685 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004686 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004687 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004688 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004689 nexus_info->region.width,(double) nexus_info->region.height,(double)
4690 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004691 return(MagickTrue);
4692}
4693
4694/*
4695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4696% %
4697% %
4698% %
4699+ R e a d P i x e l C a c h e P i x e l s %
4700% %
4701% %
4702% %
4703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4704%
4705% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4706% cache.
4707%
4708% The format of the ReadPixelCachePixels() method is:
4709%
4710% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4711% NexusInfo *nexus_info,ExceptionInfo *exception)
4712%
4713% A description of each parameter follows:
4714%
4715% o cache_info: the pixel cache.
4716%
4717% o nexus_info: the cache nexus to read the pixels.
4718%
4719% o exception: return any errors or warnings in this structure.
4720%
4721*/
4722static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4723 NexusInfo *nexus_info,ExceptionInfo *exception)
4724{
4725 MagickOffsetType
4726 count,
4727 offset;
4728
4729 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004730 extent,
4731 length;
cristy3ed852e2009-09-05 21:47:34 +00004732
cristy4c08aed2011-07-01 19:47:50 +00004733 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004734 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004735
cristye076a6e2010-08-15 19:59:43 +00004736 register ssize_t
4737 y;
4738
cristybb503372010-05-27 20:51:26 +00004739 size_t
cristy3ed852e2009-09-05 21:47:34 +00004740 rows;
4741
cristy4c08aed2011-07-01 19:47:50 +00004742 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004743 return(MagickTrue);
4744 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4745 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004746 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004747 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004748 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004749 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004750 q=nexus_info->pixels;
4751 switch (cache_info->type)
4752 {
4753 case MemoryCache:
4754 case MapCache:
4755 {
cristy4c08aed2011-07-01 19:47:50 +00004756 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004757 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004758
4759 /*
4760 Read pixels from memory.
4761 */
cristydd341db2010-03-04 19:06:38 +00004762 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004763 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004764 {
cristy48078b12010-09-23 17:11:01 +00004765 length=extent;
cristydd341db2010-03-04 19:06:38 +00004766 rows=1UL;
4767 }
cristyed231572011-07-14 02:18:59 +00004768 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004769 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004770 {
cristy8f036fe2010-09-18 02:02:00 +00004771 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004772 p+=cache_info->number_channels*cache_info->columns;
4773 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004774 }
4775 break;
4776 }
4777 case DiskCache:
4778 {
4779 /*
4780 Read pixels from disk.
4781 */
4782 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4783 {
4784 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4785 cache_info->cache_filename);
4786 return(MagickFalse);
4787 }
cristydd341db2010-03-04 19:06:38 +00004788 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004789 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004790 {
cristy48078b12010-09-23 17:11:01 +00004791 length=extent;
cristydd341db2010-03-04 19:06:38 +00004792 rows=1UL;
4793 }
cristybb503372010-05-27 20:51:26 +00004794 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004795 {
4796 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004797 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004798 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004799 break;
4800 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004801 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004802 }
cristybb503372010-05-27 20:51:26 +00004803 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004804 {
4805 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4806 cache_info->cache_filename);
4807 return(MagickFalse);
4808 }
4809 break;
4810 }
4811 default:
4812 break;
4813 }
4814 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004815 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004816 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004817 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004818 nexus_info->region.width,(double) nexus_info->region.height,(double)
4819 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004820 return(MagickTrue);
4821}
4822
4823/*
4824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4825% %
4826% %
4827% %
4828+ R e f e r e n c e P i x e l C a c h e %
4829% %
4830% %
4831% %
4832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4833%
4834% ReferencePixelCache() increments the reference count associated with the
4835% pixel cache returning a pointer to the cache.
4836%
4837% The format of the ReferencePixelCache method is:
4838%
4839% Cache ReferencePixelCache(Cache cache_info)
4840%
4841% A description of each parameter follows:
4842%
4843% o cache_info: the pixel cache.
4844%
4845*/
cristya6577ff2011-09-02 19:54:26 +00004846MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004847{
4848 CacheInfo
4849 *cache_info;
4850
4851 assert(cache != (Cache *) NULL);
4852 cache_info=(CacheInfo *) cache;
4853 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004854 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004855 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004856 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004857 return(cache_info);
4858}
4859
4860/*
4861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4862% %
4863% %
4864% %
4865+ S e t P i x e l C a c h e M e t h o d s %
4866% %
4867% %
4868% %
4869%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870%
4871% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4872%
4873% The format of the SetPixelCacheMethods() method is:
4874%
4875% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4876%
4877% A description of each parameter follows:
4878%
4879% o cache: the pixel cache.
4880%
4881% o cache_methods: Specifies a pointer to a CacheMethods structure.
4882%
4883*/
cristya6577ff2011-09-02 19:54:26 +00004884MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004885{
4886 CacheInfo
4887 *cache_info;
4888
4889 GetOneAuthenticPixelFromHandler
4890 get_one_authentic_pixel_from_handler;
4891
4892 GetOneVirtualPixelFromHandler
4893 get_one_virtual_pixel_from_handler;
4894
4895 /*
4896 Set cache pixel methods.
4897 */
4898 assert(cache != (Cache) NULL);
4899 assert(cache_methods != (CacheMethods *) NULL);
4900 cache_info=(CacheInfo *) cache;
4901 assert(cache_info->signature == MagickSignature);
4902 if (cache_info->debug != MagickFalse)
4903 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4904 cache_info->filename);
4905 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4906 cache_info->methods.get_virtual_pixel_handler=
4907 cache_methods->get_virtual_pixel_handler;
4908 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4909 cache_info->methods.destroy_pixel_handler=
4910 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004911 if (cache_methods->get_virtual_metacontent_from_handler !=
4912 (GetVirtualMetacontentFromHandler) NULL)
4913 cache_info->methods.get_virtual_metacontent_from_handler=
4914 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004915 if (cache_methods->get_authentic_pixels_handler !=
4916 (GetAuthenticPixelsHandler) NULL)
4917 cache_info->methods.get_authentic_pixels_handler=
4918 cache_methods->get_authentic_pixels_handler;
4919 if (cache_methods->queue_authentic_pixels_handler !=
4920 (QueueAuthenticPixelsHandler) NULL)
4921 cache_info->methods.queue_authentic_pixels_handler=
4922 cache_methods->queue_authentic_pixels_handler;
4923 if (cache_methods->sync_authentic_pixels_handler !=
4924 (SyncAuthenticPixelsHandler) NULL)
4925 cache_info->methods.sync_authentic_pixels_handler=
4926 cache_methods->sync_authentic_pixels_handler;
4927 if (cache_methods->get_authentic_pixels_from_handler !=
4928 (GetAuthenticPixelsFromHandler) NULL)
4929 cache_info->methods.get_authentic_pixels_from_handler=
4930 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004931 if (cache_methods->get_authentic_metacontent_from_handler !=
4932 (GetAuthenticMetacontentFromHandler) NULL)
4933 cache_info->methods.get_authentic_metacontent_from_handler=
4934 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004935 get_one_virtual_pixel_from_handler=
4936 cache_info->methods.get_one_virtual_pixel_from_handler;
4937 if (get_one_virtual_pixel_from_handler !=
4938 (GetOneVirtualPixelFromHandler) NULL)
4939 cache_info->methods.get_one_virtual_pixel_from_handler=
4940 cache_methods->get_one_virtual_pixel_from_handler;
4941 get_one_authentic_pixel_from_handler=
4942 cache_methods->get_one_authentic_pixel_from_handler;
4943 if (get_one_authentic_pixel_from_handler !=
4944 (GetOneAuthenticPixelFromHandler) NULL)
4945 cache_info->methods.get_one_authentic_pixel_from_handler=
4946 cache_methods->get_one_authentic_pixel_from_handler;
4947}
4948
4949/*
4950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4951% %
4952% %
4953% %
4954+ S e t P i x e l C a c h e N e x u s P i x e l s %
4955% %
4956% %
4957% %
4958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4959%
4960% SetPixelCacheNexusPixels() defines the region of the cache for the
4961% specified cache nexus.
4962%
4963% The format of the SetPixelCacheNexusPixels() method is:
4964%
cristy4c08aed2011-07-01 19:47:50 +00004965% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004966% const RectangleInfo *region,NexusInfo *nexus_info,
4967% ExceptionInfo *exception)
4968%
4969% A description of each parameter follows:
4970%
4971% o image: the image.
4972%
4973% o region: A pointer to the RectangleInfo structure that defines the
4974% region of this particular cache nexus.
4975%
4976% o nexus_info: the cache nexus to set.
4977%
4978% o exception: return any errors or warnings in this structure.
4979%
4980*/
cristyabd6e372010-09-15 19:11:26 +00004981
4982static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4983 NexusInfo *nexus_info,ExceptionInfo *exception)
4984{
4985 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4986 return(MagickFalse);
4987 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00004988 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004989 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004990 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004991 {
4992 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004993 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004994 nexus_info->length);
4995 }
cristy4c08aed2011-07-01 19:47:50 +00004996 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004997 {
4998 (void) ThrowMagickException(exception,GetMagickModule(),
4999 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5000 cache_info->filename);
5001 return(MagickFalse);
5002 }
5003 return(MagickTrue);
5004}
5005
cristy4c08aed2011-07-01 19:47:50 +00005006static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005007 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5008{
5009 CacheInfo
5010 *cache_info;
5011
5012 MagickBooleanType
5013 status;
5014
cristy3ed852e2009-09-05 21:47:34 +00005015 MagickSizeType
5016 length,
5017 number_pixels;
5018
cristy3ed852e2009-09-05 21:47:34 +00005019 cache_info=(CacheInfo *) image->cache;
5020 assert(cache_info->signature == MagickSignature);
5021 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005022 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005023 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005024 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5025 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005026 {
cristybb503372010-05-27 20:51:26 +00005027 ssize_t
cristybad067a2010-02-15 17:20:55 +00005028 x,
5029 y;
cristy3ed852e2009-09-05 21:47:34 +00005030
cristyeaedf062010-05-29 22:36:02 +00005031 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5032 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005033 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5034 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005035 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005036 ((nexus_info->region.width == cache_info->columns) ||
5037 ((nexus_info->region.width % cache_info->columns) == 0)))))
5038 {
5039 MagickOffsetType
5040 offset;
5041
5042 /*
5043 Pixels are accessed directly from memory.
5044 */
5045 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5046 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005047 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005048 offset;
5049 nexus_info->metacontent=(void *) NULL;
5050 if (cache_info->metacontent_extent != 0)
5051 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5052 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005053 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005054 }
5055 }
5056 /*
5057 Pixels are stored in a cache region until they are synced to the cache.
5058 */
5059 number_pixels=(MagickSizeType) nexus_info->region.width*
5060 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005061 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005062 if (cache_info->metacontent_extent != 0)
5063 length+=number_pixels*cache_info->metacontent_extent;
5064 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005065 {
5066 nexus_info->length=length;
5067 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5068 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005069 {
5070 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005071 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005072 }
cristy3ed852e2009-09-05 21:47:34 +00005073 }
5074 else
5075 if (nexus_info->length != length)
5076 {
5077 RelinquishCacheNexusPixels(nexus_info);
5078 nexus_info->length=length;
5079 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5080 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005081 {
5082 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005083 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005084 }
cristy3ed852e2009-09-05 21:47:34 +00005085 }
5086 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005087 nexus_info->metacontent=(void *) NULL;
5088 if (cache_info->metacontent_extent != 0)
5089 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005090 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005091 return(nexus_info->pixels);
5092}
5093
5094/*
5095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5096% %
5097% %
5098% %
5099% 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 %
5100% %
5101% %
5102% %
5103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5104%
5105% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5106% pixel cache and returns the previous setting. A virtual pixel is any pixel
5107% access that is outside the boundaries of the image cache.
5108%
5109% The format of the SetPixelCacheVirtualMethod() method is:
5110%
5111% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5112% const VirtualPixelMethod virtual_pixel_method)
5113%
5114% A description of each parameter follows:
5115%
5116% o image: the image.
5117%
5118% o virtual_pixel_method: choose the type of virtual pixel.
5119%
5120*/
cristyd1dd6e42011-09-04 01:46:08 +00005121MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005122 const VirtualPixelMethod virtual_pixel_method)
5123{
5124 CacheInfo
5125 *cache_info;
5126
5127 VirtualPixelMethod
5128 method;
5129
5130 assert(image != (Image *) NULL);
5131 assert(image->signature == MagickSignature);
5132 if (image->debug != MagickFalse)
5133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5134 assert(image->cache != (Cache) NULL);
5135 cache_info=(CacheInfo *) image->cache;
5136 assert(cache_info->signature == MagickSignature);
5137 method=cache_info->virtual_pixel_method;
5138 cache_info->virtual_pixel_method=virtual_pixel_method;
5139 return(method);
5140}
5141
5142/*
5143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5144% %
5145% %
5146% %
5147+ 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 %
5148% %
5149% %
5150% %
5151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152%
5153% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5154% in-memory or disk cache. The method returns MagickTrue if the pixel region
5155% is synced, otherwise MagickFalse.
5156%
5157% The format of the SyncAuthenticPixelCacheNexus() method is:
5158%
5159% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5160% NexusInfo *nexus_info,ExceptionInfo *exception)
5161%
5162% A description of each parameter follows:
5163%
5164% o image: the image.
5165%
5166% o nexus_info: the cache nexus to sync.
5167%
5168% o exception: return any errors or warnings in this structure.
5169%
5170*/
cristya6577ff2011-09-02 19:54:26 +00005171MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005172 NexusInfo *nexus_info,ExceptionInfo *exception)
5173{
5174 CacheInfo
5175 *cache_info;
5176
5177 MagickBooleanType
5178 status;
5179
5180 /*
5181 Transfer pixels to the cache.
5182 */
5183 assert(image != (Image *) NULL);
5184 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005185 if (image->cache == (Cache) NULL)
5186 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5187 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005188 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005189 if (cache_info->type == UndefinedCache)
5190 return(MagickFalse);
5191 if ((image->clip_mask != (Image *) NULL) &&
5192 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5193 return(MagickFalse);
5194 if ((image->mask != (Image *) NULL) &&
5195 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5196 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005197 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005198 return(MagickTrue);
5199 assert(cache_info->signature == MagickSignature);
5200 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005201 if ((cache_info->metacontent_extent != 0) &&
5202 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005203 return(MagickFalse);
5204 return(status);
5205}
5206
5207/*
5208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5209% %
5210% %
5211% %
5212+ S y n c A u t h e n t i c P i x e l C a c h e %
5213% %
5214% %
5215% %
5216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217%
5218% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5219% or disk cache. The method returns MagickTrue if the pixel region is synced,
5220% otherwise MagickFalse.
5221%
5222% The format of the SyncAuthenticPixelsCache() method is:
5223%
5224% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5225% ExceptionInfo *exception)
5226%
5227% A description of each parameter follows:
5228%
5229% o image: the image.
5230%
5231% o exception: return any errors or warnings in this structure.
5232%
5233*/
5234static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5235 ExceptionInfo *exception)
5236{
5237 CacheInfo
5238 *cache_info;
5239
cristy5c9e6f22010-09-17 17:31:01 +00005240 const int
5241 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005242
cristy4c08aed2011-07-01 19:47:50 +00005243 MagickBooleanType
5244 status;
5245
cristye7cc7cf2010-09-21 13:26:47 +00005246 assert(image != (Image *) NULL);
5247 assert(image->signature == MagickSignature);
5248 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005249 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005250 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005251 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005252 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5253 exception);
5254 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005255}
5256
5257/*
5258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5259% %
5260% %
5261% %
5262% S y n c A u t h e n t i c P i x e l s %
5263% %
5264% %
5265% %
5266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5267%
5268% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5269% The method returns MagickTrue if the pixel region is flushed, otherwise
5270% MagickFalse.
5271%
5272% The format of the SyncAuthenticPixels() method is:
5273%
5274% MagickBooleanType SyncAuthenticPixels(Image *image,
5275% ExceptionInfo *exception)
5276%
5277% A description of each parameter follows:
5278%
5279% o image: the image.
5280%
5281% o exception: return any errors or warnings in this structure.
5282%
5283*/
5284MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5285 ExceptionInfo *exception)
5286{
5287 CacheInfo
5288 *cache_info;
5289
cristy2036f5c2010-09-19 21:18:17 +00005290 const int
5291 id = GetOpenMPThreadId();
5292
cristy4c08aed2011-07-01 19:47:50 +00005293 MagickBooleanType
5294 status;
5295
cristy3ed852e2009-09-05 21:47:34 +00005296 assert(image != (Image *) NULL);
5297 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005298 assert(image->cache != (Cache) NULL);
5299 cache_info=(CacheInfo *) image->cache;
5300 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005301 if (cache_info->methods.sync_authentic_pixels_handler !=
5302 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005303 {
5304 status=cache_info->methods.sync_authentic_pixels_handler(image,
5305 exception);
5306 return(status);
5307 }
cristy2036f5c2010-09-19 21:18:17 +00005308 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005309 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5310 exception);
5311 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005312}
5313
5314/*
5315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5316% %
5317% %
5318% %
cristyd1dd6e42011-09-04 01:46:08 +00005319+ 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 +00005320% %
5321% %
5322% %
5323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5324%
5325% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5326% The method returns MagickTrue if the pixel region is flushed, otherwise
5327% MagickFalse.
5328%
5329% The format of the SyncImagePixelCache() method is:
5330%
5331% MagickBooleanType SyncImagePixelCache(Image *image,
5332% ExceptionInfo *exception)
5333%
5334% A description of each parameter follows:
5335%
5336% o image: the image.
5337%
5338% o exception: return any errors or warnings in this structure.
5339%
5340*/
cristyd1dd6e42011-09-04 01:46:08 +00005341MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005342 ExceptionInfo *exception)
5343{
5344 CacheInfo
5345 *cache_info;
5346
5347 assert(image != (Image *) NULL);
5348 assert(exception != (ExceptionInfo *) NULL);
5349 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5350 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5351}
5352
5353/*
5354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5355% %
5356% %
5357% %
cristy4c08aed2011-07-01 19:47:50 +00005358+ 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 +00005359% %
5360% %
5361% %
5362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5363%
cristy4c08aed2011-07-01 19:47:50 +00005364% WritePixelCacheMetacontent() writes the meta-content to the specified region
5365% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005366%
cristy4c08aed2011-07-01 19:47:50 +00005367% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005368%
cristy4c08aed2011-07-01 19:47:50 +00005369% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005370% NexusInfo *nexus_info,ExceptionInfo *exception)
5371%
5372% A description of each parameter follows:
5373%
5374% o cache_info: the pixel cache.
5375%
cristy4c08aed2011-07-01 19:47:50 +00005376% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005377%
5378% o exception: return any errors or warnings in this structure.
5379%
5380*/
cristy4c08aed2011-07-01 19:47:50 +00005381static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005382 NexusInfo *nexus_info,ExceptionInfo *exception)
5383{
5384 MagickOffsetType
5385 count,
5386 offset;
5387
5388 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005389 extent,
5390 length;
cristy3ed852e2009-09-05 21:47:34 +00005391
cristy4c08aed2011-07-01 19:47:50 +00005392 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005393 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005394
cristybb503372010-05-27 20:51:26 +00005395 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005396 y;
5397
cristybb503372010-05-27 20:51:26 +00005398 size_t
cristy3ed852e2009-09-05 21:47:34 +00005399 rows;
5400
cristy4c08aed2011-07-01 19:47:50 +00005401 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005402 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005403 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005404 return(MagickTrue);
5405 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5406 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005407 length=(MagickSizeType) nexus_info->region.width*
5408 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005409 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005410 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005411 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005412 switch (cache_info->type)
5413 {
5414 case MemoryCache:
5415 case MapCache:
5416 {
cristy4c08aed2011-07-01 19:47:50 +00005417 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005418 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005419
5420 /*
cristy4c08aed2011-07-01 19:47:50 +00005421 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005422 */
cristydd341db2010-03-04 19:06:38 +00005423 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005424 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005425 {
cristy48078b12010-09-23 17:11:01 +00005426 length=extent;
cristydd341db2010-03-04 19:06:38 +00005427 rows=1UL;
5428 }
cristy4c08aed2011-07-01 19:47:50 +00005429 q=(unsigned char *) cache_info->metacontent+offset*
5430 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005431 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005432 {
cristy8f036fe2010-09-18 02:02:00 +00005433 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005434 p+=nexus_info->region.width*cache_info->metacontent_extent;
5435 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005436 }
5437 break;
5438 }
5439 case DiskCache:
5440 {
5441 /*
cristy4c08aed2011-07-01 19:47:50 +00005442 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005443 */
5444 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5445 {
5446 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5447 cache_info->cache_filename);
5448 return(MagickFalse);
5449 }
cristydd341db2010-03-04 19:06:38 +00005450 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005451 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005452 {
cristy48078b12010-09-23 17:11:01 +00005453 length=extent;
cristydd341db2010-03-04 19:06:38 +00005454 rows=1UL;
5455 }
cristy48078b12010-09-23 17:11:01 +00005456 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005457 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005458 {
cristy48078b12010-09-23 17:11:01 +00005459 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005460 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005461 cache_info->metacontent_extent,length,(const unsigned char *) p);
5462 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005463 break;
cristy4c08aed2011-07-01 19:47:50 +00005464 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005465 offset+=cache_info->columns;
5466 }
cristybb503372010-05-27 20:51:26 +00005467 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005468 {
5469 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5470 cache_info->cache_filename);
5471 return(MagickFalse);
5472 }
5473 break;
5474 }
5475 default:
5476 break;
5477 }
5478 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005479 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005480 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005481 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005482 nexus_info->region.width,(double) nexus_info->region.height,(double)
5483 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005484 return(MagickTrue);
5485}
5486
5487/*
5488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5489% %
5490% %
5491% %
5492+ W r i t e C a c h e P i x e l s %
5493% %
5494% %
5495% %
5496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5497%
5498% WritePixelCachePixels() writes image pixels to the specified region of the
5499% pixel cache.
5500%
5501% The format of the WritePixelCachePixels() method is:
5502%
5503% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5504% NexusInfo *nexus_info,ExceptionInfo *exception)
5505%
5506% A description of each parameter follows:
5507%
5508% o cache_info: the pixel cache.
5509%
5510% o nexus_info: the cache nexus to write the pixels.
5511%
5512% o exception: return any errors or warnings in this structure.
5513%
5514*/
5515static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5516 NexusInfo *nexus_info,ExceptionInfo *exception)
5517{
5518 MagickOffsetType
5519 count,
5520 offset;
5521
5522 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005523 extent,
5524 length;
cristy3ed852e2009-09-05 21:47:34 +00005525
cristy4c08aed2011-07-01 19:47:50 +00005526 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005527 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005528
cristybb503372010-05-27 20:51:26 +00005529 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005530 y;
5531
cristybb503372010-05-27 20:51:26 +00005532 size_t
cristy3ed852e2009-09-05 21:47:34 +00005533 rows;
5534
cristy4c08aed2011-07-01 19:47:50 +00005535 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005536 return(MagickTrue);
5537 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5538 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005539 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005540 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005541 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005542 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005543 p=nexus_info->pixels;
5544 switch (cache_info->type)
5545 {
5546 case MemoryCache:
5547 case MapCache:
5548 {
cristy4c08aed2011-07-01 19:47:50 +00005549 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005550 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005551
5552 /*
5553 Write pixels to memory.
5554 */
cristydd341db2010-03-04 19:06:38 +00005555 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005556 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005557 {
cristy48078b12010-09-23 17:11:01 +00005558 length=extent;
cristydd341db2010-03-04 19:06:38 +00005559 rows=1UL;
5560 }
cristyed231572011-07-14 02:18:59 +00005561 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005562 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005563 {
cristy8f036fe2010-09-18 02:02:00 +00005564 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005565 p+=nexus_info->region.width*cache_info->number_channels;
5566 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005567 }
5568 break;
5569 }
5570 case DiskCache:
5571 {
5572 /*
5573 Write pixels to disk.
5574 */
5575 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5576 {
5577 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5578 cache_info->cache_filename);
5579 return(MagickFalse);
5580 }
cristydd341db2010-03-04 19:06:38 +00005581 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005582 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005583 {
cristy48078b12010-09-23 17:11:01 +00005584 length=extent;
cristydd341db2010-03-04 19:06:38 +00005585 rows=1UL;
5586 }
cristybb503372010-05-27 20:51:26 +00005587 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005588 {
5589 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005590 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005591 p);
5592 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005593 break;
cristyed231572011-07-14 02:18:59 +00005594 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005595 offset+=cache_info->columns;
5596 }
cristybb503372010-05-27 20:51:26 +00005597 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005598 {
5599 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5600 cache_info->cache_filename);
5601 return(MagickFalse);
5602 }
5603 break;
5604 }
5605 default:
5606 break;
5607 }
5608 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005609 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005610 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005611 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005612 nexus_info->region.width,(double) nexus_info->region.height,(double)
5613 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005614 return(MagickTrue);
5615}