blob: 2034e3dee6754e7a1262654cb6fb39c44ef97b19 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78
79/*
cristy3ed852e2009-09-05 21:47:34 +000080 Typedef declarations.
81*/
82typedef struct _MagickModulo
83{
cristybb503372010-05-27 20:51:26 +000084 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000085 quotient,
86 remainder;
87} MagickModulo;
88
89struct _NexusInfo
90{
91 MagickBooleanType
92 mapped;
93
94 RectangleInfo
95 region;
96
97 MagickSizeType
98 length;
99
cristy4c08aed2011-07-01 19:47:50 +0000100 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000101 *cache,
102 *pixels;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 void
105 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000106
cristybb503372010-05-27 20:51:26 +0000107 size_t
cristy3ed852e2009-09-05 21:47:34 +0000108 signature;
109};
110
111/*
112 Forward declarations.
113*/
114#if defined(__cplusplus) || defined(c_plusplus)
115extern "C" {
116#endif
117
cristy4c08aed2011-07-01 19:47:50 +0000118static const Quantum
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
cristy4c08aed2011-07-01 19:47:50 +0000123static const void
124 *GetVirtualMetacontentFromCache(const Image *);
125
cristy3ed852e2009-09-05 21:47:34 +0000126static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000128 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
137
cristy4c08aed2011-07-01 19:47:50 +0000138static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000144 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146#if defined(__cplusplus) || defined(c_plusplus)
147}
148#endif
149
150/*
151 Global declarations.
152*/
153static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
155
156static SemaphoreInfo
157 *cache_semaphore = (SemaphoreInfo *) NULL;
158
159static SplayTreeInfo
160 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167+ A c q u i r e P i x e l C a c h e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquirePixelCache() acquires a pixel cache.
174%
175% The format of the AcquirePixelCache() method is:
176%
cristybb503372010-05-27 20:51:26 +0000177% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178%
179% A description of each parameter follows:
180%
181% o number_threads: the number of nexus threads.
182%
183*/
cristya6577ff2011-09-02 19:54:26 +0000184MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000185{
186 CacheInfo
187 *cache_info;
188
cristya64b85d2011-09-14 01:02:31 +0000189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000194 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristya6577ff2011-09-02 19:54:26 +0000250MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristya64b85d2011-09-14 01:02:31 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
cristyd1dd6e42011-09-04 01:46:08 +0000301MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
cristy5ff4eaf2011-09-03 01:38:02 +0000339MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
cristy5ff4eaf2011-09-03 01:38:02 +0000363MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000387% mask. It returns MagickTrue if the pixel region is clipped, otherwise
388% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
cristy4c08aed2011-07-01 19:47:50 +0000417 register const Quantum
418 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristy4c08aed2011-07-01 19:47:50 +0000421 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristye076a6e2010-08-15 19:59:43 +0000424 register ssize_t
425 i;
426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
428 Apply clip mask.
429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000434 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000445 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000451 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy4c08aed2011-07-01 19:47:50 +0000453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000454 break;
cristy4c08aed2011-07-01 19:47:50 +0000455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000456 {
cristy4c08aed2011-07-01 19:47:50 +0000457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000463 }
cristyed231572011-07-14 02:18:59 +0000464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000467 }
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000470 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000471 return(MagickFalse);
472 return(MagickTrue);
473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
480+ C l o n e P i x e l C a c h e %
481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
486% ClonePixelCache() clones a pixel cache.
487%
488% The format of the ClonePixelCache() method is:
489%
490% Cache ClonePixelCache(const Cache cache)
491%
492% A description of each parameter follows:
493%
494% o cache: the pixel cache.
495%
496*/
cristya6577ff2011-09-02 19:54:26 +0000497MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000498{
499 CacheInfo
500 *clone_info;
501
502 const CacheInfo
503 *cache_info;
504
cristy9f027d12011-09-21 01:17:17 +0000505 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
516}
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520% %
521% %
522% %
cristy60c44a82009-10-07 00:58:49 +0000523+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000524% %
525% %
526% %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528% ClonePixelCachePixels() clones the source pixel cache to the destination
529% cache.
530%
531% The format of the ClonePixelCachePixels() method is:
532%
533% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534% CacheInfo *source_info,ExceptionInfo *exception)
535%
536% A description of each parameter follows:
537%
538% o cache_info: the pixel cache.
539%
540% o source_info: the source pixel cache.
541%
542% o exception: return any errors or warnings in this structure.
543%
544*/
545
546static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
547{
548 int
549 status;
550
cristy5ee247a2010-02-12 15:42:34 +0000551 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000552 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000553 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000554 {
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
558 }
cristyf84a1932010-01-03 18:00:18 +0000559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000560 return(status == -1 ? MagickFalse : MagickTrue);
561}
562
563static void LimitPixelCacheDescriptors(void)
564{
565 register CacheInfo
566 *p,
567 *q;
568
569 /*
570 Limit # of open file descriptors.
571 */
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
573 return;
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (cache_resources == (SplayTreeInfo *) NULL)
576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return;
579 }
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
583 {
584 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000585 break;
cristy3ed852e2009-09-05 21:47:34 +0000586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 }
588 for (q=p; p != (CacheInfo *) NULL; )
589 {
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000592 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
594 }
595 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000596 {
597 /*
598 Close least recently used cache.
599 */
600 (void) close(q->file);
601 q->file=(-1);
602 }
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604}
605
606static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
608{
609 if (x > y)
610 return(x);
611 return(y);
612}
613
614static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x < y)
618 return(x);
619 return(y);
620}
621
622static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
623 const MapMode mode)
624{
625 int
626 file;
627
628 /*
629 Open pixel cache on disk.
630 */
cristyf84a1932010-01-03 18:00:18 +0000631 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000632 if (cache_info->file != -1)
633 {
cristyf84a1932010-01-03 18:00:18 +0000634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 return(MagickTrue); /* cache already open */
636 }
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
640 else
641 switch (mode)
642 {
643 case ReadMode:
644 {
cristy18c6c272011-09-23 14:40:37 +0000645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 case WriteMode:
649 {
cristy18c6c272011-09-23 14:40:37 +0000650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000652 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case IOMode:
657 default:
658 {
cristy18c6c272011-09-23 14:40:37 +0000659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000660 O_EXCL,S_MODE);
661 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
664 }
665 }
666 if (file == -1)
667 {
cristyf84a1932010-01-03 18:00:18 +0000668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000669 return(MagickFalse);
670 }
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
673 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000674 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000675 return(MagickTrue);
676}
677
678static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
679 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000680 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000681{
682 register MagickOffsetType
683 i;
684
685 ssize_t
686 count;
687
cristy08a88202010-03-04 19:18:05 +0000688 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000689#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000690 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000691 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristyf84a1932010-01-03 18:00:18 +0000693 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 return((MagickOffsetType) -1);
695 }
696#endif
697 count=0;
698 for (i=0; i < (MagickOffsetType) length; i+=count)
699 {
700#if !defined(MAGICKCORE_HAVE_PREAD)
701 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX));
703#else
704 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000705 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000706#endif
707 if (count > 0)
708 continue;
709 count=0;
710 if (errno != EINTR)
711 {
712 i=(-1);
713 break;
714 }
715 }
716#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000717 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000718#endif
719 return(i);
720}
721
722static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
723 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000724 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000725{
726 register MagickOffsetType
727 i;
728
729 ssize_t
730 count;
731
cristy08a88202010-03-04 19:18:05 +0000732 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000733#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000734 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000735 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000736 {
cristyf84a1932010-01-03 18:00:18 +0000737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 return((MagickOffsetType) -1);
739 }
740#endif
741 count=0;
742 for (i=0; i < (MagickOffsetType) length; i+=count)
743 {
744#if !defined(MAGICKCORE_HAVE_PWRITE)
745 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX));
747#else
748 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000749 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000750#endif
751 if (count > 0)
752 continue;
753 count=0;
754 if (errno != EINTR)
755 {
756 i=(-1);
757 break;
758 }
759 }
760#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000761 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000762#endif
763 return(i);
764}
765
cristy4c08aed2011-07-01 19:47:50 +0000766static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000767 CacheInfo *cache_info,ExceptionInfo *exception)
768{
769 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000770 count;
cristy3ed852e2009-09-05 21:47:34 +0000771
cristy4c08aed2011-07-01 19:47:50 +0000772 register MagickOffsetType
773 i;
cristye076a6e2010-08-15 19:59:43 +0000774
cristybb503372010-05-27 20:51:26 +0000775 size_t
cristy4c08aed2011-07-01 19:47:50 +0000776 length;
cristy3ed852e2009-09-05 21:47:34 +0000777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
780
781 /*
782 Clone pixel cache (both caches on disk).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000786 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000787 sizeof(*blob));
788 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000789 {
cristy4c08aed2011-07-01 19:47:50 +0000790 (void) ThrowMagickException(exception,GetMagickModule(),
791 ResourceLimitError,"MemoryAllocationFailed","`%s'",
792 cache_info->filename);
793 return(MagickFalse);
794 }
cristy3dedf062011-07-02 14:07:40 +0000795 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000796 {
797 blob=(unsigned char *) RelinquishMagickMemory(blob);
798 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
799 cache_info->cache_filename);
800 return(MagickFalse);
801 }
cristy3dedf062011-07-02 14:07:40 +0000802 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000803 {
804 (void) ClosePixelCacheOnDisk(cache_info);
805 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000806 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
807 clone_info->cache_filename);
808 return(MagickFalse);
809 }
cristy4c08aed2011-07-01 19:47:50 +0000810 count=0;
811 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
814 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
815 blob);
816 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000817 {
cristy4c08aed2011-07-01 19:47:50 +0000818 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
819 cache_info->cache_filename);
820 break;
cristy3ed852e2009-09-05 21:47:34 +0000821 }
cristy4c08aed2011-07-01 19:47:50 +0000822 length=(size_t) count;
823 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
824 if ((MagickSizeType) count != length)
825 {
826 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
827 clone_info->cache_filename);
828 break;
829 }
830 }
831 (void) ClosePixelCacheOnDisk(clone_info);
832 (void) ClosePixelCacheOnDisk(cache_info);
833 blob=(unsigned char *) RelinquishMagickMemory(blob);
834 if (i < (MagickOffsetType) cache_info->length)
835 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000836 return(MagickTrue);
837}
838
cristy4c08aed2011-07-01 19:47:50 +0000839static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000840 CacheInfo *cache_info,ExceptionInfo *exception)
841{
842 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000843 count;
cristy3ed852e2009-09-05 21:47:34 +0000844
cristy4c08aed2011-07-01 19:47:50 +0000845 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000846 {
cristy3ed852e2009-09-05 21:47:34 +0000847 /*
cristy4c08aed2011-07-01 19:47:50 +0000848 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000849 */
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->debug != MagickFalse)
851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
852 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
853 cache_info->length);
854 return(MagickTrue);
855 }
856 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
857 {
858 /*
859 Clone pixel cache (one cache on disk, one in memory).
860 */
861 if (cache_info->debug != MagickFalse)
862 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
863 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy4c08aed2011-07-01 19:47:50 +0000865 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000866 cache_info->cache_filename);
867 return(MagickFalse);
868 }
cristy4c08aed2011-07-01 19:47:50 +0000869 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
870 cache_info->length,(unsigned char *) clone_info->pixels);
871 (void) ClosePixelCacheOnDisk(cache_info);
872 if ((MagickSizeType) count != cache_info->length)
873 {
874 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
875 cache_info->cache_filename);
876 return(MagickFalse);
877 }
878 return(MagickTrue);
879 }
880 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
881 {
882 /*
883 Clone pixel cache (one cache on disk, one in memory).
884 */
885 if (clone_info->debug != MagickFalse)
886 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
887 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
888 {
889 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
890 clone_info->cache_filename);
891 return(MagickFalse);
892 }
893 count=WritePixelCacheRegion(clone_info,clone_info->offset,
894 clone_info->length,(unsigned char *) cache_info->pixels);
895 (void) ClosePixelCacheOnDisk(clone_info);
896 if ((MagickSizeType) count != clone_info->length)
897 {
898 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
899 clone_info->cache_filename);
900 return(MagickFalse);
901 }
902 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000903 }
904 /*
cristy4c08aed2011-07-01 19:47:50 +0000905 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000906 */
cristy4c08aed2011-07-01 19:47:50 +0000907 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000908}
909
cristy4c08aed2011-07-01 19:47:50 +0000910static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000911 CacheInfo *cache_info,ExceptionInfo *exception)
912{
cristy4c08aed2011-07-01 19:47:50 +0000913 MagickBooleanType
914 status;
cristy3ed852e2009-09-05 21:47:34 +0000915
cristy4c08aed2011-07-01 19:47:50 +0000916 MagickOffsetType
917 cache_offset,
918 clone_offset,
919 count;
920
921 register ssize_t
922 x;
923
924 size_t
cristy3ed852e2009-09-05 21:47:34 +0000925 length;
926
cristy4c08aed2011-07-01 19:47:50 +0000927 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000928 y;
929
cristy4c08aed2011-07-01 19:47:50 +0000930 unsigned char
931 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000932
cristy4c08aed2011-07-01 19:47:50 +0000933 /*
934 Clone pixel cache (unoptimized).
935 */
cristy3ed852e2009-09-05 21:47:34 +0000936 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000937 {
cristy4c08aed2011-07-01 19:47:50 +0000938 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
939 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
940 else
941 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
942 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
943 else
944 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
946 else
947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
948 }
cristyed231572011-07-14 02:18:59 +0000949 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
950 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000951 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000952 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000953 if (blob == (unsigned char *) NULL)
954 {
955 (void) ThrowMagickException(exception,GetMagickModule(),
956 ResourceLimitError,"MemoryAllocationFailed","`%s'",
957 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000958 return(MagickFalse);
959 }
cristy4c08aed2011-07-01 19:47:50 +0000960 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
961 cache_offset=0;
962 clone_offset=0;
963 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000964 {
cristy4c08aed2011-07-01 19:47:50 +0000965 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
cristy4c08aed2011-07-01 19:47:50 +0000967 blob=(unsigned char *) RelinquishMagickMemory(blob);
968 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
cristy4c08aed2011-07-01 19:47:50 +0000972 cache_offset=cache_info->offset;
973 }
974 if (clone_info->type == DiskCache)
975 {
cristy3dedf062011-07-02 14:07:40 +0000976 if ((cache_info->type == DiskCache) &&
977 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
978 {
979 (void) ClosePixelCacheOnDisk(clone_info);
980 *clone_info->cache_filename='\0';
981 }
982 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000983 {
cristy4c08aed2011-07-01 19:47:50 +0000984 if (cache_info->type == DiskCache)
985 (void) ClosePixelCacheOnDisk(cache_info);
986 blob=(unsigned char *) RelinquishMagickMemory(blob);
987 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
988 clone_info->cache_filename);
989 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000990 }
cristy4c08aed2011-07-01 19:47:50 +0000991 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000992 }
993 /*
cristy4c08aed2011-07-01 19:47:50 +0000994 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000995 */
cristy4c08aed2011-07-01 19:47:50 +0000996 status=MagickTrue;
997 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
cristy4c08aed2011-07-01 19:47:50 +0000999 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001000 {
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{
cristy3dfccb22011-12-28 21:47:20 +00001194 PixelChannelMap
1195 *p,
1196 *q;
1197
cristy5a7fbfb2010-11-06 16:10:59 +00001198 if (cache_info->type == PingCache)
1199 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001200 p=cache_info->channel_map;
1201 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001202 if ((cache_info->columns == clone_info->columns) &&
1203 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001204 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001205 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001206 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1207 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3dfccb22011-12-28 21:47:20 +00001208 if (memcmp(p,q,cache_info->number_channels*sizeof(*p)) != 0)
1209 ;
cristy4c08aed2011-07-01 19:47:50 +00001210 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001211}
1212
1213/*
1214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215% %
1216% %
1217% %
1218+ C l o n e P i x e l C a c h e M e t h o d s %
1219% %
1220% %
1221% %
1222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1223%
1224% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1225% another.
1226%
1227% The format of the ClonePixelCacheMethods() method is:
1228%
1229% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1230%
1231% A description of each parameter follows:
1232%
1233% o clone: Specifies a pointer to a Cache structure.
1234%
1235% o cache: the pixel cache.
1236%
1237*/
cristya6577ff2011-09-02 19:54:26 +00001238MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001239{
1240 CacheInfo
1241 *cache_info,
1242 *source_info;
1243
1244 assert(clone != (Cache) NULL);
1245 source_info=(CacheInfo *) clone;
1246 assert(source_info->signature == MagickSignature);
1247 if (source_info->debug != MagickFalse)
1248 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1249 source_info->filename);
1250 assert(cache != (Cache) NULL);
1251 cache_info=(CacheInfo *) cache;
1252 assert(cache_info->signature == MagickSignature);
1253 source_info->methods=cache_info->methods;
1254}
1255
1256/*
1257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258% %
1259% %
1260% %
1261+ D e s t r o y I m a g e P i x e l C a c h e %
1262% %
1263% %
1264% %
1265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1266%
1267% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1268%
1269% The format of the DestroyImagePixelCache() method is:
1270%
1271% void DestroyImagePixelCache(Image *image)
1272%
1273% A description of each parameter follows:
1274%
1275% o image: the image.
1276%
1277*/
1278static void DestroyImagePixelCache(Image *image)
1279{
1280 assert(image != (Image *) NULL);
1281 assert(image->signature == MagickSignature);
1282 if (image->debug != MagickFalse)
1283 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1284 if (image->cache == (void *) NULL)
1285 return;
1286 image->cache=DestroyPixelCache(image->cache);
1287}
1288
1289/*
1290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1291% %
1292% %
1293% %
1294+ D e s t r o y I m a g e P i x e l s %
1295% %
1296% %
1297% %
1298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1299%
1300% DestroyImagePixels() deallocates memory associated with the pixel cache.
1301%
1302% The format of the DestroyImagePixels() method is:
1303%
1304% void DestroyImagePixels(Image *image)
1305%
1306% A description of each parameter follows:
1307%
1308% o image: the image.
1309%
1310*/
1311MagickExport void DestroyImagePixels(Image *image)
1312{
1313 CacheInfo
1314 *cache_info;
1315
1316 assert(image != (const Image *) NULL);
1317 assert(image->signature == MagickSignature);
1318 if (image->debug != MagickFalse)
1319 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1320 assert(image->cache != (Cache) NULL);
1321 cache_info=(CacheInfo *) image->cache;
1322 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001323 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1324 {
1325 cache_info->methods.destroy_pixel_handler(image);
1326 return;
1327 }
cristy2036f5c2010-09-19 21:18:17 +00001328 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001329}
1330
1331/*
1332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333% %
1334% %
1335% %
1336+ D e s t r o y P i x e l C a c h e %
1337% %
1338% %
1339% %
1340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341%
1342% DestroyPixelCache() deallocates memory associated with the pixel cache.
1343%
1344% The format of the DestroyPixelCache() method is:
1345%
1346% Cache DestroyPixelCache(Cache cache)
1347%
1348% A description of each parameter follows:
1349%
1350% o cache: the pixel cache.
1351%
1352*/
1353
1354static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1355{
1356 switch (cache_info->type)
1357 {
1358 case MemoryCache:
1359 {
1360 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001361 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001362 cache_info->pixels);
1363 else
cristy4c08aed2011-07-01 19:47:50 +00001364 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001365 (size_t) cache_info->length);
1366 RelinquishMagickResource(MemoryResource,cache_info->length);
1367 break;
1368 }
1369 case MapCache:
1370 {
cristy4c08aed2011-07-01 19:47:50 +00001371 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001372 cache_info->length);
1373 RelinquishMagickResource(MapResource,cache_info->length);
1374 }
1375 case DiskCache:
1376 {
1377 if (cache_info->file != -1)
1378 (void) ClosePixelCacheOnDisk(cache_info);
1379 RelinquishMagickResource(DiskResource,cache_info->length);
1380 break;
1381 }
1382 default:
1383 break;
1384 }
1385 cache_info->type=UndefinedCache;
1386 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001387 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001388}
1389
cristya6577ff2011-09-02 19:54:26 +00001390MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001391{
1392 CacheInfo
1393 *cache_info;
1394
cristy3ed852e2009-09-05 21:47:34 +00001395 assert(cache != (Cache) NULL);
1396 cache_info=(CacheInfo *) cache;
1397 assert(cache_info->signature == MagickSignature);
1398 if (cache_info->debug != MagickFalse)
1399 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1400 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001401 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001402 cache_info->reference_count--;
1403 if (cache_info->reference_count != 0)
1404 {
cristyf84a1932010-01-03 18:00:18 +00001405 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001406 return((Cache) NULL);
1407 }
cristyf84a1932010-01-03 18:00:18 +00001408 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001409 if (cache_resources != (SplayTreeInfo *) NULL)
1410 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001411 if (cache_info->debug != MagickFalse)
1412 {
1413 char
1414 message[MaxTextExtent];
1415
cristyb51dff52011-05-19 16:55:47 +00001416 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001417 cache_info->filename);
1418 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1419 }
cristyc2e1bdd2009-09-10 23:43:34 +00001420 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1421 (cache_info->type != DiskCache)))
1422 RelinquishPixelCachePixels(cache_info);
1423 else
1424 {
1425 RelinquishPixelCachePixels(cache_info);
1426 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1427 }
cristy3ed852e2009-09-05 21:47:34 +00001428 *cache_info->cache_filename='\0';
1429 if (cache_info->nexus_info != (NexusInfo **) NULL)
1430 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1431 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001432 if (cache_info->random_info != (RandomInfo *) NULL)
1433 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001434 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1435 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1436 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1437 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001438 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001439 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001440 cache=(Cache) NULL;
1441 return(cache);
1442}
1443
1444/*
1445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446% %
1447% %
1448% %
1449+ D e s t r o y P i x e l C a c h e N e x u s %
1450% %
1451% %
1452% %
1453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454%
1455% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1456%
1457% The format of the DestroyPixelCacheNexus() method is:
1458%
1459% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001460% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001461%
1462% A description of each parameter follows:
1463%
1464% o nexus_info: the nexus to destroy.
1465%
1466% o number_threads: the number of nexus threads.
1467%
1468*/
1469
1470static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1471{
1472 if (nexus_info->mapped == MagickFalse)
1473 (void) RelinquishMagickMemory(nexus_info->cache);
1474 else
1475 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001476 nexus_info->cache=(Quantum *) NULL;
1477 nexus_info->pixels=(Quantum *) NULL;
1478 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001479 nexus_info->length=0;
1480 nexus_info->mapped=MagickFalse;
1481}
1482
cristya6577ff2011-09-02 19:54:26 +00001483MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001484 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001485{
cristybb503372010-05-27 20:51:26 +00001486 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001487 i;
1488
1489 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001490 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001491 {
cristy4c08aed2011-07-01 19:47:50 +00001492 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001493 RelinquishCacheNexusPixels(nexus_info[i]);
1494 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001495 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001496 }
cristyb41ee102010-10-04 16:46:15 +00001497 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001498 return(nexus_info);
1499}
1500
1501/*
1502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503% %
1504% %
1505% %
cristy4c08aed2011-07-01 19:47:50 +00001506% 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 +00001507% %
1508% %
1509% %
1510%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1511%
cristy4c08aed2011-07-01 19:47:50 +00001512% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1513% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1514% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001515%
cristy4c08aed2011-07-01 19:47:50 +00001516% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001517%
cristy4c08aed2011-07-01 19:47:50 +00001518% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001519%
1520% A description of each parameter follows:
1521%
1522% o image: the image.
1523%
1524*/
cristy4c08aed2011-07-01 19:47:50 +00001525MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001526{
1527 CacheInfo
1528 *cache_info;
1529
cristy5c9e6f22010-09-17 17:31:01 +00001530 const int
1531 id = GetOpenMPThreadId();
1532
cristy4c08aed2011-07-01 19:47:50 +00001533 void
1534 *metacontent;
1535
cristye7cc7cf2010-09-21 13:26:47 +00001536 assert(image != (const Image *) NULL);
1537 assert(image->signature == MagickSignature);
1538 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001539 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001540 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001541 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1542 (GetAuthenticMetacontentFromHandler) NULL)
1543 {
1544 metacontent=cache_info->methods.
1545 get_authentic_metacontent_from_handler(image);
1546 return(metacontent);
1547 }
cristy6ebe97c2010-07-03 01:17:28 +00001548 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001549 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1550 cache_info->nexus_info[id]);
1551 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001552}
1553
1554/*
1555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556% %
1557% %
1558% %
cristy4c08aed2011-07-01 19:47:50 +00001559+ 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 +00001560% %
1561% %
1562% %
1563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1564%
cristy4c08aed2011-07-01 19:47:50 +00001565% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1566% with the last call to QueueAuthenticPixelsCache() or
1567% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001568%
cristy4c08aed2011-07-01 19:47:50 +00001569% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001570%
cristy4c08aed2011-07-01 19:47:50 +00001571% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001572%
1573% A description of each parameter follows:
1574%
1575% o image: the image.
1576%
1577*/
cristy4c08aed2011-07-01 19:47:50 +00001578static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001579{
1580 CacheInfo
1581 *cache_info;
1582
cristy2036f5c2010-09-19 21:18:17 +00001583 const int
1584 id = GetOpenMPThreadId();
1585
cristy4c08aed2011-07-01 19:47:50 +00001586 void
1587 *metacontent;
1588
cristy3ed852e2009-09-05 21:47:34 +00001589 assert(image != (const Image *) NULL);
1590 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001591 assert(image->cache != (Cache) NULL);
1592 cache_info=(CacheInfo *) image->cache;
1593 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001594 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001595 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1596 cache_info->nexus_info[id]);
1597 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001598}
1599
1600/*
1601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602% %
1603% %
1604% %
1605+ 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 %
1606% %
1607% %
1608% %
1609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1610%
1611% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1612% disk pixel cache as defined by the geometry parameters. A pointer to the
1613% pixels is returned if the pixels are transferred, otherwise a NULL is
1614% returned.
1615%
1616% The format of the GetAuthenticPixelCacheNexus() method is:
1617%
cristy4c08aed2011-07-01 19:47:50 +00001618% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001619% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001620% NexusInfo *nexus_info,ExceptionInfo *exception)
1621%
1622% A description of each parameter follows:
1623%
1624% o image: the image.
1625%
1626% o x,y,columns,rows: These values define the perimeter of a region of
1627% pixels.
1628%
1629% o nexus_info: the cache nexus to return.
1630%
1631% o exception: return any errors or warnings in this structure.
1632%
1633*/
1634
cristy4c08aed2011-07-01 19:47:50 +00001635static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001636 NexusInfo *nexus_info)
1637{
cristy4c08aed2011-07-01 19:47:50 +00001638 MagickBooleanType
1639 status;
1640
cristy3ed852e2009-09-05 21:47:34 +00001641 MagickOffsetType
1642 offset;
1643
cristy73724512010-04-12 14:43:14 +00001644 if (cache_info->type == PingCache)
1645 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001646 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1647 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001648 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001649 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001650 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001651}
1652
cristya6577ff2011-09-02 19:54:26 +00001653MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001654 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001655 NexusInfo *nexus_info,ExceptionInfo *exception)
1656{
1657 CacheInfo
1658 *cache_info;
1659
cristy4c08aed2011-07-01 19:47:50 +00001660 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001661 *q;
cristy3ed852e2009-09-05 21:47:34 +00001662
1663 /*
1664 Transfer pixels from the cache.
1665 */
1666 assert(image != (Image *) NULL);
1667 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001668 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001669 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001670 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001671 cache_info=(CacheInfo *) image->cache;
1672 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001673 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001674 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001675 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001676 return((Quantum *) NULL);
1677 if (cache_info->metacontent_extent != 0)
1678 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1679 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001680 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001681}
1682
1683/*
1684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685% %
1686% %
1687% %
1688+ 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 %
1689% %
1690% %
1691% %
1692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693%
1694% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1695% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1696%
1697% The format of the GetAuthenticPixelsFromCache() method is:
1698%
cristy4c08aed2011-07-01 19:47:50 +00001699% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001700%
1701% A description of each parameter follows:
1702%
1703% o image: the image.
1704%
1705*/
cristy4c08aed2011-07-01 19:47:50 +00001706static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001707{
1708 CacheInfo
1709 *cache_info;
1710
cristy5c9e6f22010-09-17 17:31:01 +00001711 const int
1712 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001713
cristye7cc7cf2010-09-21 13:26:47 +00001714 assert(image != (const Image *) NULL);
1715 assert(image->signature == MagickSignature);
1716 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001717 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001718 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001719 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001720 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001721}
1722
1723/*
1724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1725% %
1726% %
1727% %
1728% G e t A u t h e n t i c P i x e l Q u e u e %
1729% %
1730% %
1731% %
1732%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1733%
cristy4c08aed2011-07-01 19:47:50 +00001734% GetAuthenticPixelQueue() returns the authentic pixels associated
1735% corresponding with the last call to QueueAuthenticPixels() or
1736% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001737%
1738% The format of the GetAuthenticPixelQueue() method is:
1739%
cristy4c08aed2011-07-01 19:47:50 +00001740% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001741%
1742% A description of each parameter follows:
1743%
1744% o image: the image.
1745%
1746*/
cristy4c08aed2011-07-01 19:47:50 +00001747MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001748{
1749 CacheInfo
1750 *cache_info;
1751
cristy2036f5c2010-09-19 21:18:17 +00001752 const int
1753 id = GetOpenMPThreadId();
1754
cristy3ed852e2009-09-05 21:47:34 +00001755 assert(image != (const Image *) NULL);
1756 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001757 assert(image->cache != (Cache) NULL);
1758 cache_info=(CacheInfo *) image->cache;
1759 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001760 if (cache_info->methods.get_authentic_pixels_from_handler !=
1761 (GetAuthenticPixelsFromHandler) NULL)
1762 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001763 assert(id < (int) cache_info->number_threads);
1764 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001765}
1766
1767/*
1768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769% %
1770% %
1771% %
1772% G e t A u t h e n t i c P i x e l s %
1773% %
1774% %
cristy4c08aed2011-07-01 19:47:50 +00001775% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001776%
1777% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001778% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001779% representing the region is returned, otherwise NULL is returned.
1780%
1781% The returned pointer may point to a temporary working copy of the pixels
1782% or it may point to the original pixels in memory. Performance is maximized
1783% if the selected region is part of one row, or one or more full rows, since
1784% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001785% if the image is in memory, or in a memory-mapped file. The returned pointer
1786% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001787%
1788% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001789% Quantum. If the image has corresponding metacontent,call
1790% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1791% meta-content corresponding to the region. Once the Quantum array has
1792% been updated, the changes must be saved back to the underlying image using
1793% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001794%
1795% The format of the GetAuthenticPixels() method is:
1796%
cristy4c08aed2011-07-01 19:47:50 +00001797% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001798% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001799% ExceptionInfo *exception)
1800%
1801% A description of each parameter follows:
1802%
1803% o image: the image.
1804%
1805% o x,y,columns,rows: These values define the perimeter of a region of
1806% pixels.
1807%
1808% o exception: return any errors or warnings in this structure.
1809%
1810*/
cristy4c08aed2011-07-01 19:47:50 +00001811MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001812 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001813 ExceptionInfo *exception)
1814{
1815 CacheInfo
1816 *cache_info;
1817
cristy2036f5c2010-09-19 21:18:17 +00001818 const int
1819 id = GetOpenMPThreadId();
1820
cristy4c08aed2011-07-01 19:47:50 +00001821 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001822 *q;
cristy4c08aed2011-07-01 19:47:50 +00001823
cristy3ed852e2009-09-05 21:47:34 +00001824 assert(image != (Image *) NULL);
1825 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001826 assert(image->cache != (Cache) NULL);
1827 cache_info=(CacheInfo *) image->cache;
1828 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001829 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001830 (GetAuthenticPixelsHandler) NULL)
1831 {
cristyacd2ed22011-08-30 01:44:23 +00001832 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1833 exception);
1834 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001835 }
cristy2036f5c2010-09-19 21:18:17 +00001836 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001837 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001838 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001839 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001840}
1841
1842/*
1843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1844% %
1845% %
1846% %
1847+ G e t A u t h e n t i c P i x e l s C a c h e %
1848% %
1849% %
1850% %
1851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1852%
1853% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1854% as defined by the geometry parameters. A pointer to the pixels is returned
1855% if the pixels are transferred, otherwise a NULL is returned.
1856%
1857% The format of the GetAuthenticPixelsCache() method is:
1858%
cristy4c08aed2011-07-01 19:47:50 +00001859% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001860% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001861% ExceptionInfo *exception)
1862%
1863% A description of each parameter follows:
1864%
1865% o image: the image.
1866%
1867% o x,y,columns,rows: These values define the perimeter of a region of
1868% pixels.
1869%
1870% o exception: return any errors or warnings in this structure.
1871%
1872*/
cristy4c08aed2011-07-01 19:47:50 +00001873static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001874 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001875 ExceptionInfo *exception)
1876{
1877 CacheInfo
1878 *cache_info;
1879
cristy5c9e6f22010-09-17 17:31:01 +00001880 const int
1881 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001882
cristy4c08aed2011-07-01 19:47:50 +00001883 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001884 *q;
cristy4c08aed2011-07-01 19:47:50 +00001885
cristye7cc7cf2010-09-21 13:26:47 +00001886 assert(image != (const Image *) NULL);
1887 assert(image->signature == MagickSignature);
1888 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001889 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001890 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001891 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001892 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001893 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001894 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001895 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001896 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001897}
1898
1899/*
1900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901% %
1902% %
1903% %
1904+ G e t I m a g e E x t e n t %
1905% %
1906% %
1907% %
1908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1909%
cristy4c08aed2011-07-01 19:47:50 +00001910% GetImageExtent() returns the extent of the pixels associated corresponding
1911% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001912%
1913% The format of the GetImageExtent() method is:
1914%
1915% MagickSizeType GetImageExtent(const Image *image)
1916%
1917% A description of each parameter follows:
1918%
1919% o image: the image.
1920%
1921*/
1922MagickExport MagickSizeType GetImageExtent(const Image *image)
1923{
1924 CacheInfo
1925 *cache_info;
1926
cristy5c9e6f22010-09-17 17:31:01 +00001927 const int
1928 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001929
cristy3ed852e2009-09-05 21:47:34 +00001930 assert(image != (Image *) NULL);
1931 assert(image->signature == MagickSignature);
1932 if (image->debug != MagickFalse)
1933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1934 assert(image->cache != (Cache) NULL);
1935 cache_info=(CacheInfo *) image->cache;
1936 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001937 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001938 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001939}
1940
1941/*
1942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943% %
1944% %
1945% %
1946+ G e t I m a g e P i x e l C a c h e %
1947% %
1948% %
1949% %
1950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951%
1952% GetImagePixelCache() ensures that there is only a single reference to the
1953% pixel cache to be modified, updating the provided cache pointer to point to
1954% a clone of the original pixel cache if necessary.
1955%
1956% The format of the GetImagePixelCache method is:
1957%
1958% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1959% ExceptionInfo *exception)
1960%
1961% A description of each parameter follows:
1962%
1963% o image: the image.
1964%
1965% o clone: any value other than MagickFalse clones the cache pixels.
1966%
1967% o exception: return any errors or warnings in this structure.
1968%
1969*/
cristyaf894d72011-08-06 23:03:10 +00001970
cristy3ed852e2009-09-05 21:47:34 +00001971static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1972{
1973 CacheInfo
1974 *cache_info;
1975
1976 /*
1977 Does the image match the pixel cache morphology?
1978 */
1979 cache_info=(CacheInfo *) image->cache;
1980 if ((image->storage_class != cache_info->storage_class) ||
1981 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001982 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00001983 (image->columns != cache_info->columns) ||
1984 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001985 (image->number_channels != cache_info->number_channels) ||
cristy4c08aed2011-07-01 19:47:50 +00001986 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001987 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1988 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1989 return(MagickFalse);
1990 return(MagickTrue);
1991}
1992
cristycd01fae2011-08-06 23:52:42 +00001993static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1994 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001995{
1996 CacheInfo
1997 *cache_info;
1998
cristy3ed852e2009-09-05 21:47:34 +00001999 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002000 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002001 status;
2002
cristy50a10922010-02-15 18:35:25 +00002003 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002004 cpu_throttle = 0,
2005 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002006 time_limit = 0;
2007
cristy1ea34962010-07-01 19:49:21 +00002008 static time_t
cristy208b1002011-08-07 18:51:50 +00002009 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002010
cristyc4f9f132010-03-04 18:50:01 +00002011 status=MagickTrue;
2012 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002013 if (cpu_throttle == 0)
2014 {
2015 char
2016 *limit;
2017
2018 /*
2019 Set CPU throttle in milleseconds.
2020 */
2021 cpu_throttle=MagickResourceInfinity;
2022 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2023 if (limit == (char *) NULL)
2024 limit=GetPolicyValue("throttle");
2025 if (limit != (char *) NULL)
2026 {
2027 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2028 limit=DestroyString(limit);
2029 }
2030 }
2031 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2032 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002033 if (time_limit == 0)
2034 {
cristy6ebe97c2010-07-03 01:17:28 +00002035 /*
2036 Set the exire time in seconds.
2037 */
cristy1ea34962010-07-01 19:49:21 +00002038 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002039 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002040 }
2041 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002042 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002043 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002044 assert(image->cache != (Cache) NULL);
2045 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002046 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002047 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002048 {
cristyceb55ee2010-11-06 16:05:49 +00002049 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002050 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002051 {
cristyceb55ee2010-11-06 16:05:49 +00002052 Image
2053 clone_image;
2054
2055 CacheInfo
2056 *clone_info;
2057
2058 /*
2059 Clone pixel cache.
2060 */
2061 clone_image=(*image);
2062 clone_image.semaphore=AllocateSemaphoreInfo();
2063 clone_image.reference_count=1;
2064 clone_image.cache=ClonePixelCache(cache_info);
2065 clone_info=(CacheInfo *) clone_image.cache;
2066 status=OpenPixelCache(&clone_image,IOMode,exception);
2067 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002068 {
cristy5a7fbfb2010-11-06 16:10:59 +00002069 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002070 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002071 if (status != MagickFalse)
2072 {
cristy979bf772011-08-08 00:04:15 +00002073 if (cache_info->mode == ReadMode)
2074 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002075 destroy=MagickTrue;
2076 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002077 }
2078 }
cristyceb55ee2010-11-06 16:05:49 +00002079 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002080 }
cristyceb55ee2010-11-06 16:05:49 +00002081 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002082 }
cristy4320e0e2009-09-10 15:00:08 +00002083 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002084 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002085 if (status != MagickFalse)
2086 {
2087 /*
2088 Ensure the image matches the pixel cache morphology.
2089 */
2090 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002091 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002092 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2093 status=OpenPixelCache(image,IOMode,exception);
2094 }
cristyf84a1932010-01-03 18:00:18 +00002095 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002096 if (status == MagickFalse)
2097 return((Cache) NULL);
2098 return(image->cache);
2099}
2100
2101/*
2102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2103% %
2104% %
2105% %
2106% G e t O n e A u t h e n t i c P i x e l %
2107% %
2108% %
2109% %
2110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2111%
2112% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2113% location. The image background color is returned if an error occurs.
2114%
2115% The format of the GetOneAuthenticPixel() method is:
2116%
cristybb503372010-05-27 20:51:26 +00002117% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002118% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002119%
2120% A description of each parameter follows:
2121%
2122% o image: the image.
2123%
2124% o x,y: These values define the location of the pixel to return.
2125%
2126% o pixel: return a pixel at the specified (x,y) location.
2127%
2128% o exception: return any errors or warnings in this structure.
2129%
2130*/
cristyacbbb7c2010-06-30 18:56:48 +00002131MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002132 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002133{
2134 CacheInfo
2135 *cache_info;
2136
cristy4c08aed2011-07-01 19:47:50 +00002137 register Quantum
2138 *q;
cristy2036f5c2010-09-19 21:18:17 +00002139
cristy2ed42f62011-10-02 19:49:57 +00002140 register ssize_t
2141 i;
2142
cristy3ed852e2009-09-05 21:47:34 +00002143 assert(image != (Image *) NULL);
2144 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002145 assert(image->cache != (Cache) NULL);
2146 cache_info=(CacheInfo *) image->cache;
2147 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002148 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002149 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2150 (GetOneAuthenticPixelFromHandler) NULL)
2151 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2152 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002153 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2154 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002155 {
2156 pixel[RedPixelChannel]=image->background_color.red;
2157 pixel[GreenPixelChannel]=image->background_color.green;
2158 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002159 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002160 pixel[AlphaPixelChannel]=image->background_color.alpha;
2161 return(MagickFalse);
2162 }
2163 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2164 {
2165 PixelChannel
2166 channel;
2167
cristye2a912b2011-12-05 20:02:07 +00002168 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002169 pixel[channel]=q[i];
2170 }
cristy2036f5c2010-09-19 21:18:17 +00002171 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002172}
2173
2174/*
2175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176% %
2177% %
2178% %
2179+ 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 %
2180% %
2181% %
2182% %
2183%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184%
2185% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2186% location. The image background color is returned if an error occurs.
2187%
2188% The format of the GetOneAuthenticPixelFromCache() method is:
2189%
2190% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002191% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002192% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002193%
2194% A description of each parameter follows:
2195%
2196% o image: the image.
2197%
2198% o x,y: These values define the location of the pixel to return.
2199%
2200% o pixel: return a pixel at the specified (x,y) location.
2201%
2202% o exception: return any errors or warnings in this structure.
2203%
2204*/
2205static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002206 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002207{
cristy098f78c2010-09-23 17:28:44 +00002208 CacheInfo
2209 *cache_info;
2210
2211 const int
2212 id = GetOpenMPThreadId();
2213
cristy4c08aed2011-07-01 19:47:50 +00002214 register Quantum
2215 *q;
cristy3ed852e2009-09-05 21:47:34 +00002216
cristy2ed42f62011-10-02 19:49:57 +00002217 register ssize_t
2218 i;
2219
cristy0158a4b2010-09-20 13:59:45 +00002220 assert(image != (const Image *) NULL);
2221 assert(image->signature == MagickSignature);
2222 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002223 cache_info=(CacheInfo *) image->cache;
2224 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002225 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002226 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002227 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2228 exception);
2229 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002230 {
2231 pixel[RedPixelChannel]=image->background_color.red;
2232 pixel[GreenPixelChannel]=image->background_color.green;
2233 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002234 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002235 pixel[AlphaPixelChannel]=image->background_color.alpha;
2236 return(MagickFalse);
2237 }
2238 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2239 {
2240 PixelChannel
2241 channel;
2242
cristye2a912b2011-12-05 20:02:07 +00002243 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002244 pixel[channel]=q[i];
2245 }
cristy3ed852e2009-09-05 21:47:34 +00002246 return(MagickTrue);
2247}
2248
2249/*
2250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2251% %
2252% %
2253% %
cristy3ed852e2009-09-05 21:47:34 +00002254% G e t O n e V i r t u a l P i x e l %
2255% %
2256% %
2257% %
2258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2259%
2260% GetOneVirtualPixel() returns a single virtual pixel at the specified
2261% (x,y) location. The image background color is returned if an error occurs.
2262% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2263%
2264% The format of the GetOneVirtualPixel() method is:
2265%
cristybb503372010-05-27 20:51:26 +00002266% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002267% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002268%
2269% A description of each parameter follows:
2270%
2271% o image: the image.
2272%
2273% o x,y: These values define the location of the pixel to return.
2274%
2275% o pixel: return a pixel at the specified (x,y) location.
2276%
2277% o exception: return any errors or warnings in this structure.
2278%
2279*/
2280MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002281 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002282{
cristy3ed852e2009-09-05 21:47:34 +00002283 CacheInfo
2284 *cache_info;
2285
cristy0158a4b2010-09-20 13:59:45 +00002286 const int
2287 id = GetOpenMPThreadId();
2288
cristy4c08aed2011-07-01 19:47:50 +00002289 const Quantum
2290 *p;
cristy2036f5c2010-09-19 21:18:17 +00002291
cristy2ed42f62011-10-02 19:49:57 +00002292 register ssize_t
2293 i;
2294
cristy3ed852e2009-09-05 21:47:34 +00002295 assert(image != (const Image *) NULL);
2296 assert(image->signature == MagickSignature);
2297 assert(image->cache != (Cache) NULL);
2298 cache_info=(CacheInfo *) image->cache;
2299 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002300 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002301 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2302 (GetOneVirtualPixelFromHandler) NULL)
2303 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2304 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002305 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002306 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002307 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002308 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002309 {
2310 pixel[RedPixelChannel]=image->background_color.red;
2311 pixel[GreenPixelChannel]=image->background_color.green;
2312 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002313 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002314 pixel[AlphaPixelChannel]=image->background_color.alpha;
2315 return(MagickFalse);
2316 }
2317 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2318 {
2319 PixelChannel
2320 channel;
2321
cristye2a912b2011-12-05 20:02:07 +00002322 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002323 pixel[channel]=p[i];
2324 }
cristy2036f5c2010-09-19 21:18:17 +00002325 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002326}
2327
2328/*
2329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2330% %
2331% %
2332% %
2333+ 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 %
2334% %
2335% %
2336% %
2337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2338%
2339% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2340% specified (x,y) location. The image background color is returned if an
2341% error occurs.
2342%
2343% The format of the GetOneVirtualPixelFromCache() method is:
2344%
2345% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002346% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002347% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002348%
2349% A description of each parameter follows:
2350%
2351% o image: the image.
2352%
2353% o virtual_pixel_method: the virtual pixel method.
2354%
2355% o x,y: These values define the location of the pixel to return.
2356%
2357% o pixel: return a pixel at the specified (x,y) location.
2358%
2359% o exception: return any errors or warnings in this structure.
2360%
2361*/
2362static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002363 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002364 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002365{
cristy0158a4b2010-09-20 13:59:45 +00002366 CacheInfo
2367 *cache_info;
2368
2369 const int
2370 id = GetOpenMPThreadId();
2371
cristy4c08aed2011-07-01 19:47:50 +00002372 const Quantum
2373 *p;
cristy3ed852e2009-09-05 21:47:34 +00002374
cristy2ed42f62011-10-02 19:49:57 +00002375 register ssize_t
2376 i;
2377
cristye7cc7cf2010-09-21 13:26:47 +00002378 assert(image != (const Image *) NULL);
2379 assert(image->signature == MagickSignature);
2380 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002381 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002382 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002383 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002384 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002385 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002386 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002387 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002388 {
2389 pixel[RedPixelChannel]=image->background_color.red;
2390 pixel[GreenPixelChannel]=image->background_color.green;
2391 pixel[BluePixelChannel]=image->background_color.blue;
cristyec061ec2011-10-21 17:41:17 +00002392 pixel[BlackPixelChannel]=image->background_color.black;
cristy2ed42f62011-10-02 19:49:57 +00002393 pixel[AlphaPixelChannel]=image->background_color.alpha;
2394 return(MagickFalse);
2395 }
2396 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2397 {
2398 PixelChannel
2399 channel;
2400
cristye2a912b2011-12-05 20:02:07 +00002401 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002402 pixel[channel]=p[i];
2403 }
cristy3ed852e2009-09-05 21:47:34 +00002404 return(MagickTrue);
2405}
2406
2407/*
2408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2409% %
2410% %
2411% %
cristy3aa93752011-12-18 15:54:24 +00002412% G e t O n e V i r t u a l P i x e l I n f o %
2413% %
2414% %
2415% %
2416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2417%
2418% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2419% location. The image background color is returned if an error occurs. If
2420% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2421%
2422% The format of the GetOneVirtualPixelInfo() method is:
2423%
2424% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2425% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2426% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2427%
2428% A description of each parameter follows:
2429%
2430% o image: the image.
2431%
2432% o virtual_pixel_method: the virtual pixel method.
2433%
2434% o x,y: these values define the location of the pixel to return.
2435%
2436% o pixel: return a pixel at the specified (x,y) location.
2437%
2438% o exception: return any errors or warnings in this structure.
2439%
2440*/
2441MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2442 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2443 PixelInfo *pixel,ExceptionInfo *exception)
2444{
2445 CacheInfo
2446 *cache_info;
2447
2448 const int
2449 id = GetOpenMPThreadId();
2450
2451 register const Quantum
2452 *p;
2453
2454 assert(image != (const Image *) NULL);
2455 assert(image->signature == MagickSignature);
2456 assert(image->cache != (Cache) NULL);
2457 cache_info=(CacheInfo *) image->cache;
2458 assert(cache_info->signature == MagickSignature);
2459 assert(id < (int) cache_info->number_threads);
2460 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2461 cache_info->nexus_info[id],exception);
2462 GetPixelInfo(image,pixel);
2463 if (p == (const Quantum *) NULL)
2464 return(MagickFalse);
2465 GetPixelInfoPixel(image,p,pixel);
2466 return(MagickTrue);
2467}
2468
2469/*
2470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471% %
2472% %
2473% %
cristy3ed852e2009-09-05 21:47:34 +00002474+ G e t P i x e l C a c h e C o l o r s p a c e %
2475% %
2476% %
2477% %
2478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2479%
2480% GetPixelCacheColorspace() returns the class type of the pixel cache.
2481%
2482% The format of the GetPixelCacheColorspace() method is:
2483%
2484% Colorspace GetPixelCacheColorspace(Cache cache)
2485%
2486% A description of each parameter follows:
2487%
2488% o cache: the pixel cache.
2489%
2490*/
cristya6577ff2011-09-02 19:54:26 +00002491MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002492{
2493 CacheInfo
2494 *cache_info;
2495
2496 assert(cache != (Cache) NULL);
2497 cache_info=(CacheInfo *) cache;
2498 assert(cache_info->signature == MagickSignature);
2499 if (cache_info->debug != MagickFalse)
2500 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2501 cache_info->filename);
2502 return(cache_info->colorspace);
2503}
2504
2505/*
2506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2507% %
2508% %
2509% %
2510+ G e t P i x e l C a c h e M e t h o d s %
2511% %
2512% %
2513% %
2514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2515%
2516% GetPixelCacheMethods() initializes the CacheMethods structure.
2517%
2518% The format of the GetPixelCacheMethods() method is:
2519%
2520% void GetPixelCacheMethods(CacheMethods *cache_methods)
2521%
2522% A description of each parameter follows:
2523%
2524% o cache_methods: Specifies a pointer to a CacheMethods structure.
2525%
2526*/
cristya6577ff2011-09-02 19:54:26 +00002527MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002528{
2529 assert(cache_methods != (CacheMethods *) NULL);
2530 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2531 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2532 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002533 cache_methods->get_virtual_metacontent_from_handler=
2534 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002535 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2536 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002537 cache_methods->get_authentic_metacontent_from_handler=
2538 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002539 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2540 cache_methods->get_one_authentic_pixel_from_handler=
2541 GetOneAuthenticPixelFromCache;
2542 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2543 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2544 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2545}
2546
2547/*
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549% %
2550% %
2551% %
2552+ G e t P i x e l C a c h e N e x u s E x t e n t %
2553% %
2554% %
2555% %
2556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2557%
cristy4c08aed2011-07-01 19:47:50 +00002558% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2559% corresponding with the last call to SetPixelCacheNexusPixels() or
2560% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002561%
2562% The format of the GetPixelCacheNexusExtent() method is:
2563%
2564% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2565% NexusInfo *nexus_info)
2566%
2567% A description of each parameter follows:
2568%
2569% o nexus_info: the nexus info.
2570%
2571*/
cristya6577ff2011-09-02 19:54:26 +00002572MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002573 NexusInfo *nexus_info)
2574{
2575 CacheInfo
2576 *cache_info;
2577
2578 MagickSizeType
2579 extent;
2580
cristy9f027d12011-09-21 01:17:17 +00002581 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002582 cache_info=(CacheInfo *) cache;
2583 assert(cache_info->signature == MagickSignature);
2584 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2585 if (extent == 0)
2586 return((MagickSizeType) cache_info->columns*cache_info->rows);
2587 return(extent);
2588}
2589
2590/*
2591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592% %
2593% %
2594% %
cristy4c08aed2011-07-01 19:47:50 +00002595+ 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 +00002596% %
2597% %
2598% %
2599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2600%
cristy4c08aed2011-07-01 19:47:50 +00002601% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2602% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002603%
cristy4c08aed2011-07-01 19:47:50 +00002604% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002605%
cristy4c08aed2011-07-01 19:47:50 +00002606% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002607% NexusInfo *nexus_info)
2608%
2609% A description of each parameter follows:
2610%
2611% o cache: the pixel cache.
2612%
cristy4c08aed2011-07-01 19:47:50 +00002613% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002614%
2615*/
cristya6577ff2011-09-02 19:54:26 +00002616MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002617 NexusInfo *nexus_info)
2618{
2619 CacheInfo
2620 *cache_info;
2621
cristy9f027d12011-09-21 01:17:17 +00002622 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002623 cache_info=(CacheInfo *) cache;
2624 assert(cache_info->signature == MagickSignature);
2625 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002626 return((void *) NULL);
2627 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002628}
2629
2630/*
2631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632% %
2633% %
2634% %
2635+ G e t P i x e l C a c h e N e x u s P i x e l s %
2636% %
2637% %
2638% %
2639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2640%
2641% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2642% cache nexus.
2643%
2644% The format of the GetPixelCacheNexusPixels() method is:
2645%
cristy4c08aed2011-07-01 19:47:50 +00002646% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002647% NexusInfo *nexus_info)
2648%
2649% A description of each parameter follows:
2650%
2651% o cache: the pixel cache.
2652%
2653% o nexus_info: the cache nexus to return the pixels.
2654%
2655*/
cristya6577ff2011-09-02 19:54:26 +00002656MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002657 NexusInfo *nexus_info)
2658{
2659 CacheInfo
2660 *cache_info;
2661
cristy9f027d12011-09-21 01:17:17 +00002662 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002663 cache_info=(CacheInfo *) cache;
2664 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002665 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002666 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002667 return(nexus_info->pixels);
2668}
2669
2670/*
2671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2672% %
2673% %
2674% %
cristy056ba772010-01-02 23:33:54 +00002675+ G e t P i x e l C a c h e P i x e l s %
2676% %
2677% %
2678% %
2679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2680%
2681% GetPixelCachePixels() returns the pixels associated with the specified image.
2682%
2683% The format of the GetPixelCachePixels() method is:
2684%
cristyf84a1932010-01-03 18:00:18 +00002685% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2686% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002687%
2688% A description of each parameter follows:
2689%
2690% o image: the image.
2691%
2692% o length: the pixel cache length.
2693%
cristyf84a1932010-01-03 18:00:18 +00002694% o exception: return any errors or warnings in this structure.
2695%
cristy056ba772010-01-02 23:33:54 +00002696*/
cristyd1dd6e42011-09-04 01:46:08 +00002697MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002698 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002699{
2700 CacheInfo
2701 *cache_info;
2702
2703 assert(image != (const Image *) NULL);
2704 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002705 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002706 assert(length != (MagickSizeType *) NULL);
2707 assert(exception != (ExceptionInfo *) NULL);
2708 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002709 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002710 assert(cache_info->signature == MagickSignature);
2711 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002712 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002713 return((void *) NULL);
2714 *length=cache_info->length;
2715 return((void *) cache_info->pixels);
2716}
2717
2718/*
2719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720% %
2721% %
2722% %
cristyb32b90a2009-09-07 21:45:48 +00002723+ 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 +00002724% %
2725% %
2726% %
2727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2728%
2729% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2730%
2731% The format of the GetPixelCacheStorageClass() method is:
2732%
2733% ClassType GetPixelCacheStorageClass(Cache cache)
2734%
2735% A description of each parameter follows:
2736%
2737% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2738%
2739% o cache: the pixel cache.
2740%
2741*/
cristya6577ff2011-09-02 19:54:26 +00002742MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002743{
2744 CacheInfo
2745 *cache_info;
2746
2747 assert(cache != (Cache) NULL);
2748 cache_info=(CacheInfo *) cache;
2749 assert(cache_info->signature == MagickSignature);
2750 if (cache_info->debug != MagickFalse)
2751 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2752 cache_info->filename);
2753 return(cache_info->storage_class);
2754}
2755
2756/*
2757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2758% %
2759% %
2760% %
cristyb32b90a2009-09-07 21:45:48 +00002761+ G e t P i x e l C a c h e T i l e S i z e %
2762% %
2763% %
2764% %
2765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2766%
2767% GetPixelCacheTileSize() returns the pixel cache tile size.
2768%
2769% The format of the GetPixelCacheTileSize() method is:
2770%
cristybb503372010-05-27 20:51:26 +00002771% void GetPixelCacheTileSize(const Image *image,size_t *width,
2772% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002773%
2774% A description of each parameter follows:
2775%
2776% o image: the image.
2777%
2778% o width: the optimize cache tile width in pixels.
2779%
2780% o height: the optimize cache tile height in pixels.
2781%
2782*/
cristya6577ff2011-09-02 19:54:26 +00002783MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002784 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002785{
cristy4c08aed2011-07-01 19:47:50 +00002786 CacheInfo
2787 *cache_info;
2788
cristyb32b90a2009-09-07 21:45:48 +00002789 assert(image != (Image *) NULL);
2790 assert(image->signature == MagickSignature);
2791 if (image->debug != MagickFalse)
2792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002793 cache_info=(CacheInfo *) image->cache;
2794 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002795 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002796 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002797 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002798 *height=(*width);
2799}
2800
2801/*
2802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2803% %
2804% %
2805% %
2806+ G e t P i x e l C a c h e T y p e %
2807% %
2808% %
2809% %
2810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2811%
2812% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2813%
2814% The format of the GetPixelCacheType() method is:
2815%
2816% CacheType GetPixelCacheType(const Image *image)
2817%
2818% A description of each parameter follows:
2819%
2820% o image: the image.
2821%
2822*/
cristya6577ff2011-09-02 19:54:26 +00002823MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002824{
2825 CacheInfo
2826 *cache_info;
2827
2828 assert(image != (Image *) NULL);
2829 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002830 assert(image->cache != (Cache) NULL);
2831 cache_info=(CacheInfo *) image->cache;
2832 assert(cache_info->signature == MagickSignature);
2833 return(cache_info->type);
2834}
2835
2836/*
2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838% %
2839% %
2840% %
cristy3ed852e2009-09-05 21:47:34 +00002841+ 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 %
2842% %
2843% %
2844% %
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846%
2847% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2848% pixel cache. A virtual pixel is any pixel access that is outside the
2849% boundaries of the image cache.
2850%
2851% The format of the GetPixelCacheVirtualMethod() method is:
2852%
2853% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2854%
2855% A description of each parameter follows:
2856%
2857% o image: the image.
2858%
2859*/
cristyd1dd6e42011-09-04 01:46:08 +00002860MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002861{
2862 CacheInfo
2863 *cache_info;
2864
2865 assert(image != (Image *) NULL);
2866 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002867 assert(image->cache != (Cache) NULL);
2868 cache_info=(CacheInfo *) image->cache;
2869 assert(cache_info->signature == MagickSignature);
2870 return(cache_info->virtual_pixel_method);
2871}
2872
2873/*
2874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875% %
2876% %
2877% %
cristy4c08aed2011-07-01 19:47:50 +00002878+ 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 +00002879% %
2880% %
2881% %
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883%
cristy4c08aed2011-07-01 19:47:50 +00002884% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2885% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002886%
cristy4c08aed2011-07-01 19:47:50 +00002887% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002888%
cristy4c08aed2011-07-01 19:47:50 +00002889% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002890%
2891% A description of each parameter follows:
2892%
2893% o image: the image.
2894%
2895*/
cristy4c08aed2011-07-01 19:47:50 +00002896static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002897{
2898 CacheInfo
2899 *cache_info;
2900
cristy5c9e6f22010-09-17 17:31:01 +00002901 const int
2902 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002903
cristy4c08aed2011-07-01 19:47:50 +00002904 const void
2905 *metacontent;
2906
cristye7cc7cf2010-09-21 13:26:47 +00002907 assert(image != (const Image *) NULL);
2908 assert(image->signature == MagickSignature);
2909 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002910 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002911 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002912 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002913 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2914 cache_info->nexus_info[id]);
2915 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002916}
2917
2918/*
2919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2920% %
2921% %
2922% %
cristy4c08aed2011-07-01 19:47:50 +00002923+ 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 +00002924% %
2925% %
2926% %
2927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2928%
cristy4c08aed2011-07-01 19:47:50 +00002929% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2930% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002931%
cristy4c08aed2011-07-01 19:47:50 +00002932% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002933%
cristy4c08aed2011-07-01 19:47:50 +00002934% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002935% NexusInfo *nexus_info)
2936%
2937% A description of each parameter follows:
2938%
2939% o cache: the pixel cache.
2940%
cristy4c08aed2011-07-01 19:47:50 +00002941% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002942%
2943*/
cristya6577ff2011-09-02 19:54:26 +00002944MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002945 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002946{
2947 CacheInfo
2948 *cache_info;
2949
cristye7cc7cf2010-09-21 13:26:47 +00002950 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002951 cache_info=(CacheInfo *) cache;
2952 assert(cache_info->signature == MagickSignature);
2953 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002954 return((void *) NULL);
2955 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002956}
2957
2958/*
2959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2960% %
2961% %
2962% %
cristy4c08aed2011-07-01 19:47:50 +00002963% 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 +00002964% %
2965% %
2966% %
2967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2968%
cristy4c08aed2011-07-01 19:47:50 +00002969% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2970% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2971% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002972%
cristy4c08aed2011-07-01 19:47:50 +00002973% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002974%
cristy4c08aed2011-07-01 19:47:50 +00002975% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002976%
2977% A description of each parameter follows:
2978%
2979% o image: the image.
2980%
2981*/
cristy4c08aed2011-07-01 19:47:50 +00002982MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002983{
2984 CacheInfo
2985 *cache_info;
2986
cristy2036f5c2010-09-19 21:18:17 +00002987 const int
2988 id = GetOpenMPThreadId();
2989
cristy4c08aed2011-07-01 19:47:50 +00002990 const void
2991 *metacontent;
2992
cristy3ed852e2009-09-05 21:47:34 +00002993 assert(image != (const Image *) NULL);
2994 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002995 assert(image->cache != (Cache) NULL);
2996 cache_info=(CacheInfo *) image->cache;
2997 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002998 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2999 (GetVirtualMetacontentFromHandler) NULL)
3000 {
3001 metacontent=cache_info->methods.
3002 get_virtual_metacontent_from_handler(image);
3003 return(metacontent);
3004 }
cristy2036f5c2010-09-19 21:18:17 +00003005 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003006 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3007 cache_info->nexus_info[id]);
3008 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003009}
3010
3011/*
3012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3013% %
3014% %
3015% %
3016+ 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 %
3017% %
3018% %
3019% %
3020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3021%
3022% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3023% pixel cache as defined by the geometry parameters. A pointer to the pixels
3024% is returned if the pixels are transferred, otherwise a NULL is returned.
3025%
3026% The format of the GetVirtualPixelsFromNexus() method is:
3027%
cristy4c08aed2011-07-01 19:47:50 +00003028% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003029% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003030% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3031% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003032%
3033% A description of each parameter follows:
3034%
3035% o image: the image.
3036%
3037% o virtual_pixel_method: the virtual pixel method.
3038%
3039% o x,y,columns,rows: These values define the perimeter of a region of
3040% pixels.
3041%
3042% o nexus_info: the cache nexus to acquire.
3043%
3044% o exception: return any errors or warnings in this structure.
3045%
3046*/
3047
cristybb503372010-05-27 20:51:26 +00003048static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003049 DitherMatrix[64] =
3050 {
3051 0, 48, 12, 60, 3, 51, 15, 63,
3052 32, 16, 44, 28, 35, 19, 47, 31,
3053 8, 56, 4, 52, 11, 59, 7, 55,
3054 40, 24, 36, 20, 43, 27, 39, 23,
3055 2, 50, 14, 62, 1, 49, 13, 61,
3056 34, 18, 46, 30, 33, 17, 45, 29,
3057 10, 58, 6, 54, 9, 57, 5, 53,
3058 42, 26, 38, 22, 41, 25, 37, 21
3059 };
3060
cristybb503372010-05-27 20:51:26 +00003061static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003062{
cristybb503372010-05-27 20:51:26 +00003063 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003064 index;
3065
3066 index=x+DitherMatrix[x & 0x07]-32L;
3067 if (index < 0L)
3068 return(0L);
cristybb503372010-05-27 20:51:26 +00003069 if (index >= (ssize_t) columns)
3070 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003071 return(index);
3072}
3073
cristybb503372010-05-27 20:51:26 +00003074static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003075{
cristybb503372010-05-27 20:51:26 +00003076 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003077 index;
3078
3079 index=y+DitherMatrix[y & 0x07]-32L;
3080 if (index < 0L)
3081 return(0L);
cristybb503372010-05-27 20:51:26 +00003082 if (index >= (ssize_t) rows)
3083 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003084 return(index);
3085}
3086
cristybb503372010-05-27 20:51:26 +00003087static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003088{
3089 if (x < 0L)
3090 return(0L);
cristybb503372010-05-27 20:51:26 +00003091 if (x >= (ssize_t) columns)
3092 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003093 return(x);
3094}
3095
cristybb503372010-05-27 20:51:26 +00003096static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003097{
3098 if (y < 0L)
3099 return(0L);
cristybb503372010-05-27 20:51:26 +00003100 if (y >= (ssize_t) rows)
3101 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003102 return(y);
3103}
3104
cristybb503372010-05-27 20:51:26 +00003105static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003106{
cristybb503372010-05-27 20:51:26 +00003107 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003108}
3109
cristybb503372010-05-27 20:51:26 +00003110static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003111{
cristybb503372010-05-27 20:51:26 +00003112 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003113}
3114
cristybb503372010-05-27 20:51:26 +00003115static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3116 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003117{
3118 MagickModulo
3119 modulo;
3120
cristy6162bb42011-07-18 11:34:09 +00003121 /*
3122 Compute the remainder of dividing offset by extent. It returns not only
3123 the quotient (tile the offset falls in) but also the positive remainer
3124 within that tile such that 0 <= remainder < extent. This method is
3125 essentially a ldiv() using a floored modulo division rather than the
3126 normal default truncated modulo division.
3127 */
cristybb503372010-05-27 20:51:26 +00003128 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003129 if (offset < 0L)
3130 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003131 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003132 return(modulo);
3133}
3134
cristya6577ff2011-09-02 19:54:26 +00003135MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003136 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3137 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003138 ExceptionInfo *exception)
3139{
3140 CacheInfo
3141 *cache_info;
3142
3143 MagickOffsetType
3144 offset;
3145
3146 MagickSizeType
3147 length,
3148 number_pixels;
3149
3150 NexusInfo
3151 **virtual_nexus;
3152
cristy4c08aed2011-07-01 19:47:50 +00003153 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003154 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003155 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003156
3157 RectangleInfo
3158 region;
3159
cristy4c08aed2011-07-01 19:47:50 +00003160 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003161 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003162
cristy4c08aed2011-07-01 19:47:50 +00003163 register const void
3164 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003165
cristy4c08aed2011-07-01 19:47:50 +00003166 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003167 *restrict q;
3168
cristybb503372010-05-27 20:51:26 +00003169 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003170 i,
3171 u;
cristy3ed852e2009-09-05 21:47:34 +00003172
cristy4c08aed2011-07-01 19:47:50 +00003173 register unsigned char
3174 *restrict s;
3175
cristy105ba3c2011-07-18 02:28:38 +00003176 ssize_t
3177 v;
3178
cristy4c08aed2011-07-01 19:47:50 +00003179 void
cristy105ba3c2011-07-18 02:28:38 +00003180 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003181
cristy3ed852e2009-09-05 21:47:34 +00003182 /*
3183 Acquire pixels.
3184 */
cristye7cc7cf2010-09-21 13:26:47 +00003185 assert(image != (const Image *) NULL);
3186 assert(image->signature == MagickSignature);
3187 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003188 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003189 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003190 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003191 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003192 region.x=x;
3193 region.y=y;
3194 region.width=columns;
3195 region.height=rows;
3196 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003197 if (pixels == (Quantum *) NULL)
3198 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003199 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003200 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3201 nexus_info->region.x;
3202 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3203 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003204 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3205 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003206 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3207 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003208 {
3209 MagickBooleanType
3210 status;
3211
3212 /*
3213 Pixel request is inside cache extents.
3214 */
cristy4c08aed2011-07-01 19:47:50 +00003215 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003216 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003217 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3218 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003219 return((const Quantum *) NULL);
3220 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003221 {
cristy4c08aed2011-07-01 19:47:50 +00003222 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003223 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003224 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003225 }
cristyacd2ed22011-08-30 01:44:23 +00003226 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003227 }
3228 /*
3229 Pixel request is outside cache extents.
3230 */
cristy4c08aed2011-07-01 19:47:50 +00003231 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003232 virtual_nexus=AcquirePixelCacheNexus(1);
3233 if (virtual_nexus == (NexusInfo **) NULL)
3234 {
cristy4c08aed2011-07-01 19:47:50 +00003235 if (virtual_nexus != (NexusInfo **) NULL)
3236 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003237 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3238 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003239 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003240 }
cristy105ba3c2011-07-18 02:28:38 +00003241 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3242 sizeof(*virtual_pixel));
3243 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003244 switch (virtual_pixel_method)
3245 {
cristy4c08aed2011-07-01 19:47:50 +00003246 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003247 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003248 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003249 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003250 case MaskVirtualPixelMethod:
3251 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003252 case EdgeVirtualPixelMethod:
3253 case CheckerTileVirtualPixelMethod:
3254 case HorizontalTileVirtualPixelMethod:
3255 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003256 {
cristy4c08aed2011-07-01 19:47:50 +00003257 if (cache_info->metacontent_extent != 0)
3258 {
cristy6162bb42011-07-18 11:34:09 +00003259 /*
3260 Acquire a metacontent buffer.
3261 */
cristya64b85d2011-09-14 01:02:31 +00003262 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003263 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003264 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003265 {
cristy4c08aed2011-07-01 19:47:50 +00003266 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3267 (void) ThrowMagickException(exception,GetMagickModule(),
3268 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3269 return((const Quantum *) NULL);
3270 }
cristy105ba3c2011-07-18 02:28:38 +00003271 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003272 cache_info->metacontent_extent);
3273 }
3274 switch (virtual_pixel_method)
3275 {
3276 case BlackVirtualPixelMethod:
3277 {
cristy30301712011-07-18 15:06:51 +00003278 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3279 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003280 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3281 break;
3282 }
3283 case GrayVirtualPixelMethod:
3284 {
cristy30301712011-07-18 15:06:51 +00003285 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003286 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3287 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003288 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3289 break;
3290 }
3291 case TransparentVirtualPixelMethod:
3292 {
cristy30301712011-07-18 15:06:51 +00003293 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3294 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003295 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3296 break;
3297 }
3298 case MaskVirtualPixelMethod:
3299 case WhiteVirtualPixelMethod:
3300 {
cristy30301712011-07-18 15:06:51 +00003301 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3302 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003303 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3304 break;
3305 }
3306 default:
3307 {
3308 SetPixelRed(image,image->background_color.red,virtual_pixel);
3309 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3310 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003311 if (image->colorspace == CMYKColorspace)
3312 SetPixelBlack(image,image->background_color.black,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003313 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3314 break;
3315 }
3316 }
cristy3ed852e2009-09-05 21:47:34 +00003317 break;
3318 }
3319 default:
cristy3ed852e2009-09-05 21:47:34 +00003320 break;
cristy3ed852e2009-09-05 21:47:34 +00003321 }
cristybb503372010-05-27 20:51:26 +00003322 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003323 {
cristybb503372010-05-27 20:51:26 +00003324 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003325 {
3326 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003327 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003328 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3329 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003330 {
3331 MagickModulo
3332 x_modulo,
3333 y_modulo;
3334
3335 /*
3336 Transfer a single pixel.
3337 */
3338 length=(MagickSizeType) 1;
3339 switch (virtual_pixel_method)
3340 {
cristy3ed852e2009-09-05 21:47:34 +00003341 default:
3342 {
3343 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003344 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003345 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003346 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003347 break;
3348 }
3349 case RandomVirtualPixelMethod:
3350 {
3351 if (cache_info->random_info == (RandomInfo *) NULL)
3352 cache_info->random_info=AcquireRandomInfo();
3353 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003354 RandomX(cache_info->random_info,cache_info->columns),
3355 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003356 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003357 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003358 break;
3359 }
3360 case DitherVirtualPixelMethod:
3361 {
3362 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003363 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003364 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003365 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003366 break;
3367 }
3368 case TileVirtualPixelMethod:
3369 {
3370 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3371 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003373 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003374 exception);
cristy4c08aed2011-07-01 19:47:50 +00003375 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003376 break;
3377 }
3378 case MirrorVirtualPixelMethod:
3379 {
3380 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3381 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003382 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003383 x_modulo.remainder-1L;
3384 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3385 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003386 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003387 y_modulo.remainder-1L;
3388 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003389 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003390 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 HorizontalTileEdgeVirtualPixelMethod:
3395 {
3396 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3397 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003398 x_modulo.remainder,EdgeY(y+v,cache_info->rows),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);
cristy3ed852e2009-09-05 21:47:34 +00003401 break;
3402 }
3403 case VerticalTileEdgeVirtualPixelMethod:
3404 {
3405 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3406 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003407 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003408 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003409 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3410 break;
3411 }
3412 case BackgroundVirtualPixelMethod:
3413 case BlackVirtualPixelMethod:
3414 case GrayVirtualPixelMethod:
3415 case TransparentVirtualPixelMethod:
3416 case MaskVirtualPixelMethod:
3417 case WhiteVirtualPixelMethod:
3418 {
3419 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003420 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003421 break;
3422 }
3423 case EdgeVirtualPixelMethod:
3424 case CheckerTileVirtualPixelMethod:
3425 {
3426 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3427 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3428 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3429 {
3430 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003431 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003432 break;
3433 }
3434 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3435 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3436 exception);
3437 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3438 break;
3439 }
3440 case HorizontalTileVirtualPixelMethod:
3441 {
3442 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3443 {
3444 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003445 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003446 break;
3447 }
3448 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3449 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3450 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3451 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3452 exception);
3453 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3454 break;
3455 }
3456 case VerticalTileVirtualPixelMethod:
3457 {
3458 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3459 {
3460 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003461 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003462 break;
3463 }
3464 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3465 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3466 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3467 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3468 exception);
3469 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003470 break;
3471 }
3472 }
cristy4c08aed2011-07-01 19:47:50 +00003473 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003474 break;
cristyed231572011-07-14 02:18:59 +00003475 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003476 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003477 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003478 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003479 {
3480 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3481 s+=cache_info->metacontent_extent;
3482 }
cristy3ed852e2009-09-05 21:47:34 +00003483 continue;
3484 }
3485 /*
3486 Transfer a run of pixels.
3487 */
cristy4c08aed2011-07-01 19:47:50 +00003488 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3489 length,1UL,*virtual_nexus,exception);
3490 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003491 break;
cristy4c08aed2011-07-01 19:47:50 +00003492 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003493 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3494 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003495 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003496 {
cristy4c08aed2011-07-01 19:47:50 +00003497 (void) memcpy(s,r,(size_t) length);
3498 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003499 }
3500 }
3501 }
cristy4c08aed2011-07-01 19:47:50 +00003502 /*
3503 Free resources.
3504 */
cristy105ba3c2011-07-18 02:28:38 +00003505 if (virtual_metacontent != (void *) NULL)
3506 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003507 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3508 return(pixels);
3509}
3510
3511/*
3512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513% %
3514% %
3515% %
3516+ G e t V i r t u a l P i x e l C a c h e %
3517% %
3518% %
3519% %
3520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3521%
3522% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3523% cache as defined by the geometry parameters. A pointer to the pixels
3524% is returned if the pixels are transferred, otherwise a NULL is returned.
3525%
3526% The format of the GetVirtualPixelCache() method is:
3527%
cristy4c08aed2011-07-01 19:47:50 +00003528% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003529% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3530% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003531% ExceptionInfo *exception)
3532%
3533% A description of each parameter follows:
3534%
3535% o image: the image.
3536%
3537% o virtual_pixel_method: the virtual pixel method.
3538%
3539% o x,y,columns,rows: These values define the perimeter of a region of
3540% pixels.
3541%
3542% o exception: return any errors or warnings in this structure.
3543%
3544*/
cristy4c08aed2011-07-01 19:47:50 +00003545static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003546 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3547 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003548{
3549 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003550 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003551
cristy5c9e6f22010-09-17 17:31:01 +00003552 const int
3553 id = GetOpenMPThreadId();
3554
cristy4c08aed2011-07-01 19:47:50 +00003555 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003556 *p;
cristy4c08aed2011-07-01 19:47:50 +00003557
cristye7cc7cf2010-09-21 13:26:47 +00003558 assert(image != (const Image *) NULL);
3559 assert(image->signature == MagickSignature);
3560 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003561 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003562 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003563 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003564 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003565 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003566 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003567}
3568
3569/*
3570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3571% %
3572% %
3573% %
3574% G e t V i r t u a l P i x e l Q u e u e %
3575% %
3576% %
3577% %
3578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3579%
cristy4c08aed2011-07-01 19:47:50 +00003580% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3581% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003582%
3583% The format of the GetVirtualPixelQueue() method is:
3584%
cristy4c08aed2011-07-01 19:47:50 +00003585% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003586%
3587% A description of each parameter follows:
3588%
3589% o image: the image.
3590%
3591*/
cristy4c08aed2011-07-01 19:47:50 +00003592MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003593{
3594 CacheInfo
3595 *cache_info;
3596
cristy2036f5c2010-09-19 21:18:17 +00003597 const int
3598 id = GetOpenMPThreadId();
3599
cristy3ed852e2009-09-05 21:47:34 +00003600 assert(image != (const Image *) NULL);
3601 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003602 assert(image->cache != (Cache) NULL);
3603 cache_info=(CacheInfo *) image->cache;
3604 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003605 if (cache_info->methods.get_virtual_pixels_handler !=
3606 (GetVirtualPixelsHandler) NULL)
3607 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003608 assert(id < (int) cache_info->number_threads);
3609 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003610}
3611
3612/*
3613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614% %
3615% %
3616% %
3617% G e t V i r t u a l P i x e l s %
3618% %
3619% %
3620% %
3621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3622%
3623% GetVirtualPixels() returns an immutable pixel region. If the
3624% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003625% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003626% copy of the pixels or it may point to the original pixels in memory.
3627% Performance is maximized if the selected region is part of one row, or one
3628% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003629% (without a copy) if the image is in memory, or in a memory-mapped file. The
3630% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003631%
3632% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003633% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3634% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3635% access the meta-content (of type void) corresponding to the the
3636% region.
cristy3ed852e2009-09-05 21:47:34 +00003637%
3638% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3639%
3640% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3641% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3642% GetCacheViewAuthenticPixels() instead.
3643%
3644% The format of the GetVirtualPixels() method is:
3645%
cristy4c08aed2011-07-01 19:47:50 +00003646% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003647% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003648% ExceptionInfo *exception)
3649%
3650% A description of each parameter follows:
3651%
3652% o image: the image.
3653%
3654% o x,y,columns,rows: These values define the perimeter of a region of
3655% pixels.
3656%
3657% o exception: return any errors or warnings in this structure.
3658%
3659*/
cristy4c08aed2011-07-01 19:47:50 +00003660MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003661 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3662 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003663{
3664 CacheInfo
3665 *cache_info;
3666
cristy2036f5c2010-09-19 21:18:17 +00003667 const int
3668 id = GetOpenMPThreadId();
3669
cristy4c08aed2011-07-01 19:47:50 +00003670 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003671 *p;
cristy4c08aed2011-07-01 19:47:50 +00003672
cristy3ed852e2009-09-05 21:47:34 +00003673 assert(image != (const Image *) NULL);
3674 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003675 assert(image->cache != (Cache) NULL);
3676 cache_info=(CacheInfo *) image->cache;
3677 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003678 if (cache_info->methods.get_virtual_pixel_handler !=
3679 (GetVirtualPixelHandler) NULL)
3680 return(cache_info->methods.get_virtual_pixel_handler(image,
3681 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003682 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003683 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003684 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003685 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003686}
3687
3688/*
3689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3690% %
3691% %
3692% %
3693+ 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 %
3694% %
3695% %
3696% %
3697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3698%
cristy4c08aed2011-07-01 19:47:50 +00003699% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3700% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003701%
3702% The format of the GetVirtualPixelsCache() method is:
3703%
cristy4c08aed2011-07-01 19:47:50 +00003704% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003705%
3706% A description of each parameter follows:
3707%
3708% o image: the image.
3709%
3710*/
cristy4c08aed2011-07-01 19:47:50 +00003711static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003712{
3713 CacheInfo
3714 *cache_info;
3715
cristy5c9e6f22010-09-17 17:31:01 +00003716 const int
3717 id = GetOpenMPThreadId();
3718
cristye7cc7cf2010-09-21 13:26:47 +00003719 assert(image != (const Image *) NULL);
3720 assert(image->signature == MagickSignature);
3721 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003722 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003723 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003724 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003725 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003726}
3727
3728/*
3729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3730% %
3731% %
3732% %
3733+ G e t V i r t u a l P i x e l s N e x u s %
3734% %
3735% %
3736% %
3737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3738%
3739% GetVirtualPixelsNexus() returns the pixels associated with the specified
3740% cache nexus.
3741%
3742% The format of the GetVirtualPixelsNexus() method is:
3743%
cristy4c08aed2011-07-01 19:47:50 +00003744% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003745% NexusInfo *nexus_info)
3746%
3747% A description of each parameter follows:
3748%
3749% o cache: the pixel cache.
3750%
3751% o nexus_info: the cache nexus to return the colormap pixels.
3752%
3753*/
cristya6577ff2011-09-02 19:54:26 +00003754MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003755 NexusInfo *nexus_info)
3756{
3757 CacheInfo
3758 *cache_info;
3759
cristye7cc7cf2010-09-21 13:26:47 +00003760 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003761 cache_info=(CacheInfo *) cache;
3762 assert(cache_info->signature == MagickSignature);
3763 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003764 return((Quantum *) NULL);
3765 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003766}
3767
3768/*
3769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3770% %
3771% %
3772% %
3773+ M a s k P i x e l C a c h e N e x u s %
3774% %
3775% %
3776% %
3777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3778%
3779% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3780% The method returns MagickTrue if the pixel region is masked, otherwise
3781% MagickFalse.
3782%
3783% The format of the MaskPixelCacheNexus() method is:
3784%
3785% MagickBooleanType MaskPixelCacheNexus(Image *image,
3786% NexusInfo *nexus_info,ExceptionInfo *exception)
3787%
3788% A description of each parameter follows:
3789%
3790% o image: the image.
3791%
3792% o nexus_info: the cache nexus to clip.
3793%
3794% o exception: return any errors or warnings in this structure.
3795%
3796*/
3797
cristy3aa93752011-12-18 15:54:24 +00003798static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3799 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003800{
3801 MagickRealType
3802 gamma;
3803
cristyaa83c2c2011-09-21 13:36:25 +00003804 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003805 {
3806 *composite=(*q);
3807 return;
3808 }
3809 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3810 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003811 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3812 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3813 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003814 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003815 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003816}
3817
3818static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3819 ExceptionInfo *exception)
3820{
3821 CacheInfo
3822 *cache_info;
3823
cristy4c08aed2011-07-01 19:47:50 +00003824 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003825 alpha,
3826 beta;
3827
3828 MagickSizeType
3829 number_pixels;
3830
3831 NexusInfo
3832 **clip_nexus,
3833 **image_nexus;
3834
cristy4c08aed2011-07-01 19:47:50 +00003835 register const Quantum
3836 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003837 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003838
cristy4c08aed2011-07-01 19:47:50 +00003839 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003840 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003841
cristye076a6e2010-08-15 19:59:43 +00003842 register ssize_t
3843 i;
3844
cristy3ed852e2009-09-05 21:47:34 +00003845 /*
3846 Apply clip mask.
3847 */
3848 if (image->debug != MagickFalse)
3849 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3850 if (image->mask == (Image *) NULL)
3851 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003852 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003853 if (cache_info == (Cache) NULL)
3854 return(MagickFalse);
3855 image_nexus=AcquirePixelCacheNexus(1);
3856 clip_nexus=AcquirePixelCacheNexus(1);
3857 if ((image_nexus == (NexusInfo **) NULL) ||
3858 (clip_nexus == (NexusInfo **) NULL))
3859 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003860 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3861 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3862 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003863 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003864 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3865 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003866 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003867 GetPixelInfo(image,&alpha);
3868 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003869 number_pixels=(MagickSizeType) nexus_info->region.width*
3870 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003871 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003872 {
cristy4c08aed2011-07-01 19:47:50 +00003873 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003874 break;
cristy803640d2011-11-17 02:11:32 +00003875 GetPixelInfoPixel(image,p,&alpha);
3876 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003877 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003878 &alpha,alpha.alpha,&beta);
3879 SetPixelRed(image,ClampToQuantum(beta.red),q);
3880 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3881 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3882 if (cache_info->colorspace == CMYKColorspace)
3883 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3884 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003885 p++;
3886 q++;
3887 r++;
3888 }
3889 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3890 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003891 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003892 return(MagickFalse);
3893 return(MagickTrue);
3894}
3895
3896/*
3897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3898% %
3899% %
3900% %
3901+ O p e n P i x e l C a c h e %
3902% %
3903% %
3904% %
3905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3906%
3907% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3908% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003909% metacontent, and memory mapping the cache if it is disk based. The cache
3910% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003911%
3912% The format of the OpenPixelCache() method is:
3913%
3914% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3915% ExceptionInfo *exception)
3916%
3917% A description of each parameter follows:
3918%
3919% o image: the image.
3920%
3921% o mode: ReadMode, WriteMode, or IOMode.
3922%
3923% o exception: return any errors or warnings in this structure.
3924%
3925*/
3926
cristyd43a46b2010-01-21 02:13:41 +00003927static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003928{
3929 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003930 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003931 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003932 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003933 {
3934 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003935 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003936 cache_info->length);
3937 }
3938}
3939
3940static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3941{
3942 CacheInfo
3943 *cache_info;
3944
3945 MagickOffsetType
3946 count,
3947 extent,
3948 offset;
3949
3950 cache_info=(CacheInfo *) image->cache;
3951 if (image->debug != MagickFalse)
3952 {
3953 char
3954 format[MaxTextExtent],
3955 message[MaxTextExtent];
3956
cristyb9080c92009-12-01 20:13:26 +00003957 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003958 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003959 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003960 cache_info->cache_filename,cache_info->file,format);
3961 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3962 }
3963 if (length != (MagickSizeType) ((MagickOffsetType) length))
3964 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003965 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003966 if (extent < 0)
3967 return(MagickFalse);
3968 if ((MagickSizeType) extent >= length)
3969 return(MagickTrue);
3970 offset=(MagickOffsetType) length-1;
3971 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3972 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3973}
3974
3975static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3976 ExceptionInfo *exception)
3977{
cristy3ed852e2009-09-05 21:47:34 +00003978 CacheInfo
3979 *cache_info,
3980 source_info;
3981
cristyf3a6a9d2010-11-07 21:02:56 +00003982 char
3983 format[MaxTextExtent],
3984 message[MaxTextExtent];
3985
cristy4c08aed2011-07-01 19:47:50 +00003986 MagickBooleanType
3987 status;
3988
cristy3ed852e2009-09-05 21:47:34 +00003989 MagickSizeType
3990 length,
3991 number_pixels;
3992
cristy3ed852e2009-09-05 21:47:34 +00003993 size_t
cristye076a6e2010-08-15 19:59:43 +00003994 columns,
cristy3ed852e2009-09-05 21:47:34 +00003995 packet_size;
3996
cristye7cc7cf2010-09-21 13:26:47 +00003997 assert(image != (const Image *) NULL);
3998 assert(image->signature == MagickSignature);
3999 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004000 if (image->debug != MagickFalse)
4001 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4002 if ((image->columns == 0) || (image->rows == 0))
4003 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4004 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004005 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004006 source_info=(*cache_info);
4007 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004008 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004009 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004010 cache_info->storage_class=image->storage_class;
4011 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004012 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004013 cache_info->rows=image->rows;
4014 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004015 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004016 cache_info->number_channels=GetPixelChannels(image);
cristy3dfccb22011-12-28 21:47:20 +00004017 (void) memcpy(cache_info->channel_map,image->channel_map,
4018 cache_info->number_channels*sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004019 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004020 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004021 if (image->ping != MagickFalse)
4022 {
cristy73724512010-04-12 14:43:14 +00004023 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004024 cache_info->pixels=(Quantum *) NULL;
4025 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004026 cache_info->length=0;
4027 return(MagickTrue);
4028 }
cristy3ed852e2009-09-05 21:47:34 +00004029 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004030 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004031 if (image->metacontent_extent != 0)
4032 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004033 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004034 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004035 if (cache_info->columns != columns)
4036 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4037 image->filename);
4038 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004039 if ((cache_info->type != UndefinedCache) &&
4040 (cache_info->columns <= source_info.columns) &&
4041 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004042 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004043 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4044 {
4045 /*
4046 Inline pixel cache clone optimization.
4047 */
4048 if ((cache_info->columns == source_info.columns) &&
4049 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004050 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004051 (cache_info->metacontent_extent == source_info.metacontent_extent))
4052 return(MagickTrue);
4053 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4054 }
cristy3ed852e2009-09-05 21:47:34 +00004055 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004056 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004057 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004058 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4059 {
4060 status=AcquireMagickResource(MemoryResource,cache_info->length);
4061 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4062 (cache_info->type == MemoryCache))
4063 {
cristyd43a46b2010-01-21 02:13:41 +00004064 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004065 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004066 cache_info->pixels=source_info.pixels;
4067 else
4068 {
4069 /*
4070 Create memory pixel cache.
4071 */
cristy4c08aed2011-07-01 19:47:50 +00004072 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004073 if (image->debug != MagickFalse)
4074 {
cristy97e7a572009-12-05 15:07:53 +00004075 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004076 format);
cristyb51dff52011-05-19 16:55:47 +00004077 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004078 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4079 cache_info->filename,cache_info->mapped != MagickFalse ?
4080 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004081 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004082 format);
cristy3ed852e2009-09-05 21:47:34 +00004083 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4084 message);
4085 }
cristy3ed852e2009-09-05 21:47:34 +00004086 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004087 cache_info->metacontent=(void *) NULL;
4088 if (cache_info->metacontent_extent != 0)
4089 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004090 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004091 if (source_info.storage_class != UndefinedClass)
4092 {
cristy4c08aed2011-07-01 19:47:50 +00004093 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004094 exception);
4095 RelinquishPixelCachePixels(&source_info);
4096 }
cristy4c08aed2011-07-01 19:47:50 +00004097 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004098 }
4099 }
4100 RelinquishMagickResource(MemoryResource,cache_info->length);
4101 }
4102 /*
4103 Create pixel cache on disk.
4104 */
4105 status=AcquireMagickResource(DiskResource,cache_info->length);
4106 if (status == MagickFalse)
4107 {
4108 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4109 "CacheResourcesExhausted","`%s'",image->filename);
4110 return(MagickFalse);
4111 }
4112 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4113 {
4114 RelinquishMagickResource(DiskResource,cache_info->length);
4115 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4116 image->filename);
4117 return(MagickFalse);
4118 }
4119 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4120 cache_info->length);
4121 if (status == MagickFalse)
4122 {
4123 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4124 image->filename);
4125 return(MagickFalse);
4126 }
cristyed231572011-07-14 02:18:59 +00004127 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004128 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004129 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004130 cache_info->type=DiskCache;
4131 else
4132 {
4133 status=AcquireMagickResource(MapResource,cache_info->length);
4134 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4135 (cache_info->type != MemoryCache))
4136 cache_info->type=DiskCache;
4137 else
4138 {
cristy4c08aed2011-07-01 19:47:50 +00004139 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004140 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004141 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004142 {
cristy3ed852e2009-09-05 21:47:34 +00004143 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004144 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004145 }
4146 else
4147 {
4148 /*
4149 Create file-backed memory-mapped pixel cache.
4150 */
cristy4c08aed2011-07-01 19:47:50 +00004151 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004152 (void) ClosePixelCacheOnDisk(cache_info);
4153 cache_info->type=MapCache;
4154 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004155 cache_info->metacontent=(void *) NULL;
4156 if (cache_info->metacontent_extent != 0)
4157 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004158 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004159 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004160 {
4161 status=ClonePixelCachePixels(cache_info,&source_info,
4162 exception);
4163 RelinquishPixelCachePixels(&source_info);
4164 }
4165 if (image->debug != MagickFalse)
4166 {
cristy97e7a572009-12-05 15:07:53 +00004167 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004168 format);
cristyb51dff52011-05-19 16:55:47 +00004169 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004170 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004171 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004172 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004173 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004174 format);
cristy3ed852e2009-09-05 21:47:34 +00004175 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4176 message);
4177 }
cristy4c08aed2011-07-01 19:47:50 +00004178 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004179 }
4180 }
4181 RelinquishMagickResource(MapResource,cache_info->length);
4182 }
cristy4c08aed2011-07-01 19:47:50 +00004183 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004184 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4185 {
4186 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4187 RelinquishPixelCachePixels(&source_info);
4188 }
4189 if (image->debug != MagickFalse)
4190 {
cristyb9080c92009-12-01 20:13:26 +00004191 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004192 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004193 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004194 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004195 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004196 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004197 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4198 }
cristy4c08aed2011-07-01 19:47:50 +00004199 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004200}
4201
4202/*
4203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4204% %
4205% %
4206% %
4207+ P e r s i s t P i x e l C a c h e %
4208% %
4209% %
4210% %
4211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4212%
4213% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4214% persistent pixel cache is one that resides on disk and is not destroyed
4215% when the program exits.
4216%
4217% The format of the PersistPixelCache() method is:
4218%
4219% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4220% const MagickBooleanType attach,MagickOffsetType *offset,
4221% ExceptionInfo *exception)
4222%
4223% A description of each parameter follows:
4224%
4225% o image: the image.
4226%
4227% o filename: the persistent pixel cache filename.
4228%
cristyf3a6a9d2010-11-07 21:02:56 +00004229% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004230%
cristy3ed852e2009-09-05 21:47:34 +00004231% o initialize: A value other than zero initializes the persistent pixel
4232% cache.
4233%
4234% o offset: the offset in the persistent cache to store pixels.
4235%
4236% o exception: return any errors or warnings in this structure.
4237%
4238*/
4239MagickExport MagickBooleanType PersistPixelCache(Image *image,
4240 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4241 ExceptionInfo *exception)
4242{
4243 CacheInfo
4244 *cache_info,
4245 *clone_info;
4246
4247 Image
4248 clone_image;
4249
cristy3ed852e2009-09-05 21:47:34 +00004250 MagickBooleanType
4251 status;
4252
cristye076a6e2010-08-15 19:59:43 +00004253 ssize_t
4254 page_size;
4255
cristy3ed852e2009-09-05 21:47:34 +00004256 assert(image != (Image *) NULL);
4257 assert(image->signature == MagickSignature);
4258 if (image->debug != MagickFalse)
4259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4260 assert(image->cache != (void *) NULL);
4261 assert(filename != (const char *) NULL);
4262 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004263 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004264 cache_info=(CacheInfo *) image->cache;
4265 assert(cache_info->signature == MagickSignature);
4266 if (attach != MagickFalse)
4267 {
4268 /*
cristy01b7eb02009-09-10 23:10:14 +00004269 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004270 */
4271 if (image->debug != MagickFalse)
4272 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004273 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004274 (void) CopyMagickString(cache_info->cache_filename,filename,
4275 MaxTextExtent);
4276 cache_info->type=DiskCache;
4277 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004278 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004279 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004280 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004281 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004282 }
cristy01b7eb02009-09-10 23:10:14 +00004283 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4284 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004285 {
cristyf84a1932010-01-03 18:00:18 +00004286 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004287 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004288 (cache_info->reference_count == 1))
4289 {
4290 int
4291 status;
4292
4293 /*
cristy01b7eb02009-09-10 23:10:14 +00004294 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004295 */
cristy320684d2011-09-23 14:55:47 +00004296 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004297 if (status == 0)
4298 {
4299 (void) CopyMagickString(cache_info->cache_filename,filename,
4300 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004301 *offset+=cache_info->length+page_size-(cache_info->length %
4302 page_size);
cristyf84a1932010-01-03 18:00:18 +00004303 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004304 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004305 if (image->debug != MagickFalse)
4306 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4307 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004308 return(MagickTrue);
4309 }
4310 }
cristyf84a1932010-01-03 18:00:18 +00004311 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004312 }
4313 /*
cristy01b7eb02009-09-10 23:10:14 +00004314 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004315 */
4316 clone_image=(*image);
4317 clone_info=(CacheInfo *) clone_image.cache;
4318 image->cache=ClonePixelCache(cache_info);
4319 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4320 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4321 cache_info->type=DiskCache;
4322 cache_info->offset=(*offset);
4323 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004324 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004325 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004326 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004327 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004328 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4329 return(status);
4330}
4331
4332/*
4333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4334% %
4335% %
4336% %
4337+ Q u e u e A u t h e n t i c N e x u s %
4338% %
4339% %
4340% %
4341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4342%
4343% QueueAuthenticNexus() allocates an region to store image pixels as defined
4344% by the region rectangle and returns a pointer to the region. This region is
4345% subsequently transferred from the pixel cache with
4346% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4347% pixels are transferred, otherwise a NULL is returned.
4348%
4349% The format of the QueueAuthenticNexus() method is:
4350%
cristy4c08aed2011-07-01 19:47:50 +00004351% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004352% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004353% const MagickBooleanType clone,NexusInfo *nexus_info,
4354% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004355%
4356% A description of each parameter follows:
4357%
4358% o image: the image.
4359%
4360% o x,y,columns,rows: These values define the perimeter of a region of
4361% pixels.
4362%
4363% o nexus_info: the cache nexus to set.
4364%
cristy65dbf172011-10-06 17:32:04 +00004365% o clone: clone the pixel cache.
4366%
cristy3ed852e2009-09-05 21:47:34 +00004367% o exception: return any errors or warnings in this structure.
4368%
4369*/
cristya6577ff2011-09-02 19:54:26 +00004370MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004371 const ssize_t y,const size_t columns,const size_t rows,
4372 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004373{
4374 CacheInfo
4375 *cache_info;
4376
4377 MagickOffsetType
4378 offset;
4379
4380 MagickSizeType
4381 number_pixels;
4382
4383 RectangleInfo
4384 region;
4385
4386 /*
4387 Validate pixel cache geometry.
4388 */
cristye7cc7cf2010-09-21 13:26:47 +00004389 assert(image != (const Image *) NULL);
4390 assert(image->signature == MagickSignature);
4391 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004392 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004393 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004394 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004395 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004396 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4397 {
4398 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4399 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004400 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004401 }
cristybb503372010-05-27 20:51:26 +00004402 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4403 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004404 {
4405 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4406 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004407 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004408 }
4409 offset=(MagickOffsetType) y*cache_info->columns+x;
4410 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004411 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004412 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4413 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4414 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004415 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004416 /*
4417 Return pixel cache.
4418 */
4419 region.x=x;
4420 region.y=y;
4421 region.width=columns;
4422 region.height=rows;
4423 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4424}
4425
4426/*
4427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4428% %
4429% %
4430% %
4431+ 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 %
4432% %
4433% %
4434% %
4435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4436%
4437% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4438% defined by the region rectangle and returns a pointer to the region. This
4439% region is subsequently transferred from the pixel cache with
4440% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4441% pixels are transferred, otherwise a NULL is returned.
4442%
4443% The format of the QueueAuthenticPixelsCache() method is:
4444%
cristy4c08aed2011-07-01 19:47:50 +00004445% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004446% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004447% ExceptionInfo *exception)
4448%
4449% A description of each parameter follows:
4450%
4451% o image: the image.
4452%
4453% o x,y,columns,rows: These values define the perimeter of a region of
4454% pixels.
4455%
4456% o exception: return any errors or warnings in this structure.
4457%
4458*/
cristy4c08aed2011-07-01 19:47:50 +00004459static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004460 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004461 ExceptionInfo *exception)
4462{
4463 CacheInfo
4464 *cache_info;
4465
cristy5c9e6f22010-09-17 17:31:01 +00004466 const int
4467 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004468
cristy4c08aed2011-07-01 19:47:50 +00004469 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004470 *q;
cristy4c08aed2011-07-01 19:47:50 +00004471
cristye7cc7cf2010-09-21 13:26:47 +00004472 assert(image != (const Image *) NULL);
4473 assert(image->signature == MagickSignature);
4474 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004475 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004476 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004477 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004478 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4479 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004480 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004481}
4482
4483/*
4484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4485% %
4486% %
4487% %
4488% Q u e u e A u t h e n t i c P i x e l s %
4489% %
4490% %
4491% %
4492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493%
4494% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004495% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004496% region is returned, otherwise NULL is returned. The returned pointer may
4497% point to a temporary working buffer for the pixels or it may point to the
4498% final location of the pixels in memory.
4499%
4500% Write-only access means that any existing pixel values corresponding to
4501% the region are ignored. This is useful if the initial image is being
4502% created from scratch, or if the existing pixel values are to be
4503% completely replaced without need to refer to their pre-existing values.
4504% The application is free to read and write the pixel buffer returned by
4505% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4506% initialize the pixel array values. Initializing pixel array values is the
4507% application's responsibility.
4508%
4509% Performance is maximized if the selected region is part of one row, or
4510% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004511% pixels in-place (without a copy) if the image is in memory, or in a
4512% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004513% by the user.
4514%
4515% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004516% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4517% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4518% obtain the meta-content (of type void) corresponding to the region.
4519% Once the Quantum (and/or Quantum) array has been updated, the
4520% changes must be saved back to the underlying image using
4521% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004522%
4523% The format of the QueueAuthenticPixels() method is:
4524%
cristy4c08aed2011-07-01 19:47:50 +00004525% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004526% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004527% ExceptionInfo *exception)
4528%
4529% A description of each parameter follows:
4530%
4531% o image: the image.
4532%
4533% o x,y,columns,rows: These values define the perimeter of a region of
4534% pixels.
4535%
4536% o exception: return any errors or warnings in this structure.
4537%
4538*/
cristy4c08aed2011-07-01 19:47:50 +00004539MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004540 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004541 ExceptionInfo *exception)
4542{
4543 CacheInfo
4544 *cache_info;
4545
cristy2036f5c2010-09-19 21:18:17 +00004546 const int
4547 id = GetOpenMPThreadId();
4548
cristy4c08aed2011-07-01 19:47:50 +00004549 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004550 *q;
cristy4c08aed2011-07-01 19:47:50 +00004551
cristy3ed852e2009-09-05 21:47:34 +00004552 assert(image != (Image *) NULL);
4553 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004554 assert(image->cache != (Cache) NULL);
4555 cache_info=(CacheInfo *) image->cache;
4556 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004557 if (cache_info->methods.queue_authentic_pixels_handler !=
4558 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004559 {
cristyacd2ed22011-08-30 01:44:23 +00004560 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004561 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004562 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004563 }
cristy2036f5c2010-09-19 21:18:17 +00004564 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004565 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4566 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004567 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004568}
4569
4570/*
4571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4572% %
4573% %
4574% %
cristy4c08aed2011-07-01 19:47:50 +00004575+ 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 +00004576% %
4577% %
4578% %
4579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4580%
cristy4c08aed2011-07-01 19:47:50 +00004581% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004582% the pixel cache.
4583%
cristy4c08aed2011-07-01 19:47:50 +00004584% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004585%
cristy4c08aed2011-07-01 19:47:50 +00004586% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004587% NexusInfo *nexus_info,ExceptionInfo *exception)
4588%
4589% A description of each parameter follows:
4590%
4591% o cache_info: the pixel cache.
4592%
cristy4c08aed2011-07-01 19:47:50 +00004593% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004594%
4595% o exception: return any errors or warnings in this structure.
4596%
4597*/
cristy4c08aed2011-07-01 19:47:50 +00004598static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004599 NexusInfo *nexus_info,ExceptionInfo *exception)
4600{
4601 MagickOffsetType
4602 count,
4603 offset;
4604
4605 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004606 extent,
4607 length;
cristy3ed852e2009-09-05 21:47:34 +00004608
cristybb503372010-05-27 20:51:26 +00004609 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004610 y;
4611
cristy4c08aed2011-07-01 19:47:50 +00004612 register unsigned char
4613 *restrict q;
4614
cristybb503372010-05-27 20:51:26 +00004615 size_t
cristy3ed852e2009-09-05 21:47:34 +00004616 rows;
4617
cristy4c08aed2011-07-01 19:47:50 +00004618 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004619 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004620 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004621 return(MagickTrue);
4622 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4623 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004624 length=(MagickSizeType) nexus_info->region.width*
4625 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004626 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004627 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004628 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004629 switch (cache_info->type)
4630 {
4631 case MemoryCache:
4632 case MapCache:
4633 {
cristy4c08aed2011-07-01 19:47:50 +00004634 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004635 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004636
4637 /*
cristy4c08aed2011-07-01 19:47:50 +00004638 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004639 */
cristydd341db2010-03-04 19:06:38 +00004640 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004641 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004642 {
cristy48078b12010-09-23 17:11:01 +00004643 length=extent;
cristydd341db2010-03-04 19:06:38 +00004644 rows=1UL;
4645 }
cristy4c08aed2011-07-01 19:47:50 +00004646 p=(unsigned char *) cache_info->metacontent+offset*
4647 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004648 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004649 {
cristy8f036fe2010-09-18 02:02:00 +00004650 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004651 p+=cache_info->metacontent_extent*cache_info->columns;
4652 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004653 }
4654 break;
4655 }
4656 case DiskCache:
4657 {
4658 /*
cristy4c08aed2011-07-01 19:47:50 +00004659 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004660 */
4661 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4662 {
4663 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4664 cache_info->cache_filename);
4665 return(MagickFalse);
4666 }
cristydd341db2010-03-04 19:06:38 +00004667 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004668 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004669 {
cristy48078b12010-09-23 17:11:01 +00004670 length=extent;
cristydd341db2010-03-04 19:06:38 +00004671 rows=1UL;
4672 }
cristy48078b12010-09-23 17:11:01 +00004673 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004674 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004675 {
cristy48078b12010-09-23 17:11:01 +00004676 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004677 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004678 cache_info->metacontent_extent,length,(unsigned char *) q);
4679 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004680 break;
4681 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004682 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004683 }
cristybb503372010-05-27 20:51:26 +00004684 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004685 {
4686 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4687 cache_info->cache_filename);
4688 return(MagickFalse);
4689 }
4690 break;
4691 }
4692 default:
4693 break;
4694 }
4695 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004696 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004698 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004699 nexus_info->region.width,(double) nexus_info->region.height,(double)
4700 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004701 return(MagickTrue);
4702}
4703
4704/*
4705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4706% %
4707% %
4708% %
4709+ R e a d P i x e l C a c h e P i x e l s %
4710% %
4711% %
4712% %
4713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4714%
4715% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4716% cache.
4717%
4718% The format of the ReadPixelCachePixels() method is:
4719%
4720% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4721% NexusInfo *nexus_info,ExceptionInfo *exception)
4722%
4723% A description of each parameter follows:
4724%
4725% o cache_info: the pixel cache.
4726%
4727% o nexus_info: the cache nexus to read the pixels.
4728%
4729% o exception: return any errors or warnings in this structure.
4730%
4731*/
4732static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4733 NexusInfo *nexus_info,ExceptionInfo *exception)
4734{
4735 MagickOffsetType
4736 count,
4737 offset;
4738
4739 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004740 extent,
4741 length;
cristy3ed852e2009-09-05 21:47:34 +00004742
cristy4c08aed2011-07-01 19:47:50 +00004743 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004744 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004745
cristye076a6e2010-08-15 19:59:43 +00004746 register ssize_t
4747 y;
4748
cristybb503372010-05-27 20:51:26 +00004749 size_t
cristy3ed852e2009-09-05 21:47:34 +00004750 rows;
4751
cristy4c08aed2011-07-01 19:47:50 +00004752 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004753 return(MagickTrue);
4754 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4755 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004756 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004757 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004758 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004759 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004760 q=nexus_info->pixels;
4761 switch (cache_info->type)
4762 {
4763 case MemoryCache:
4764 case MapCache:
4765 {
cristy4c08aed2011-07-01 19:47:50 +00004766 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004767 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004768
4769 /*
4770 Read pixels from memory.
4771 */
cristydd341db2010-03-04 19:06:38 +00004772 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004773 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004774 {
cristy48078b12010-09-23 17:11:01 +00004775 length=extent;
cristydd341db2010-03-04 19:06:38 +00004776 rows=1UL;
4777 }
cristyed231572011-07-14 02:18:59 +00004778 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004779 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004780 {
cristy8f036fe2010-09-18 02:02:00 +00004781 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004782 p+=cache_info->number_channels*cache_info->columns;
4783 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004784 }
4785 break;
4786 }
4787 case DiskCache:
4788 {
4789 /*
4790 Read pixels from disk.
4791 */
4792 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4793 {
4794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4795 cache_info->cache_filename);
4796 return(MagickFalse);
4797 }
cristydd341db2010-03-04 19:06:38 +00004798 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004799 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004800 {
cristy48078b12010-09-23 17:11:01 +00004801 length=extent;
cristydd341db2010-03-04 19:06:38 +00004802 rows=1UL;
4803 }
cristybb503372010-05-27 20:51:26 +00004804 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004805 {
4806 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004807 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004808 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004809 break;
4810 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004811 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004812 }
cristybb503372010-05-27 20:51:26 +00004813 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004814 {
4815 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4816 cache_info->cache_filename);
4817 return(MagickFalse);
4818 }
4819 break;
4820 }
4821 default:
4822 break;
4823 }
4824 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004825 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004826 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004827 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004828 nexus_info->region.width,(double) nexus_info->region.height,(double)
4829 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004830 return(MagickTrue);
4831}
4832
4833/*
4834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4835% %
4836% %
4837% %
4838+ R e f e r e n c e P i x e l C a c h e %
4839% %
4840% %
4841% %
4842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4843%
4844% ReferencePixelCache() increments the reference count associated with the
4845% pixel cache returning a pointer to the cache.
4846%
4847% The format of the ReferencePixelCache method is:
4848%
4849% Cache ReferencePixelCache(Cache cache_info)
4850%
4851% A description of each parameter follows:
4852%
4853% o cache_info: the pixel cache.
4854%
4855*/
cristya6577ff2011-09-02 19:54:26 +00004856MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004857{
4858 CacheInfo
4859 *cache_info;
4860
4861 assert(cache != (Cache *) NULL);
4862 cache_info=(CacheInfo *) cache;
4863 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004864 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004865 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004866 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004867 return(cache_info);
4868}
4869
4870/*
4871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4872% %
4873% %
4874% %
4875+ S e t P i x e l C a c h e M e t h o d s %
4876% %
4877% %
4878% %
4879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4880%
4881% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4882%
4883% The format of the SetPixelCacheMethods() method is:
4884%
4885% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4886%
4887% A description of each parameter follows:
4888%
4889% o cache: the pixel cache.
4890%
4891% o cache_methods: Specifies a pointer to a CacheMethods structure.
4892%
4893*/
cristya6577ff2011-09-02 19:54:26 +00004894MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004895{
4896 CacheInfo
4897 *cache_info;
4898
4899 GetOneAuthenticPixelFromHandler
4900 get_one_authentic_pixel_from_handler;
4901
4902 GetOneVirtualPixelFromHandler
4903 get_one_virtual_pixel_from_handler;
4904
4905 /*
4906 Set cache pixel methods.
4907 */
4908 assert(cache != (Cache) NULL);
4909 assert(cache_methods != (CacheMethods *) NULL);
4910 cache_info=(CacheInfo *) cache;
4911 assert(cache_info->signature == MagickSignature);
4912 if (cache_info->debug != MagickFalse)
4913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4914 cache_info->filename);
4915 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4916 cache_info->methods.get_virtual_pixel_handler=
4917 cache_methods->get_virtual_pixel_handler;
4918 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4919 cache_info->methods.destroy_pixel_handler=
4920 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004921 if (cache_methods->get_virtual_metacontent_from_handler !=
4922 (GetVirtualMetacontentFromHandler) NULL)
4923 cache_info->methods.get_virtual_metacontent_from_handler=
4924 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004925 if (cache_methods->get_authentic_pixels_handler !=
4926 (GetAuthenticPixelsHandler) NULL)
4927 cache_info->methods.get_authentic_pixels_handler=
4928 cache_methods->get_authentic_pixels_handler;
4929 if (cache_methods->queue_authentic_pixels_handler !=
4930 (QueueAuthenticPixelsHandler) NULL)
4931 cache_info->methods.queue_authentic_pixels_handler=
4932 cache_methods->queue_authentic_pixels_handler;
4933 if (cache_methods->sync_authentic_pixels_handler !=
4934 (SyncAuthenticPixelsHandler) NULL)
4935 cache_info->methods.sync_authentic_pixels_handler=
4936 cache_methods->sync_authentic_pixels_handler;
4937 if (cache_methods->get_authentic_pixels_from_handler !=
4938 (GetAuthenticPixelsFromHandler) NULL)
4939 cache_info->methods.get_authentic_pixels_from_handler=
4940 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004941 if (cache_methods->get_authentic_metacontent_from_handler !=
4942 (GetAuthenticMetacontentFromHandler) NULL)
4943 cache_info->methods.get_authentic_metacontent_from_handler=
4944 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004945 get_one_virtual_pixel_from_handler=
4946 cache_info->methods.get_one_virtual_pixel_from_handler;
4947 if (get_one_virtual_pixel_from_handler !=
4948 (GetOneVirtualPixelFromHandler) NULL)
4949 cache_info->methods.get_one_virtual_pixel_from_handler=
4950 cache_methods->get_one_virtual_pixel_from_handler;
4951 get_one_authentic_pixel_from_handler=
4952 cache_methods->get_one_authentic_pixel_from_handler;
4953 if (get_one_authentic_pixel_from_handler !=
4954 (GetOneAuthenticPixelFromHandler) NULL)
4955 cache_info->methods.get_one_authentic_pixel_from_handler=
4956 cache_methods->get_one_authentic_pixel_from_handler;
4957}
4958
4959/*
4960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4961% %
4962% %
4963% %
4964+ S e t P i x e l C a c h e N e x u s P i x e l s %
4965% %
4966% %
4967% %
4968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4969%
4970% SetPixelCacheNexusPixels() defines the region of the cache for the
4971% specified cache nexus.
4972%
4973% The format of the SetPixelCacheNexusPixels() method is:
4974%
cristy4c08aed2011-07-01 19:47:50 +00004975% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004976% const RectangleInfo *region,NexusInfo *nexus_info,
4977% ExceptionInfo *exception)
4978%
4979% A description of each parameter follows:
4980%
4981% o image: the image.
4982%
4983% o region: A pointer to the RectangleInfo structure that defines the
4984% region of this particular cache nexus.
4985%
4986% o nexus_info: the cache nexus to set.
4987%
4988% o exception: return any errors or warnings in this structure.
4989%
4990*/
cristyabd6e372010-09-15 19:11:26 +00004991
4992static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4993 NexusInfo *nexus_info,ExceptionInfo *exception)
4994{
4995 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4996 return(MagickFalse);
4997 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00004998 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004999 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005000 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005001 {
5002 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005003 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005004 nexus_info->length);
5005 }
cristy4c08aed2011-07-01 19:47:50 +00005006 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005007 {
5008 (void) ThrowMagickException(exception,GetMagickModule(),
5009 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5010 cache_info->filename);
5011 return(MagickFalse);
5012 }
5013 return(MagickTrue);
5014}
5015
cristy4c08aed2011-07-01 19:47:50 +00005016static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005017 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5018{
5019 CacheInfo
5020 *cache_info;
5021
5022 MagickBooleanType
5023 status;
5024
cristy3ed852e2009-09-05 21:47:34 +00005025 MagickSizeType
5026 length,
5027 number_pixels;
5028
cristy3ed852e2009-09-05 21:47:34 +00005029 cache_info=(CacheInfo *) image->cache;
5030 assert(cache_info->signature == MagickSignature);
5031 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005032 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005033 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005034 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5035 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005036 {
cristybb503372010-05-27 20:51:26 +00005037 ssize_t
cristybad067a2010-02-15 17:20:55 +00005038 x,
5039 y;
cristy3ed852e2009-09-05 21:47:34 +00005040
cristyeaedf062010-05-29 22:36:02 +00005041 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5042 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005043 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5044 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005045 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005046 ((nexus_info->region.width == cache_info->columns) ||
5047 ((nexus_info->region.width % cache_info->columns) == 0)))))
5048 {
5049 MagickOffsetType
5050 offset;
5051
5052 /*
5053 Pixels are accessed directly from memory.
5054 */
5055 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5056 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005057 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005058 offset;
5059 nexus_info->metacontent=(void *) NULL;
5060 if (cache_info->metacontent_extent != 0)
5061 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5062 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005063 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005064 }
5065 }
5066 /*
5067 Pixels are stored in a cache region until they are synced to the cache.
5068 */
5069 number_pixels=(MagickSizeType) nexus_info->region.width*
5070 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005071 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005072 if (cache_info->metacontent_extent != 0)
5073 length+=number_pixels*cache_info->metacontent_extent;
5074 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005075 {
5076 nexus_info->length=length;
5077 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5078 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005079 {
5080 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005081 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005082 }
cristy3ed852e2009-09-05 21:47:34 +00005083 }
5084 else
5085 if (nexus_info->length != length)
5086 {
5087 RelinquishCacheNexusPixels(nexus_info);
5088 nexus_info->length=length;
5089 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5090 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005091 {
5092 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005093 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005094 }
cristy3ed852e2009-09-05 21:47:34 +00005095 }
5096 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005097 nexus_info->metacontent=(void *) NULL;
5098 if (cache_info->metacontent_extent != 0)
5099 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005100 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005101 return(nexus_info->pixels);
5102}
5103
5104/*
5105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5106% %
5107% %
5108% %
5109% 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 %
5110% %
5111% %
5112% %
5113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5114%
5115% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5116% pixel cache and returns the previous setting. A virtual pixel is any pixel
5117% access that is outside the boundaries of the image cache.
5118%
5119% The format of the SetPixelCacheVirtualMethod() method is:
5120%
5121% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5122% const VirtualPixelMethod virtual_pixel_method)
5123%
5124% A description of each parameter follows:
5125%
5126% o image: the image.
5127%
5128% o virtual_pixel_method: choose the type of virtual pixel.
5129%
5130*/
cristyd1dd6e42011-09-04 01:46:08 +00005131MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005132 const VirtualPixelMethod virtual_pixel_method)
5133{
5134 CacheInfo
5135 *cache_info;
5136
5137 VirtualPixelMethod
5138 method;
5139
5140 assert(image != (Image *) NULL);
5141 assert(image->signature == MagickSignature);
5142 if (image->debug != MagickFalse)
5143 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5144 assert(image->cache != (Cache) NULL);
5145 cache_info=(CacheInfo *) image->cache;
5146 assert(cache_info->signature == MagickSignature);
5147 method=cache_info->virtual_pixel_method;
5148 cache_info->virtual_pixel_method=virtual_pixel_method;
5149 return(method);
5150}
5151
5152/*
5153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5154% %
5155% %
5156% %
5157+ 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 %
5158% %
5159% %
5160% %
5161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5162%
5163% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5164% in-memory or disk cache. The method returns MagickTrue if the pixel region
5165% is synced, otherwise MagickFalse.
5166%
5167% The format of the SyncAuthenticPixelCacheNexus() method is:
5168%
5169% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5170% NexusInfo *nexus_info,ExceptionInfo *exception)
5171%
5172% A description of each parameter follows:
5173%
5174% o image: the image.
5175%
5176% o nexus_info: the cache nexus to sync.
5177%
5178% o exception: return any errors or warnings in this structure.
5179%
5180*/
cristya6577ff2011-09-02 19:54:26 +00005181MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005182 NexusInfo *nexus_info,ExceptionInfo *exception)
5183{
5184 CacheInfo
5185 *cache_info;
5186
5187 MagickBooleanType
5188 status;
5189
5190 /*
5191 Transfer pixels to the cache.
5192 */
5193 assert(image != (Image *) NULL);
5194 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005195 if (image->cache == (Cache) NULL)
5196 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5197 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005198 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005199 if (cache_info->type == UndefinedCache)
5200 return(MagickFalse);
5201 if ((image->clip_mask != (Image *) NULL) &&
5202 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5203 return(MagickFalse);
5204 if ((image->mask != (Image *) NULL) &&
5205 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5206 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005207 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005208 return(MagickTrue);
5209 assert(cache_info->signature == MagickSignature);
5210 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005211 if ((cache_info->metacontent_extent != 0) &&
5212 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005213 return(MagickFalse);
5214 return(status);
5215}
5216
5217/*
5218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5219% %
5220% %
5221% %
5222+ S y n c A u t h e n t i c P i x e l C a c h e %
5223% %
5224% %
5225% %
5226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5227%
5228% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5229% or disk cache. The method returns MagickTrue if the pixel region is synced,
5230% otherwise MagickFalse.
5231%
5232% The format of the SyncAuthenticPixelsCache() method is:
5233%
5234% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5235% ExceptionInfo *exception)
5236%
5237% A description of each parameter follows:
5238%
5239% o image: the image.
5240%
5241% o exception: return any errors or warnings in this structure.
5242%
5243*/
5244static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5245 ExceptionInfo *exception)
5246{
5247 CacheInfo
5248 *cache_info;
5249
cristy5c9e6f22010-09-17 17:31:01 +00005250 const int
5251 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005252
cristy4c08aed2011-07-01 19:47:50 +00005253 MagickBooleanType
5254 status;
5255
cristye7cc7cf2010-09-21 13:26:47 +00005256 assert(image != (Image *) NULL);
5257 assert(image->signature == MagickSignature);
5258 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005259 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005260 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005261 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005262 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5263 exception);
5264 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005265}
5266
5267/*
5268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5269% %
5270% %
5271% %
5272% S y n c A u t h e n t i c P i x e l s %
5273% %
5274% %
5275% %
5276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5277%
5278% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5279% The method returns MagickTrue if the pixel region is flushed, otherwise
5280% MagickFalse.
5281%
5282% The format of the SyncAuthenticPixels() method is:
5283%
5284% MagickBooleanType SyncAuthenticPixels(Image *image,
5285% ExceptionInfo *exception)
5286%
5287% A description of each parameter follows:
5288%
5289% o image: the image.
5290%
5291% o exception: return any errors or warnings in this structure.
5292%
5293*/
5294MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5295 ExceptionInfo *exception)
5296{
5297 CacheInfo
5298 *cache_info;
5299
cristy2036f5c2010-09-19 21:18:17 +00005300 const int
5301 id = GetOpenMPThreadId();
5302
cristy4c08aed2011-07-01 19:47:50 +00005303 MagickBooleanType
5304 status;
5305
cristy3ed852e2009-09-05 21:47:34 +00005306 assert(image != (Image *) NULL);
5307 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005308 assert(image->cache != (Cache) NULL);
5309 cache_info=(CacheInfo *) image->cache;
5310 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005311 if (cache_info->methods.sync_authentic_pixels_handler !=
5312 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005313 {
5314 status=cache_info->methods.sync_authentic_pixels_handler(image,
5315 exception);
5316 return(status);
5317 }
cristy2036f5c2010-09-19 21:18:17 +00005318 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005319 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5320 exception);
5321 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005322}
5323
5324/*
5325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5326% %
5327% %
5328% %
cristyd1dd6e42011-09-04 01:46:08 +00005329+ 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 +00005330% %
5331% %
5332% %
5333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5334%
5335% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5336% The method returns MagickTrue if the pixel region is flushed, otherwise
5337% MagickFalse.
5338%
5339% The format of the SyncImagePixelCache() method is:
5340%
5341% MagickBooleanType SyncImagePixelCache(Image *image,
5342% ExceptionInfo *exception)
5343%
5344% A description of each parameter follows:
5345%
5346% o image: the image.
5347%
5348% o exception: return any errors or warnings in this structure.
5349%
5350*/
cristyd1dd6e42011-09-04 01:46:08 +00005351MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005352 ExceptionInfo *exception)
5353{
5354 CacheInfo
5355 *cache_info;
5356
5357 assert(image != (Image *) NULL);
5358 assert(exception != (ExceptionInfo *) NULL);
5359 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5360 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5361}
5362
5363/*
5364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5365% %
5366% %
5367% %
cristy4c08aed2011-07-01 19:47:50 +00005368+ 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 +00005369% %
5370% %
5371% %
5372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5373%
cristy4c08aed2011-07-01 19:47:50 +00005374% WritePixelCacheMetacontent() writes the meta-content to the specified region
5375% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005376%
cristy4c08aed2011-07-01 19:47:50 +00005377% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005378%
cristy4c08aed2011-07-01 19:47:50 +00005379% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005380% NexusInfo *nexus_info,ExceptionInfo *exception)
5381%
5382% A description of each parameter follows:
5383%
5384% o cache_info: the pixel cache.
5385%
cristy4c08aed2011-07-01 19:47:50 +00005386% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005387%
5388% o exception: return any errors or warnings in this structure.
5389%
5390*/
cristy4c08aed2011-07-01 19:47:50 +00005391static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005392 NexusInfo *nexus_info,ExceptionInfo *exception)
5393{
5394 MagickOffsetType
5395 count,
5396 offset;
5397
5398 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005399 extent,
5400 length;
cristy3ed852e2009-09-05 21:47:34 +00005401
cristy4c08aed2011-07-01 19:47:50 +00005402 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005403 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005404
cristybb503372010-05-27 20:51:26 +00005405 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005406 y;
5407
cristybb503372010-05-27 20:51:26 +00005408 size_t
cristy3ed852e2009-09-05 21:47:34 +00005409 rows;
5410
cristy4c08aed2011-07-01 19:47:50 +00005411 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005412 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005413 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005414 return(MagickTrue);
5415 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5416 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005417 length=(MagickSizeType) nexus_info->region.width*
5418 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005419 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005420 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005421 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005422 switch (cache_info->type)
5423 {
5424 case MemoryCache:
5425 case MapCache:
5426 {
cristy4c08aed2011-07-01 19:47:50 +00005427 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005428 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005429
5430 /*
cristy4c08aed2011-07-01 19:47:50 +00005431 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005432 */
cristydd341db2010-03-04 19:06:38 +00005433 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005434 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005435 {
cristy48078b12010-09-23 17:11:01 +00005436 length=extent;
cristydd341db2010-03-04 19:06:38 +00005437 rows=1UL;
5438 }
cristy4c08aed2011-07-01 19:47:50 +00005439 q=(unsigned char *) cache_info->metacontent+offset*
5440 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005441 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005442 {
cristy8f036fe2010-09-18 02:02:00 +00005443 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005444 p+=nexus_info->region.width*cache_info->metacontent_extent;
5445 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005446 }
5447 break;
5448 }
5449 case DiskCache:
5450 {
5451 /*
cristy4c08aed2011-07-01 19:47:50 +00005452 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005453 */
5454 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5455 {
5456 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5457 cache_info->cache_filename);
5458 return(MagickFalse);
5459 }
cristydd341db2010-03-04 19:06:38 +00005460 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005461 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005462 {
cristy48078b12010-09-23 17:11:01 +00005463 length=extent;
cristydd341db2010-03-04 19:06:38 +00005464 rows=1UL;
5465 }
cristy48078b12010-09-23 17:11:01 +00005466 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005467 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005468 {
cristy48078b12010-09-23 17:11:01 +00005469 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005470 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005471 cache_info->metacontent_extent,length,(const unsigned char *) p);
5472 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005473 break;
cristy4c08aed2011-07-01 19:47:50 +00005474 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005475 offset+=cache_info->columns;
5476 }
cristybb503372010-05-27 20:51:26 +00005477 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005478 {
5479 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5480 cache_info->cache_filename);
5481 return(MagickFalse);
5482 }
5483 break;
5484 }
5485 default:
5486 break;
5487 }
5488 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005489 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005490 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005491 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005492 nexus_info->region.width,(double) nexus_info->region.height,(double)
5493 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005494 return(MagickTrue);
5495}
5496
5497/*
5498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5499% %
5500% %
5501% %
5502+ W r i t e C a c h e P i x e l s %
5503% %
5504% %
5505% %
5506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5507%
5508% WritePixelCachePixels() writes image pixels to the specified region of the
5509% pixel cache.
5510%
5511% The format of the WritePixelCachePixels() method is:
5512%
5513% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5514% NexusInfo *nexus_info,ExceptionInfo *exception)
5515%
5516% A description of each parameter follows:
5517%
5518% o cache_info: the pixel cache.
5519%
5520% o nexus_info: the cache nexus to write the pixels.
5521%
5522% o exception: return any errors or warnings in this structure.
5523%
5524*/
5525static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5526 NexusInfo *nexus_info,ExceptionInfo *exception)
5527{
5528 MagickOffsetType
5529 count,
5530 offset;
5531
5532 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005533 extent,
5534 length;
cristy3ed852e2009-09-05 21:47:34 +00005535
cristy4c08aed2011-07-01 19:47:50 +00005536 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005537 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005538
cristybb503372010-05-27 20:51:26 +00005539 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005540 y;
5541
cristybb503372010-05-27 20:51:26 +00005542 size_t
cristy3ed852e2009-09-05 21:47:34 +00005543 rows;
5544
cristy4c08aed2011-07-01 19:47:50 +00005545 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005546 return(MagickTrue);
5547 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5548 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005549 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005550 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005551 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005552 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005553 p=nexus_info->pixels;
5554 switch (cache_info->type)
5555 {
5556 case MemoryCache:
5557 case MapCache:
5558 {
cristy4c08aed2011-07-01 19:47:50 +00005559 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005560 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005561
5562 /*
5563 Write pixels to memory.
5564 */
cristydd341db2010-03-04 19:06:38 +00005565 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005566 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005567 {
cristy48078b12010-09-23 17:11:01 +00005568 length=extent;
cristydd341db2010-03-04 19:06:38 +00005569 rows=1UL;
5570 }
cristyed231572011-07-14 02:18:59 +00005571 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005572 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005573 {
cristy8f036fe2010-09-18 02:02:00 +00005574 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005575 p+=nexus_info->region.width*cache_info->number_channels;
5576 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005577 }
5578 break;
5579 }
5580 case DiskCache:
5581 {
5582 /*
5583 Write pixels to disk.
5584 */
5585 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5586 {
5587 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5588 cache_info->cache_filename);
5589 return(MagickFalse);
5590 }
cristydd341db2010-03-04 19:06:38 +00005591 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005592 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005593 {
cristy48078b12010-09-23 17:11:01 +00005594 length=extent;
cristydd341db2010-03-04 19:06:38 +00005595 rows=1UL;
5596 }
cristybb503372010-05-27 20:51:26 +00005597 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005598 {
5599 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005600 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005601 p);
5602 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005603 break;
cristyed231572011-07-14 02:18:59 +00005604 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005605 offset+=cache_info->columns;
5606 }
cristybb503372010-05-27 20:51:26 +00005607 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005608 {
5609 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5610 cache_info->cache_filename);
5611 return(MagickFalse);
5612 }
5613 break;
5614 }
5615 default:
5616 break;
5617 }
5618 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005619 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005620 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005621 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005622 nexus_info->region.width,(double) nexus_info->region.height,(double)
5623 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005624 return(MagickTrue);
5625}