blob: c64769d49c81a5dbefe8aae3f8e66ac0c938362b [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78
79/*
cristy3ed852e2009-09-05 21:47:34 +000080 Typedef declarations.
81*/
82typedef struct _MagickModulo
83{
cristybb503372010-05-27 20:51:26 +000084 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000085 quotient,
86 remainder;
87} MagickModulo;
88
89struct _NexusInfo
90{
91 MagickBooleanType
92 mapped;
93
94 RectangleInfo
95 region;
96
97 MagickSizeType
98 length;
99
cristy4c08aed2011-07-01 19:47:50 +0000100 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000101 *cache,
102 *pixels;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 void
105 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000106
cristybb503372010-05-27 20:51:26 +0000107 size_t
cristy3ed852e2009-09-05 21:47:34 +0000108 signature;
109};
110
111/*
112 Forward declarations.
113*/
114#if defined(__cplusplus) || defined(c_plusplus)
115extern "C" {
116#endif
117
cristy4c08aed2011-07-01 19:47:50 +0000118static const Quantum
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
cristy4c08aed2011-07-01 19:47:50 +0000123static const void
124 *GetVirtualMetacontentFromCache(const Image *);
125
cristy3ed852e2009-09-05 21:47:34 +0000126static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
128 PixelPacket *,ExceptionInfo *),
129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
130 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
137
cristy4c08aed2011-07-01 19:47:50 +0000138static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000144 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146#if defined(__cplusplus) || defined(c_plusplus)
147}
148#endif
149
150/*
151 Global declarations.
152*/
153static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
155
156static SemaphoreInfo
157 *cache_semaphore = (SemaphoreInfo *) NULL;
158
159static SplayTreeInfo
160 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167+ A c q u i r e P i x e l C a c h e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquirePixelCache() acquires a pixel cache.
174%
175% The format of the AcquirePixelCache() method is:
176%
cristybb503372010-05-27 20:51:26 +0000177% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178%
179% A description of each parameter follows:
180%
181% o number_threads: the number of nexus threads.
182%
183*/
cristya6577ff2011-09-02 19:54:26 +0000184MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000185{
186 CacheInfo
187 *cache_info;
188
cristya64b85d2011-09-14 01:02:31 +0000189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000194 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristya6577ff2011-09-02 19:54:26 +0000250MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristya64b85d2011-09-14 01:02:31 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
cristyd1dd6e42011-09-04 01:46:08 +0000301MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
cristy5ff4eaf2011-09-03 01:38:02 +0000339MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
cristy5ff4eaf2011-09-03 01:38:02 +0000363MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000387% mask. It returns MagickTrue if the pixel region is clipped, otherwise
388% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
cristy4c08aed2011-07-01 19:47:50 +0000417 register const Quantum
418 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristy4c08aed2011-07-01 19:47:50 +0000421 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristye076a6e2010-08-15 19:59:43 +0000424 register ssize_t
425 i;
426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
428 Apply clip mask.
429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000434 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000445 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000451 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy4c08aed2011-07-01 19:47:50 +0000453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000454 break;
cristy4c08aed2011-07-01 19:47:50 +0000455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000456 {
cristy4c08aed2011-07-01 19:47:50 +0000457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000463 }
cristyed231572011-07-14 02:18:59 +0000464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000467 }
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000470 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000471 return(MagickFalse);
472 return(MagickTrue);
473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
480+ C l o n e P i x e l C a c h e %
481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
486% ClonePixelCache() clones a pixel cache.
487%
488% The format of the ClonePixelCache() method is:
489%
490% Cache ClonePixelCache(const Cache cache)
491%
492% A description of each parameter follows:
493%
494% o cache: the pixel cache.
495%
496*/
cristya6577ff2011-09-02 19:54:26 +0000497MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000498{
499 CacheInfo
500 *clone_info;
501
502 const CacheInfo
503 *cache_info;
504
cristy9f027d12011-09-21 01:17:17 +0000505 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
516}
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520% %
521% %
522% %
cristy60c44a82009-10-07 00:58:49 +0000523+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000524% %
525% %
526% %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528% ClonePixelCachePixels() clones the source pixel cache to the destination
529% cache.
530%
531% The format of the ClonePixelCachePixels() method is:
532%
533% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534% CacheInfo *source_info,ExceptionInfo *exception)
535%
536% A description of each parameter follows:
537%
538% o cache_info: the pixel cache.
539%
540% o source_info: the source pixel cache.
541%
542% o exception: return any errors or warnings in this structure.
543%
544*/
545
546static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
547{
548 int
549 status;
550
cristy5ee247a2010-02-12 15:42:34 +0000551 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000552 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000553 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000554 {
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
558 }
cristyf84a1932010-01-03 18:00:18 +0000559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000560 return(status == -1 ? MagickFalse : MagickTrue);
561}
562
563static void LimitPixelCacheDescriptors(void)
564{
565 register CacheInfo
566 *p,
567 *q;
568
569 /*
570 Limit # of open file descriptors.
571 */
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
573 return;
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (cache_resources == (SplayTreeInfo *) NULL)
576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return;
579 }
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
583 {
584 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000585 break;
cristy3ed852e2009-09-05 21:47:34 +0000586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 }
588 for (q=p; p != (CacheInfo *) NULL; )
589 {
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000592 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
594 }
595 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000596 {
597 /*
598 Close least recently used cache.
599 */
600 (void) close(q->file);
601 q->file=(-1);
602 }
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604}
605
606static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
608{
609 if (x > y)
610 return(x);
611 return(y);
612}
613
614static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x < y)
618 return(x);
619 return(y);
620}
621
622static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
623 const MapMode mode)
624{
625 int
626 file;
627
628 /*
629 Open pixel cache on disk.
630 */
cristyf84a1932010-01-03 18:00:18 +0000631 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000632 if (cache_info->file != -1)
633 {
cristyf84a1932010-01-03 18:00:18 +0000634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 return(MagickTrue); /* cache already open */
636 }
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
640 else
641 switch (mode)
642 {
643 case ReadMode:
644 {
cristy18c6c272011-09-23 14:40:37 +0000645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 case WriteMode:
649 {
cristy18c6c272011-09-23 14:40:37 +0000650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000652 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case IOMode:
657 default:
658 {
cristy18c6c272011-09-23 14:40:37 +0000659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000660 O_EXCL,S_MODE);
661 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
664 }
665 }
666 if (file == -1)
667 {
cristyf84a1932010-01-03 18:00:18 +0000668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000669 return(MagickFalse);
670 }
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
673 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000674 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000675 return(MagickTrue);
676}
677
678static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
679 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000680 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000681{
682 register MagickOffsetType
683 i;
684
685 ssize_t
686 count;
687
cristy08a88202010-03-04 19:18:05 +0000688 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000689#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000690 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000691 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000692 {
cristyf84a1932010-01-03 18:00:18 +0000693 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 return((MagickOffsetType) -1);
695 }
696#endif
697 count=0;
698 for (i=0; i < (MagickOffsetType) length; i+=count)
699 {
700#if !defined(MAGICKCORE_HAVE_PREAD)
701 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX));
703#else
704 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000705 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000706#endif
707 if (count > 0)
708 continue;
709 count=0;
710 if (errno != EINTR)
711 {
712 i=(-1);
713 break;
714 }
715 }
716#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000717 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000718#endif
719 return(i);
720}
721
722static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
723 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000724 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000725{
726 register MagickOffsetType
727 i;
728
729 ssize_t
730 count;
731
cristy08a88202010-03-04 19:18:05 +0000732 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000733#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000734 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000735 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000736 {
cristyf84a1932010-01-03 18:00:18 +0000737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 return((MagickOffsetType) -1);
739 }
740#endif
741 count=0;
742 for (i=0; i < (MagickOffsetType) length; i+=count)
743 {
744#if !defined(MAGICKCORE_HAVE_PWRITE)
745 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX));
747#else
748 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000749 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000750#endif
751 if (count > 0)
752 continue;
753 count=0;
754 if (errno != EINTR)
755 {
756 i=(-1);
757 break;
758 }
759 }
760#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000761 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000762#endif
763 return(i);
764}
765
cristy4c08aed2011-07-01 19:47:50 +0000766static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000767 CacheInfo *cache_info,ExceptionInfo *exception)
768{
769 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000770 count;
cristy3ed852e2009-09-05 21:47:34 +0000771
cristy4c08aed2011-07-01 19:47:50 +0000772 register MagickOffsetType
773 i;
cristye076a6e2010-08-15 19:59:43 +0000774
cristybb503372010-05-27 20:51:26 +0000775 size_t
cristy4c08aed2011-07-01 19:47:50 +0000776 length;
cristy3ed852e2009-09-05 21:47:34 +0000777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
780
781 /*
782 Clone pixel cache (both caches on disk).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000786 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000787 sizeof(*blob));
788 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000789 {
cristy4c08aed2011-07-01 19:47:50 +0000790 (void) ThrowMagickException(exception,GetMagickModule(),
791 ResourceLimitError,"MemoryAllocationFailed","`%s'",
792 cache_info->filename);
793 return(MagickFalse);
794 }
cristy3dedf062011-07-02 14:07:40 +0000795 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000796 {
797 blob=(unsigned char *) RelinquishMagickMemory(blob);
798 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
799 cache_info->cache_filename);
800 return(MagickFalse);
801 }
cristy3dedf062011-07-02 14:07:40 +0000802 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000803 {
804 (void) ClosePixelCacheOnDisk(cache_info);
805 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000806 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
807 clone_info->cache_filename);
808 return(MagickFalse);
809 }
cristy4c08aed2011-07-01 19:47:50 +0000810 count=0;
811 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
814 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
815 blob);
816 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000817 {
cristy4c08aed2011-07-01 19:47:50 +0000818 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
819 cache_info->cache_filename);
820 break;
cristy3ed852e2009-09-05 21:47:34 +0000821 }
cristy4c08aed2011-07-01 19:47:50 +0000822 length=(size_t) count;
823 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
824 if ((MagickSizeType) count != length)
825 {
826 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
827 clone_info->cache_filename);
828 break;
829 }
830 }
831 (void) ClosePixelCacheOnDisk(clone_info);
832 (void) ClosePixelCacheOnDisk(cache_info);
833 blob=(unsigned char *) RelinquishMagickMemory(blob);
834 if (i < (MagickOffsetType) cache_info->length)
835 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000836 return(MagickTrue);
837}
838
cristy4c08aed2011-07-01 19:47:50 +0000839static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000840 CacheInfo *cache_info,ExceptionInfo *exception)
841{
842 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000843 count;
cristy3ed852e2009-09-05 21:47:34 +0000844
cristy4c08aed2011-07-01 19:47:50 +0000845 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000846 {
cristy3ed852e2009-09-05 21:47:34 +0000847 /*
cristy4c08aed2011-07-01 19:47:50 +0000848 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000849 */
cristy4c08aed2011-07-01 19:47:50 +0000850 if (cache_info->debug != MagickFalse)
851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
852 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
853 cache_info->length);
854 return(MagickTrue);
855 }
856 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
857 {
858 /*
859 Clone pixel cache (one cache on disk, one in memory).
860 */
861 if (cache_info->debug != MagickFalse)
862 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
863 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy4c08aed2011-07-01 19:47:50 +0000865 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000866 cache_info->cache_filename);
867 return(MagickFalse);
868 }
cristy4c08aed2011-07-01 19:47:50 +0000869 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
870 cache_info->length,(unsigned char *) clone_info->pixels);
871 (void) ClosePixelCacheOnDisk(cache_info);
872 if ((MagickSizeType) count != cache_info->length)
873 {
874 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
875 cache_info->cache_filename);
876 return(MagickFalse);
877 }
878 return(MagickTrue);
879 }
880 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
881 {
882 /*
883 Clone pixel cache (one cache on disk, one in memory).
884 */
885 if (clone_info->debug != MagickFalse)
886 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
887 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
888 {
889 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
890 clone_info->cache_filename);
891 return(MagickFalse);
892 }
893 count=WritePixelCacheRegion(clone_info,clone_info->offset,
894 clone_info->length,(unsigned char *) cache_info->pixels);
895 (void) ClosePixelCacheOnDisk(clone_info);
896 if ((MagickSizeType) count != clone_info->length)
897 {
898 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
899 clone_info->cache_filename);
900 return(MagickFalse);
901 }
902 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000903 }
904 /*
cristy4c08aed2011-07-01 19:47:50 +0000905 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000906 */
cristy4c08aed2011-07-01 19:47:50 +0000907 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000908}
909
cristy4c08aed2011-07-01 19:47:50 +0000910static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000911 CacheInfo *cache_info,ExceptionInfo *exception)
912{
cristy4c08aed2011-07-01 19:47:50 +0000913 MagickBooleanType
914 status;
cristy3ed852e2009-09-05 21:47:34 +0000915
cristy4c08aed2011-07-01 19:47:50 +0000916 MagickOffsetType
917 cache_offset,
918 clone_offset,
919 count;
920
921 register ssize_t
922 x;
923
924 size_t
cristy3ed852e2009-09-05 21:47:34 +0000925 length;
926
cristy4c08aed2011-07-01 19:47:50 +0000927 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000928 y;
929
cristy4c08aed2011-07-01 19:47:50 +0000930 unsigned char
931 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000932
cristy4c08aed2011-07-01 19:47:50 +0000933 /*
934 Clone pixel cache (unoptimized).
935 */
cristy3ed852e2009-09-05 21:47:34 +0000936 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000937 {
cristy4c08aed2011-07-01 19:47:50 +0000938 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
939 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
940 else
941 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
942 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
943 else
944 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
946 else
947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
948 }
cristyed231572011-07-14 02:18:59 +0000949 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
950 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000951 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000952 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000953 if (blob == (unsigned char *) NULL)
954 {
955 (void) ThrowMagickException(exception,GetMagickModule(),
956 ResourceLimitError,"MemoryAllocationFailed","`%s'",
957 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000958 return(MagickFalse);
959 }
cristy4c08aed2011-07-01 19:47:50 +0000960 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
961 cache_offset=0;
962 clone_offset=0;
963 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000964 {
cristy4c08aed2011-07-01 19:47:50 +0000965 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
cristy4c08aed2011-07-01 19:47:50 +0000967 blob=(unsigned char *) RelinquishMagickMemory(blob);
968 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
cristy4c08aed2011-07-01 19:47:50 +0000972 cache_offset=cache_info->offset;
973 }
974 if (clone_info->type == DiskCache)
975 {
cristy3dedf062011-07-02 14:07:40 +0000976 if ((cache_info->type == DiskCache) &&
977 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
978 {
979 (void) ClosePixelCacheOnDisk(clone_info);
980 *clone_info->cache_filename='\0';
981 }
982 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000983 {
cristy4c08aed2011-07-01 19:47:50 +0000984 if (cache_info->type == DiskCache)
985 (void) ClosePixelCacheOnDisk(cache_info);
986 blob=(unsigned char *) RelinquishMagickMemory(blob);
987 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
988 clone_info->cache_filename);
989 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000990 }
cristy4c08aed2011-07-01 19:47:50 +0000991 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000992 }
993 /*
cristy4c08aed2011-07-01 19:47:50 +0000994 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000995 */
cristy4c08aed2011-07-01 19:47:50 +0000996 status=MagickTrue;
997 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
cristy4c08aed2011-07-01 19:47:50 +0000999 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001000 {
cristy3ed852e2009-09-05 21:47:34 +00001001 /*
cristy4c08aed2011-07-01 19:47:50 +00001002 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001003 */
cristyed231572011-07-14 02:18:59 +00001004 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001005 if (cache_info->type != DiskCache)
1006 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1007 length);
cristy3ed852e2009-09-05 21:47:34 +00001008 else
1009 {
cristy4c08aed2011-07-01 19:47:50 +00001010 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1011 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001012 {
cristy4c08aed2011-07-01 19:47:50 +00001013 status=MagickFalse;
1014 break;
cristy3ed852e2009-09-05 21:47:34 +00001015 }
1016 }
cristy4c08aed2011-07-01 19:47:50 +00001017 cache_offset+=length;
1018 if ((y < (ssize_t) clone_info->rows) &&
1019 (x < (ssize_t) clone_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00001020 {
cristy4c08aed2011-07-01 19:47:50 +00001021 /*
1022 Write a set of pixel channels.
1023 */
cristyed231572011-07-14 02:18:59 +00001024 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001025 if (clone_info->type != DiskCache)
1026 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1027 blob,length);
1028 else
1029 {
cristy208b1002011-08-07 18:51:50 +00001030 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001031 if ((MagickSizeType) count != length)
1032 {
1033 status=MagickFalse;
1034 break;
1035 }
1036 }
1037 clone_offset+=length;
cristy3ed852e2009-09-05 21:47:34 +00001038 }
1039 }
cristyed231572011-07-14 02:18:59 +00001040 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001041 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1042 for ( ; x < (ssize_t) clone_info->columns; x++)
1043 {
1044 /*
1045 Set remaining columns with transparent pixel channels.
1046 */
1047 if (clone_info->type != DiskCache)
1048 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1049 length);
1050 else
1051 {
1052 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1053 if ((MagickSizeType) count != length)
1054 {
1055 status=MagickFalse;
1056 break;
1057 }
1058 }
1059 clone_offset+=length;
1060 }
1061 }
cristyed231572011-07-14 02:18:59 +00001062 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001063 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1064 for ( ; y < (ssize_t) clone_info->rows; y++)
1065 {
1066 /*
1067 Set remaining rows with transparent pixels.
1068 */
1069 for (x=0; x < (ssize_t) clone_info->columns; x++)
1070 {
1071 if (clone_info->type != DiskCache)
1072 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1073 length);
1074 else
1075 {
1076 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1077 if ((MagickSizeType) count != length)
1078 {
1079 status=MagickFalse;
1080 break;
1081 }
1082 }
1083 clone_offset+=length;
1084 }
1085 }
1086 if ((cache_info->metacontent_extent != 0) &&
1087 (clone_info->metacontent_extent != 0))
1088 {
1089 /*
1090 Clone metacontent.
1091 */
1092 for (y=0; y < (ssize_t) cache_info->rows; y++)
1093 {
1094 for (x=0; x < (ssize_t) cache_info->columns; x++)
1095 {
1096 /*
1097 Read a set of metacontent.
1098 */
1099 length=cache_info->metacontent_extent;
1100 if (cache_info->type != DiskCache)
1101 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1102 cache_offset,length);
1103 else
1104 {
1105 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1106 if ((MagickSizeType) count != length)
1107 {
1108 status=MagickFalse;
1109 break;
1110 }
1111 }
1112 cache_offset+=length;
1113 if ((y < (ssize_t) clone_info->rows) &&
1114 (x < (ssize_t) clone_info->columns))
1115 {
1116 /*
1117 Write a set of metacontent.
1118 */
1119 length=clone_info->metacontent_extent;
1120 if (clone_info->type != DiskCache)
1121 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1122 blob,length);
1123 else
1124 {
1125 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1126 blob);
1127 if ((MagickSizeType) count != length)
1128 {
1129 status=MagickFalse;
1130 break;
1131 }
1132 }
1133 clone_offset+=length;
1134 }
1135 }
1136 length=clone_info->metacontent_extent;
1137 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1138 for ( ; x < (ssize_t) clone_info->columns; x++)
1139 {
1140 /*
1141 Set remaining columns with metacontent.
1142 */
1143 if (clone_info->type != DiskCache)
1144 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1145 blob,length);
1146 else
1147 {
cristy208b1002011-08-07 18:51:50 +00001148 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001149 if ((MagickSizeType) count != length)
1150 {
1151 status=MagickFalse;
1152 break;
1153 }
1154 }
1155 clone_offset+=length;
1156 }
1157 }
1158 length=clone_info->metacontent_extent;
1159 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1160 for ( ; y < (ssize_t) clone_info->rows; y++)
1161 {
1162 /*
1163 Set remaining rows with metacontent.
1164 */
1165 for (x=0; x < (ssize_t) clone_info->columns; x++)
1166 {
1167 if (clone_info->type != DiskCache)
1168 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1169 blob,length);
1170 else
1171 {
1172 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1173 if ((MagickSizeType) count != length)
1174 {
1175 status=MagickFalse;
1176 break;
1177 }
1178 }
1179 clone_offset+=length;
1180 }
1181 }
1182 }
1183 if (clone_info->type == DiskCache)
1184 (void) ClosePixelCacheOnDisk(clone_info);
1185 if (cache_info->type == DiskCache)
1186 (void) ClosePixelCacheOnDisk(cache_info);
1187 blob=(unsigned char *) RelinquishMagickMemory(blob);
1188 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001189}
1190
1191static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1192 CacheInfo *cache_info,ExceptionInfo *exception)
1193{
cristy5a7fbfb2010-11-06 16:10:59 +00001194 if (cache_info->type == PingCache)
1195 return(MagickTrue);
cristy4c08aed2011-07-01 19:47:50 +00001196 if ((cache_info->columns == clone_info->columns) &&
1197 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001198 (cache_info->number_channels == clone_info->number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00001199 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1200 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1201 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001202}
1203
1204/*
1205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206% %
1207% %
1208% %
1209+ C l o n e P i x e l C a c h e M e t h o d s %
1210% %
1211% %
1212% %
1213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214%
1215% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1216% another.
1217%
1218% The format of the ClonePixelCacheMethods() method is:
1219%
1220% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1221%
1222% A description of each parameter follows:
1223%
1224% o clone: Specifies a pointer to a Cache structure.
1225%
1226% o cache: the pixel cache.
1227%
1228*/
cristya6577ff2011-09-02 19:54:26 +00001229MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001230{
1231 CacheInfo
1232 *cache_info,
1233 *source_info;
1234
1235 assert(clone != (Cache) NULL);
1236 source_info=(CacheInfo *) clone;
1237 assert(source_info->signature == MagickSignature);
1238 if (source_info->debug != MagickFalse)
1239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1240 source_info->filename);
1241 assert(cache != (Cache) NULL);
1242 cache_info=(CacheInfo *) cache;
1243 assert(cache_info->signature == MagickSignature);
1244 source_info->methods=cache_info->methods;
1245}
1246
1247/*
1248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249% %
1250% %
1251% %
1252+ D e s t r o y I m a g e P i x e l C a c h e %
1253% %
1254% %
1255% %
1256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257%
1258% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1259%
1260% The format of the DestroyImagePixelCache() method is:
1261%
1262% void DestroyImagePixelCache(Image *image)
1263%
1264% A description of each parameter follows:
1265%
1266% o image: the image.
1267%
1268*/
1269static void DestroyImagePixelCache(Image *image)
1270{
1271 assert(image != (Image *) NULL);
1272 assert(image->signature == MagickSignature);
1273 if (image->debug != MagickFalse)
1274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1275 if (image->cache == (void *) NULL)
1276 return;
1277 image->cache=DestroyPixelCache(image->cache);
1278}
1279
1280/*
1281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282% %
1283% %
1284% %
1285+ D e s t r o y I m a g e P i x e l s %
1286% %
1287% %
1288% %
1289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290%
1291% DestroyImagePixels() deallocates memory associated with the pixel cache.
1292%
1293% The format of the DestroyImagePixels() method is:
1294%
1295% void DestroyImagePixels(Image *image)
1296%
1297% A description of each parameter follows:
1298%
1299% o image: the image.
1300%
1301*/
1302MagickExport void DestroyImagePixels(Image *image)
1303{
1304 CacheInfo
1305 *cache_info;
1306
1307 assert(image != (const Image *) NULL);
1308 assert(image->signature == MagickSignature);
1309 if (image->debug != MagickFalse)
1310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1311 assert(image->cache != (Cache) NULL);
1312 cache_info=(CacheInfo *) image->cache;
1313 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001314 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1315 {
1316 cache_info->methods.destroy_pixel_handler(image);
1317 return;
1318 }
cristy2036f5c2010-09-19 21:18:17 +00001319 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001320}
1321
1322/*
1323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324% %
1325% %
1326% %
1327+ D e s t r o y P i x e l C a c h e %
1328% %
1329% %
1330% %
1331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332%
1333% DestroyPixelCache() deallocates memory associated with the pixel cache.
1334%
1335% The format of the DestroyPixelCache() method is:
1336%
1337% Cache DestroyPixelCache(Cache cache)
1338%
1339% A description of each parameter follows:
1340%
1341% o cache: the pixel cache.
1342%
1343*/
1344
1345static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1346{
1347 switch (cache_info->type)
1348 {
1349 case MemoryCache:
1350 {
1351 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001352 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001353 cache_info->pixels);
1354 else
cristy4c08aed2011-07-01 19:47:50 +00001355 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001356 (size_t) cache_info->length);
1357 RelinquishMagickResource(MemoryResource,cache_info->length);
1358 break;
1359 }
1360 case MapCache:
1361 {
cristy4c08aed2011-07-01 19:47:50 +00001362 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001363 cache_info->length);
1364 RelinquishMagickResource(MapResource,cache_info->length);
1365 }
1366 case DiskCache:
1367 {
1368 if (cache_info->file != -1)
1369 (void) ClosePixelCacheOnDisk(cache_info);
1370 RelinquishMagickResource(DiskResource,cache_info->length);
1371 break;
1372 }
1373 default:
1374 break;
1375 }
1376 cache_info->type=UndefinedCache;
1377 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001378 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001379}
1380
cristya6577ff2011-09-02 19:54:26 +00001381MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001382{
1383 CacheInfo
1384 *cache_info;
1385
cristy3ed852e2009-09-05 21:47:34 +00001386 assert(cache != (Cache) NULL);
1387 cache_info=(CacheInfo *) cache;
1388 assert(cache_info->signature == MagickSignature);
1389 if (cache_info->debug != MagickFalse)
1390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1391 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001392 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001393 cache_info->reference_count--;
1394 if (cache_info->reference_count != 0)
1395 {
cristyf84a1932010-01-03 18:00:18 +00001396 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001397 return((Cache) NULL);
1398 }
cristyf84a1932010-01-03 18:00:18 +00001399 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001400 if (cache_resources != (SplayTreeInfo *) NULL)
1401 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001402 if (cache_info->debug != MagickFalse)
1403 {
1404 char
1405 message[MaxTextExtent];
1406
cristyb51dff52011-05-19 16:55:47 +00001407 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001408 cache_info->filename);
1409 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1410 }
cristyc2e1bdd2009-09-10 23:43:34 +00001411 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1412 (cache_info->type != DiskCache)))
1413 RelinquishPixelCachePixels(cache_info);
1414 else
1415 {
1416 RelinquishPixelCachePixels(cache_info);
1417 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1418 }
cristy3ed852e2009-09-05 21:47:34 +00001419 *cache_info->cache_filename='\0';
1420 if (cache_info->nexus_info != (NexusInfo **) NULL)
1421 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1422 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001423 if (cache_info->random_info != (RandomInfo *) NULL)
1424 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001425 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1426 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1427 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1428 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001429 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001430 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001431 cache=(Cache) NULL;
1432 return(cache);
1433}
1434
1435/*
1436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437% %
1438% %
1439% %
1440+ D e s t r o y P i x e l C a c h e N e x u s %
1441% %
1442% %
1443% %
1444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445%
1446% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1447%
1448% The format of the DestroyPixelCacheNexus() method is:
1449%
1450% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001451% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001452%
1453% A description of each parameter follows:
1454%
1455% o nexus_info: the nexus to destroy.
1456%
1457% o number_threads: the number of nexus threads.
1458%
1459*/
1460
1461static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1462{
1463 if (nexus_info->mapped == MagickFalse)
1464 (void) RelinquishMagickMemory(nexus_info->cache);
1465 else
1466 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001467 nexus_info->cache=(Quantum *) NULL;
1468 nexus_info->pixels=(Quantum *) NULL;
1469 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001470 nexus_info->length=0;
1471 nexus_info->mapped=MagickFalse;
1472}
1473
cristya6577ff2011-09-02 19:54:26 +00001474MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001475 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001476{
cristybb503372010-05-27 20:51:26 +00001477 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001478 i;
1479
1480 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001481 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001482 {
cristy4c08aed2011-07-01 19:47:50 +00001483 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001484 RelinquishCacheNexusPixels(nexus_info[i]);
1485 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001486 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001487 }
cristyb41ee102010-10-04 16:46:15 +00001488 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001489 return(nexus_info);
1490}
1491
1492/*
1493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494% %
1495% %
1496% %
cristy4c08aed2011-07-01 19:47:50 +00001497% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001498% %
1499% %
1500% %
1501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502%
cristy4c08aed2011-07-01 19:47:50 +00001503% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1504% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1505% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001506%
cristy4c08aed2011-07-01 19:47:50 +00001507% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001508%
cristy4c08aed2011-07-01 19:47:50 +00001509% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001510%
1511% A description of each parameter follows:
1512%
1513% o image: the image.
1514%
1515*/
cristy4c08aed2011-07-01 19:47:50 +00001516MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001517{
1518 CacheInfo
1519 *cache_info;
1520
cristy5c9e6f22010-09-17 17:31:01 +00001521 const int
1522 id = GetOpenMPThreadId();
1523
cristy4c08aed2011-07-01 19:47:50 +00001524 void
1525 *metacontent;
1526
cristye7cc7cf2010-09-21 13:26:47 +00001527 assert(image != (const Image *) NULL);
1528 assert(image->signature == MagickSignature);
1529 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001530 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001531 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001532 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1533 (GetAuthenticMetacontentFromHandler) NULL)
1534 {
1535 metacontent=cache_info->methods.
1536 get_authentic_metacontent_from_handler(image);
1537 return(metacontent);
1538 }
cristy6ebe97c2010-07-03 01:17:28 +00001539 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001540 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1541 cache_info->nexus_info[id]);
1542 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001543}
1544
1545/*
1546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547% %
1548% %
1549% %
cristy4c08aed2011-07-01 19:47:50 +00001550+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001551% %
1552% %
1553% %
1554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555%
cristy4c08aed2011-07-01 19:47:50 +00001556% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1557% with the last call to QueueAuthenticPixelsCache() or
1558% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001559%
cristy4c08aed2011-07-01 19:47:50 +00001560% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001561%
cristy4c08aed2011-07-01 19:47:50 +00001562% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001563%
1564% A description of each parameter follows:
1565%
1566% o image: the image.
1567%
1568*/
cristy4c08aed2011-07-01 19:47:50 +00001569static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001570{
1571 CacheInfo
1572 *cache_info;
1573
cristy2036f5c2010-09-19 21:18:17 +00001574 const int
1575 id = GetOpenMPThreadId();
1576
cristy4c08aed2011-07-01 19:47:50 +00001577 void
1578 *metacontent;
1579
cristy3ed852e2009-09-05 21:47:34 +00001580 assert(image != (const Image *) NULL);
1581 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001582 assert(image->cache != (Cache) NULL);
1583 cache_info=(CacheInfo *) image->cache;
1584 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001585 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001586 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1587 cache_info->nexus_info[id]);
1588 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001589}
1590
1591/*
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593% %
1594% %
1595% %
1596+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1597% %
1598% %
1599% %
1600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601%
1602% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1603% disk pixel cache as defined by the geometry parameters. A pointer to the
1604% pixels is returned if the pixels are transferred, otherwise a NULL is
1605% returned.
1606%
1607% The format of the GetAuthenticPixelCacheNexus() method is:
1608%
cristy4c08aed2011-07-01 19:47:50 +00001609% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001610% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001611% NexusInfo *nexus_info,ExceptionInfo *exception)
1612%
1613% A description of each parameter follows:
1614%
1615% o image: the image.
1616%
1617% o x,y,columns,rows: These values define the perimeter of a region of
1618% pixels.
1619%
1620% o nexus_info: the cache nexus to return.
1621%
1622% o exception: return any errors or warnings in this structure.
1623%
1624*/
1625
cristy4c08aed2011-07-01 19:47:50 +00001626static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001627 NexusInfo *nexus_info)
1628{
cristy4c08aed2011-07-01 19:47:50 +00001629 MagickBooleanType
1630 status;
1631
cristy3ed852e2009-09-05 21:47:34 +00001632 MagickOffsetType
1633 offset;
1634
cristy73724512010-04-12 14:43:14 +00001635 if (cache_info->type == PingCache)
1636 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001637 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1638 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001639 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001640 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001641 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001642}
1643
cristya6577ff2011-09-02 19:54:26 +00001644MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001645 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001646 NexusInfo *nexus_info,ExceptionInfo *exception)
1647{
1648 CacheInfo
1649 *cache_info;
1650
cristy4c08aed2011-07-01 19:47:50 +00001651 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001652 *q;
cristy3ed852e2009-09-05 21:47:34 +00001653
1654 /*
1655 Transfer pixels from the cache.
1656 */
1657 assert(image != (Image *) NULL);
1658 assert(image->signature == MagickSignature);
cristyacd2ed22011-08-30 01:44:23 +00001659 q=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1660 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001661 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001662 cache_info=(CacheInfo *) image->cache;
1663 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001664 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001665 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001666 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001667 return((Quantum *) NULL);
1668 if (cache_info->metacontent_extent != 0)
1669 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1670 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001671 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001672}
1673
1674/*
1675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676% %
1677% %
1678% %
1679+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1680% %
1681% %
1682% %
1683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684%
1685% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1686% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1687%
1688% The format of the GetAuthenticPixelsFromCache() method is:
1689%
cristy4c08aed2011-07-01 19:47:50 +00001690% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001691%
1692% A description of each parameter follows:
1693%
1694% o image: the image.
1695%
1696*/
cristy4c08aed2011-07-01 19:47:50 +00001697static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001698{
1699 CacheInfo
1700 *cache_info;
1701
cristy5c9e6f22010-09-17 17:31:01 +00001702 const int
1703 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001704
cristye7cc7cf2010-09-21 13:26:47 +00001705 assert(image != (const Image *) NULL);
1706 assert(image->signature == MagickSignature);
1707 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001708 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001709 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001710 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001711 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001712}
1713
1714/*
1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716% %
1717% %
1718% %
1719% G e t A u t h e n t i c P i x e l Q u e u e %
1720% %
1721% %
1722% %
1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724%
cristy4c08aed2011-07-01 19:47:50 +00001725% GetAuthenticPixelQueue() returns the authentic pixels associated
1726% corresponding with the last call to QueueAuthenticPixels() or
1727% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001728%
1729% The format of the GetAuthenticPixelQueue() method is:
1730%
cristy4c08aed2011-07-01 19:47:50 +00001731% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001732%
1733% A description of each parameter follows:
1734%
1735% o image: the image.
1736%
1737*/
cristy4c08aed2011-07-01 19:47:50 +00001738MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001739{
1740 CacheInfo
1741 *cache_info;
1742
cristy2036f5c2010-09-19 21:18:17 +00001743 const int
1744 id = GetOpenMPThreadId();
1745
cristy3ed852e2009-09-05 21:47:34 +00001746 assert(image != (const Image *) NULL);
1747 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001748 assert(image->cache != (Cache) NULL);
1749 cache_info=(CacheInfo *) image->cache;
1750 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001751 if (cache_info->methods.get_authentic_pixels_from_handler !=
1752 (GetAuthenticPixelsFromHandler) NULL)
1753 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001754 assert(id < (int) cache_info->number_threads);
1755 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001756}
1757
1758/*
1759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760% %
1761% %
1762% %
1763% G e t A u t h e n t i c P i x e l s %
1764% %
1765% %
cristy4c08aed2011-07-01 19:47:50 +00001766% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001767%
1768% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001769% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001770% representing the region is returned, otherwise NULL is returned.
1771%
1772% The returned pointer may point to a temporary working copy of the pixels
1773% or it may point to the original pixels in memory. Performance is maximized
1774% if the selected region is part of one row, or one or more full rows, since
1775% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001776% if the image is in memory, or in a memory-mapped file. The returned pointer
1777% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001778%
1779% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001780% Quantum. If the image has corresponding metacontent,call
1781% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1782% meta-content corresponding to the region. Once the Quantum array has
1783% been updated, the changes must be saved back to the underlying image using
1784% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001785%
1786% The format of the GetAuthenticPixels() method is:
1787%
cristy4c08aed2011-07-01 19:47:50 +00001788% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001789% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001790% ExceptionInfo *exception)
1791%
1792% A description of each parameter follows:
1793%
1794% o image: the image.
1795%
1796% o x,y,columns,rows: These values define the perimeter of a region of
1797% pixels.
1798%
1799% o exception: return any errors or warnings in this structure.
1800%
1801*/
cristy4c08aed2011-07-01 19:47:50 +00001802MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001803 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001804 ExceptionInfo *exception)
1805{
1806 CacheInfo
1807 *cache_info;
1808
cristy2036f5c2010-09-19 21:18:17 +00001809 const int
1810 id = GetOpenMPThreadId();
1811
cristy4c08aed2011-07-01 19:47:50 +00001812 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001813 *q;
cristy4c08aed2011-07-01 19:47:50 +00001814
cristy3ed852e2009-09-05 21:47:34 +00001815 assert(image != (Image *) NULL);
1816 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001817 assert(image->cache != (Cache) NULL);
1818 cache_info=(CacheInfo *) image->cache;
1819 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001820 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001821 (GetAuthenticPixelsHandler) NULL)
1822 {
cristyacd2ed22011-08-30 01:44:23 +00001823 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1824 exception);
1825 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001826 }
cristy2036f5c2010-09-19 21:18:17 +00001827 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001828 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001829 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001830 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001831}
1832
1833/*
1834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835% %
1836% %
1837% %
1838+ G e t A u t h e n t i c P i x e l s C a c h e %
1839% %
1840% %
1841% %
1842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1843%
1844% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1845% as defined by the geometry parameters. A pointer to the pixels is returned
1846% if the pixels are transferred, otherwise a NULL is returned.
1847%
1848% The format of the GetAuthenticPixelsCache() method is:
1849%
cristy4c08aed2011-07-01 19:47:50 +00001850% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001851% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001852% ExceptionInfo *exception)
1853%
1854% A description of each parameter follows:
1855%
1856% o image: the image.
1857%
1858% o x,y,columns,rows: These values define the perimeter of a region of
1859% pixels.
1860%
1861% o exception: return any errors or warnings in this structure.
1862%
1863*/
cristy4c08aed2011-07-01 19:47:50 +00001864static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001865 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001866 ExceptionInfo *exception)
1867{
1868 CacheInfo
1869 *cache_info;
1870
cristy5c9e6f22010-09-17 17:31:01 +00001871 const int
1872 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001873
cristy4c08aed2011-07-01 19:47:50 +00001874 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001875 *q;
cristy4c08aed2011-07-01 19:47:50 +00001876
cristye7cc7cf2010-09-21 13:26:47 +00001877 assert(image != (const Image *) NULL);
1878 assert(image->signature == MagickSignature);
1879 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001880 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001881 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001882 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001883 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001884 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001885 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001886 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001887 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001888}
1889
1890/*
1891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892% %
1893% %
1894% %
1895+ G e t I m a g e E x t e n t %
1896% %
1897% %
1898% %
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900%
cristy4c08aed2011-07-01 19:47:50 +00001901% GetImageExtent() returns the extent of the pixels associated corresponding
1902% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001903%
1904% The format of the GetImageExtent() method is:
1905%
1906% MagickSizeType GetImageExtent(const Image *image)
1907%
1908% A description of each parameter follows:
1909%
1910% o image: the image.
1911%
1912*/
1913MagickExport MagickSizeType GetImageExtent(const Image *image)
1914{
1915 CacheInfo
1916 *cache_info;
1917
cristy5c9e6f22010-09-17 17:31:01 +00001918 const int
1919 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001920
cristy3ed852e2009-09-05 21:47:34 +00001921 assert(image != (Image *) NULL);
1922 assert(image->signature == MagickSignature);
1923 if (image->debug != MagickFalse)
1924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1925 assert(image->cache != (Cache) NULL);
1926 cache_info=(CacheInfo *) image->cache;
1927 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001928 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001929 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001930}
1931
1932/*
1933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1934% %
1935% %
1936% %
1937+ G e t I m a g e P i x e l C a c h e %
1938% %
1939% %
1940% %
1941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1942%
1943% GetImagePixelCache() ensures that there is only a single reference to the
1944% pixel cache to be modified, updating the provided cache pointer to point to
1945% a clone of the original pixel cache if necessary.
1946%
1947% The format of the GetImagePixelCache method is:
1948%
1949% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1950% ExceptionInfo *exception)
1951%
1952% A description of each parameter follows:
1953%
1954% o image: the image.
1955%
1956% o clone: any value other than MagickFalse clones the cache pixels.
1957%
1958% o exception: return any errors or warnings in this structure.
1959%
1960*/
cristyaf894d72011-08-06 23:03:10 +00001961
cristy3ed852e2009-09-05 21:47:34 +00001962static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1963{
1964 CacheInfo
1965 *cache_info;
1966
1967 /*
1968 Does the image match the pixel cache morphology?
1969 */
1970 cache_info=(CacheInfo *) image->cache;
1971 if ((image->storage_class != cache_info->storage_class) ||
1972 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001973 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00001974 (image->columns != cache_info->columns) ||
1975 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001976 (image->number_channels != cache_info->number_channels) ||
cristy4c08aed2011-07-01 19:47:50 +00001977 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001978 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1979 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1980 return(MagickFalse);
1981 return(MagickTrue);
1982}
1983
cristycd01fae2011-08-06 23:52:42 +00001984static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1985 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001986{
1987 CacheInfo
1988 *cache_info;
1989
cristy3ed852e2009-09-05 21:47:34 +00001990 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001991 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001992 status;
1993
cristy50a10922010-02-15 18:35:25 +00001994 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001995 cpu_throttle = 0,
1996 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001997 time_limit = 0;
1998
cristy1ea34962010-07-01 19:49:21 +00001999 static time_t
cristy208b1002011-08-07 18:51:50 +00002000 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002001
cristyc4f9f132010-03-04 18:50:01 +00002002 status=MagickTrue;
2003 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002004 if (cpu_throttle == 0)
2005 {
2006 char
2007 *limit;
2008
2009 /*
2010 Set CPU throttle in milleseconds.
2011 */
2012 cpu_throttle=MagickResourceInfinity;
2013 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2014 if (limit == (char *) NULL)
2015 limit=GetPolicyValue("throttle");
2016 if (limit != (char *) NULL)
2017 {
2018 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2019 limit=DestroyString(limit);
2020 }
2021 }
2022 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2023 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002024 if (time_limit == 0)
2025 {
cristy6ebe97c2010-07-03 01:17:28 +00002026 /*
2027 Set the exire time in seconds.
2028 */
cristy1ea34962010-07-01 19:49:21 +00002029 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002030 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002031 }
2032 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002033 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002034 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002035 assert(image->cache != (Cache) NULL);
2036 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002037 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002038 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002039 {
cristyceb55ee2010-11-06 16:05:49 +00002040 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002041 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002042 {
cristyceb55ee2010-11-06 16:05:49 +00002043 Image
2044 clone_image;
2045
2046 CacheInfo
2047 *clone_info;
2048
2049 /*
2050 Clone pixel cache.
2051 */
2052 clone_image=(*image);
2053 clone_image.semaphore=AllocateSemaphoreInfo();
2054 clone_image.reference_count=1;
2055 clone_image.cache=ClonePixelCache(cache_info);
2056 clone_info=(CacheInfo *) clone_image.cache;
2057 status=OpenPixelCache(&clone_image,IOMode,exception);
2058 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002059 {
cristy5a7fbfb2010-11-06 16:10:59 +00002060 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002061 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002062 if (status != MagickFalse)
2063 {
cristy979bf772011-08-08 00:04:15 +00002064 if (cache_info->mode == ReadMode)
2065 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002066 destroy=MagickTrue;
2067 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002068 }
2069 }
cristyceb55ee2010-11-06 16:05:49 +00002070 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002071 }
cristyceb55ee2010-11-06 16:05:49 +00002072 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002073 }
cristy4320e0e2009-09-10 15:00:08 +00002074 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002075 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002076 if (status != MagickFalse)
2077 {
2078 /*
2079 Ensure the image matches the pixel cache morphology.
2080 */
2081 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002082 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002083 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2084 status=OpenPixelCache(image,IOMode,exception);
2085 }
cristyf84a1932010-01-03 18:00:18 +00002086 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002087 if (status == MagickFalse)
2088 return((Cache) NULL);
2089 return(image->cache);
2090}
2091
2092/*
2093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094% %
2095% %
2096% %
2097% G e t O n e A u t h e n t i c P i x e l %
2098% %
2099% %
2100% %
2101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102%
2103% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2104% location. The image background color is returned if an error occurs.
2105%
2106% The format of the GetOneAuthenticPixel() method is:
2107%
cristybb503372010-05-27 20:51:26 +00002108% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2109% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002110%
2111% A description of each parameter follows:
2112%
2113% o image: the image.
2114%
2115% o x,y: These values define the location of the pixel to return.
2116%
2117% o pixel: return a pixel at the specified (x,y) location.
2118%
2119% o exception: return any errors or warnings in this structure.
2120%
2121*/
cristyacbbb7c2010-06-30 18:56:48 +00002122MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2123 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002124{
2125 CacheInfo
2126 *cache_info;
2127
cristy4c08aed2011-07-01 19:47:50 +00002128 register Quantum
2129 *q;
cristy2036f5c2010-09-19 21:18:17 +00002130
cristy3ed852e2009-09-05 21:47:34 +00002131 assert(image != (Image *) NULL);
2132 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002133 assert(image->cache != (Cache) NULL);
2134 cache_info=(CacheInfo *) image->cache;
2135 assert(cache_info->signature == MagickSignature);
2136 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002137 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2138 (GetOneAuthenticPixelFromHandler) NULL)
2139 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2140 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002141 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2142 if (q == (Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002143 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002144 GetPixelPacket(image,q,pixel);
cristy2036f5c2010-09-19 21:18:17 +00002145 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002146}
2147
2148/*
2149%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2150% %
2151% %
2152% %
2153+ 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 %
2154% %
2155% %
2156% %
2157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158%
2159% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2160% location. The image background color is returned if an error occurs.
2161%
2162% The format of the GetOneAuthenticPixelFromCache() method is:
2163%
2164% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002165% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2166% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002167%
2168% A description of each parameter follows:
2169%
2170% o image: the image.
2171%
2172% o x,y: These values define the location of the pixel to return.
2173%
2174% o pixel: return a pixel at the specified (x,y) location.
2175%
2176% o exception: return any errors or warnings in this structure.
2177%
2178*/
2179static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002180 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002181{
cristy098f78c2010-09-23 17:28:44 +00002182 CacheInfo
2183 *cache_info;
2184
2185 const int
2186 id = GetOpenMPThreadId();
2187
cristy4c08aed2011-07-01 19:47:50 +00002188 register Quantum
2189 *q;
cristy3ed852e2009-09-05 21:47:34 +00002190
cristy0158a4b2010-09-20 13:59:45 +00002191 assert(image != (const Image *) NULL);
2192 assert(image->signature == MagickSignature);
2193 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002194 cache_info=(CacheInfo *) image->cache;
2195 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002196 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002197 *pixel=image->background_color;
2198 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2199 exception);
2200 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002201 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002202 GetPixelPacket(image,q,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002203 return(MagickTrue);
2204}
2205
2206/*
2207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2208% %
2209% %
2210% %
2211% G e t O n e V i r t u a l M a g i c k P i x e l %
2212% %
2213% %
2214% %
2215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216%
2217% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2218% location. The image background color is returned if an error occurs. If
2219% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2220%
2221% The format of the GetOneVirtualMagickPixel() method is:
2222%
2223% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002224% const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002225% ExceptionInfo exception)
2226%
2227% A description of each parameter follows:
2228%
2229% o image: the image.
2230%
2231% o x,y: these values define the location of the pixel to return.
2232%
2233% o pixel: return a pixel at the specified (x,y) location.
2234%
2235% o exception: return any errors or warnings in this structure.
2236%
2237*/
2238MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002239 const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristyacbbb7c2010-06-30 18:56:48 +00002240 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002241{
2242 CacheInfo
2243 *cache_info;
2244
cristy0158a4b2010-09-20 13:59:45 +00002245 const int
2246 id = GetOpenMPThreadId();
2247
cristy4c08aed2011-07-01 19:47:50 +00002248 register const Quantum
cristyacd2ed22011-08-30 01:44:23 +00002249 *p;
cristy3ed852e2009-09-05 21:47:34 +00002250
2251 assert(image != (const Image *) NULL);
2252 assert(image->signature == MagickSignature);
2253 assert(image->cache != (Cache) NULL);
2254 cache_info=(CacheInfo *) image->cache;
2255 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002256 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00002257 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002258 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002259 GetPixelInfo(image,pixel);
cristyacd2ed22011-08-30 01:44:23 +00002260 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002261 return(MagickFalse);
cristyacd2ed22011-08-30 01:44:23 +00002262 SetPixelInfo(image,p,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002263 return(MagickTrue);
2264}
2265
2266/*
2267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2268% %
2269% %
2270% %
2271% G e t O n e V i r t u a l M e t h o d P i x e l %
2272% %
2273% %
2274% %
2275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2276%
2277% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2278% location as defined by specified pixel method. The image background color
2279% is returned if an error occurs. If you plan to modify the pixel, use
2280% GetOneAuthenticPixel() instead.
2281%
2282% The format of the GetOneVirtualMethodPixel() method is:
2283%
2284% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002285% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
cristy4c08aed2011-07-01 19:47:50 +00002286% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002287%
2288% A description of each parameter follows:
2289%
2290% o image: the image.
2291%
2292% o virtual_pixel_method: the virtual pixel method.
2293%
2294% o x,y: These values define the location of the pixel to return.
2295%
2296% o pixel: return a pixel at the specified (x,y) location.
2297%
2298% o exception: return any errors or warnings in this structure.
2299%
2300*/
2301MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002302 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002303 PixelPacket *pixel,ExceptionInfo *exception)
2304{
cristy3ed852e2009-09-05 21:47:34 +00002305 CacheInfo
2306 *cache_info;
2307
cristy0158a4b2010-09-20 13:59:45 +00002308 const int
2309 id = GetOpenMPThreadId();
2310
cristy4c08aed2011-07-01 19:47:50 +00002311 const Quantum
2312 *p;
cristy2036f5c2010-09-19 21:18:17 +00002313
cristy3ed852e2009-09-05 21:47:34 +00002314 assert(image != (const Image *) NULL);
2315 assert(image->signature == MagickSignature);
2316 assert(image->cache != (Cache) NULL);
2317 cache_info=(CacheInfo *) image->cache;
2318 assert(cache_info->signature == MagickSignature);
2319 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002320 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2321 (GetOneVirtualPixelFromHandler) NULL)
2322 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2323 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002324 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002325 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002326 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002327 if (p == (const Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002328 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002329 GetPixelPacket(image,p,pixel);
2330 if (image->colorspace == CMYKColorspace)
2331 pixel->black=GetPixelBlack(image,p);
cristy2036f5c2010-09-19 21:18:17 +00002332 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002333}
2334
2335/*
2336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337% %
2338% %
2339% %
2340% G e t O n e V i r t u a l P i x e l %
2341% %
2342% %
2343% %
2344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2345%
2346% GetOneVirtualPixel() returns a single virtual pixel at the specified
2347% (x,y) location. The image background color is returned if an error occurs.
2348% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2349%
2350% The format of the GetOneVirtualPixel() method is:
2351%
cristybb503372010-05-27 20:51:26 +00002352% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2353% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002354%
2355% A description of each parameter follows:
2356%
2357% o image: the image.
2358%
2359% o x,y: These values define the location of the pixel to return.
2360%
2361% o pixel: return a pixel at the specified (x,y) location.
2362%
2363% o exception: return any errors or warnings in this structure.
2364%
2365*/
2366MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002367 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002368{
cristy3ed852e2009-09-05 21:47:34 +00002369 CacheInfo
2370 *cache_info;
2371
cristy0158a4b2010-09-20 13:59:45 +00002372 const int
2373 id = GetOpenMPThreadId();
2374
cristy4c08aed2011-07-01 19:47:50 +00002375 const Quantum
2376 *p;
cristy2036f5c2010-09-19 21:18:17 +00002377
cristy3ed852e2009-09-05 21:47:34 +00002378 assert(image != (const Image *) NULL);
2379 assert(image->signature == MagickSignature);
2380 assert(image->cache != (Cache) NULL);
2381 cache_info=(CacheInfo *) image->cache;
2382 assert(cache_info->signature == MagickSignature);
2383 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002384 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2385 (GetOneVirtualPixelFromHandler) NULL)
2386 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2387 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002388 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002389 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002390 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002391 if (p == (const Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002392 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002393 GetPixelPacket(image,p,pixel);
2394 if (image->colorspace == CMYKColorspace)
2395 pixel->black=GetPixelBlack(image,p);
cristy2036f5c2010-09-19 21:18:17 +00002396 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002397}
2398
2399/*
2400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2401% %
2402% %
2403% %
2404+ 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 %
2405% %
2406% %
2407% %
2408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2409%
2410% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2411% specified (x,y) location. The image background color is returned if an
2412% error occurs.
2413%
2414% The format of the GetOneVirtualPixelFromCache() method is:
2415%
2416% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002417% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002418% PixelPacket *pixel,ExceptionInfo *exception)
2419%
2420% A description of each parameter follows:
2421%
2422% o image: the image.
2423%
2424% o virtual_pixel_method: the virtual pixel method.
2425%
2426% o x,y: These values define the location of the pixel to return.
2427%
2428% o pixel: return a pixel at the specified (x,y) location.
2429%
2430% o exception: return any errors or warnings in this structure.
2431%
2432*/
2433static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002434 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002435 PixelPacket *pixel,ExceptionInfo *exception)
2436{
cristy0158a4b2010-09-20 13:59:45 +00002437 CacheInfo
2438 *cache_info;
2439
2440 const int
2441 id = GetOpenMPThreadId();
2442
cristy4c08aed2011-07-01 19:47:50 +00002443 const Quantum
2444 *p;
cristy3ed852e2009-09-05 21:47:34 +00002445
cristye7cc7cf2010-09-21 13:26:47 +00002446 assert(image != (const Image *) NULL);
2447 assert(image->signature == MagickSignature);
2448 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002449 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002450 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002451 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002452 *pixel=image->background_color;
cristy4c08aed2011-07-01 19:47:50 +00002453 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002454 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002455 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002456 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002457 GetPixelPacket(image,p,pixel);
2458 if (image->colorspace == CMYKColorspace)
2459 pixel->black=GetPixelBlack(image,p);
cristy3ed852e2009-09-05 21:47:34 +00002460 return(MagickTrue);
2461}
2462
2463/*
2464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465% %
2466% %
2467% %
2468+ G e t P i x e l C a c h e C o l o r s p a c e %
2469% %
2470% %
2471% %
2472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473%
2474% GetPixelCacheColorspace() returns the class type of the pixel cache.
2475%
2476% The format of the GetPixelCacheColorspace() method is:
2477%
2478% Colorspace GetPixelCacheColorspace(Cache cache)
2479%
2480% A description of each parameter follows:
2481%
2482% o cache: the pixel cache.
2483%
2484*/
cristya6577ff2011-09-02 19:54:26 +00002485MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002486{
2487 CacheInfo
2488 *cache_info;
2489
2490 assert(cache != (Cache) NULL);
2491 cache_info=(CacheInfo *) cache;
2492 assert(cache_info->signature == MagickSignature);
2493 if (cache_info->debug != MagickFalse)
2494 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2495 cache_info->filename);
2496 return(cache_info->colorspace);
2497}
2498
2499/*
2500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501% %
2502% %
2503% %
2504+ G e t P i x e l C a c h e M e t h o d s %
2505% %
2506% %
2507% %
2508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509%
2510% GetPixelCacheMethods() initializes the CacheMethods structure.
2511%
2512% The format of the GetPixelCacheMethods() method is:
2513%
2514% void GetPixelCacheMethods(CacheMethods *cache_methods)
2515%
2516% A description of each parameter follows:
2517%
2518% o cache_methods: Specifies a pointer to a CacheMethods structure.
2519%
2520*/
cristya6577ff2011-09-02 19:54:26 +00002521MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002522{
2523 assert(cache_methods != (CacheMethods *) NULL);
2524 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2525 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2526 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002527 cache_methods->get_virtual_metacontent_from_handler=
2528 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002529 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2530 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002531 cache_methods->get_authentic_metacontent_from_handler=
2532 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002533 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2534 cache_methods->get_one_authentic_pixel_from_handler=
2535 GetOneAuthenticPixelFromCache;
2536 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2537 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2538 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2539}
2540
2541/*
2542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543% %
2544% %
2545% %
2546+ G e t P i x e l C a c h e N e x u s E x t e n t %
2547% %
2548% %
2549% %
2550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551%
cristy4c08aed2011-07-01 19:47:50 +00002552% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2553% corresponding with the last call to SetPixelCacheNexusPixels() or
2554% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002555%
2556% The format of the GetPixelCacheNexusExtent() method is:
2557%
2558% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2559% NexusInfo *nexus_info)
2560%
2561% A description of each parameter follows:
2562%
2563% o nexus_info: the nexus info.
2564%
2565*/
cristya6577ff2011-09-02 19:54:26 +00002566MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002567 NexusInfo *nexus_info)
2568{
2569 CacheInfo
2570 *cache_info;
2571
2572 MagickSizeType
2573 extent;
2574
cristy9f027d12011-09-21 01:17:17 +00002575 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002576 cache_info=(CacheInfo *) cache;
2577 assert(cache_info->signature == MagickSignature);
2578 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2579 if (extent == 0)
2580 return((MagickSizeType) cache_info->columns*cache_info->rows);
2581 return(extent);
2582}
2583
2584/*
2585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2586% %
2587% %
2588% %
cristy4c08aed2011-07-01 19:47:50 +00002589+ 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 +00002590% %
2591% %
2592% %
2593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2594%
cristy4c08aed2011-07-01 19:47:50 +00002595% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2596% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002597%
cristy4c08aed2011-07-01 19:47:50 +00002598% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002599%
cristy4c08aed2011-07-01 19:47:50 +00002600% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002601% NexusInfo *nexus_info)
2602%
2603% A description of each parameter follows:
2604%
2605% o cache: the pixel cache.
2606%
cristy4c08aed2011-07-01 19:47:50 +00002607% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002608%
2609*/
cristya6577ff2011-09-02 19:54:26 +00002610MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002611 NexusInfo *nexus_info)
2612{
2613 CacheInfo
2614 *cache_info;
2615
cristy9f027d12011-09-21 01:17:17 +00002616 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002617 cache_info=(CacheInfo *) cache;
2618 assert(cache_info->signature == MagickSignature);
2619 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002620 return((void *) NULL);
2621 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002622}
2623
2624/*
2625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2626% %
2627% %
2628% %
2629+ G e t P i x e l C a c h e N e x u s P i x e l s %
2630% %
2631% %
2632% %
2633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2634%
2635% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2636% cache nexus.
2637%
2638% The format of the GetPixelCacheNexusPixels() method is:
2639%
cristy4c08aed2011-07-01 19:47:50 +00002640% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002641% NexusInfo *nexus_info)
2642%
2643% A description of each parameter follows:
2644%
2645% o cache: the pixel cache.
2646%
2647% o nexus_info: the cache nexus to return the pixels.
2648%
2649*/
cristya6577ff2011-09-02 19:54:26 +00002650MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002651 NexusInfo *nexus_info)
2652{
2653 CacheInfo
2654 *cache_info;
2655
cristy9f027d12011-09-21 01:17:17 +00002656 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002657 cache_info=(CacheInfo *) cache;
2658 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002659 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002660 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002661 return(nexus_info->pixels);
2662}
2663
2664/*
2665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2666% %
2667% %
2668% %
cristy056ba772010-01-02 23:33:54 +00002669+ G e t P i x e l C a c h e P i x e l s %
2670% %
2671% %
2672% %
2673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2674%
2675% GetPixelCachePixels() returns the pixels associated with the specified image.
2676%
2677% The format of the GetPixelCachePixels() method is:
2678%
cristyf84a1932010-01-03 18:00:18 +00002679% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2680% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002681%
2682% A description of each parameter follows:
2683%
2684% o image: the image.
2685%
2686% o length: the pixel cache length.
2687%
cristyf84a1932010-01-03 18:00:18 +00002688% o exception: return any errors or warnings in this structure.
2689%
cristy056ba772010-01-02 23:33:54 +00002690*/
cristyd1dd6e42011-09-04 01:46:08 +00002691MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002692 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002693{
2694 CacheInfo
2695 *cache_info;
2696
2697 assert(image != (const Image *) NULL);
2698 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002699 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002700 assert(length != (MagickSizeType *) NULL);
2701 assert(exception != (ExceptionInfo *) NULL);
2702 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002703 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002704 assert(cache_info->signature == MagickSignature);
2705 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002706 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002707 return((void *) NULL);
2708 *length=cache_info->length;
2709 return((void *) cache_info->pixels);
2710}
2711
2712/*
2713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714% %
2715% %
2716% %
cristyb32b90a2009-09-07 21:45:48 +00002717+ 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 +00002718% %
2719% %
2720% %
2721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722%
2723% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2724%
2725% The format of the GetPixelCacheStorageClass() method is:
2726%
2727% ClassType GetPixelCacheStorageClass(Cache cache)
2728%
2729% A description of each parameter follows:
2730%
2731% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2732%
2733% o cache: the pixel cache.
2734%
2735*/
cristya6577ff2011-09-02 19:54:26 +00002736MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002737{
2738 CacheInfo
2739 *cache_info;
2740
2741 assert(cache != (Cache) NULL);
2742 cache_info=(CacheInfo *) cache;
2743 assert(cache_info->signature == MagickSignature);
2744 if (cache_info->debug != MagickFalse)
2745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2746 cache_info->filename);
2747 return(cache_info->storage_class);
2748}
2749
2750/*
2751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752% %
2753% %
2754% %
cristyb32b90a2009-09-07 21:45:48 +00002755+ G e t P i x e l C a c h e T i l e S i z e %
2756% %
2757% %
2758% %
2759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760%
2761% GetPixelCacheTileSize() returns the pixel cache tile size.
2762%
2763% The format of the GetPixelCacheTileSize() method is:
2764%
cristybb503372010-05-27 20:51:26 +00002765% void GetPixelCacheTileSize(const Image *image,size_t *width,
2766% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002767%
2768% A description of each parameter follows:
2769%
2770% o image: the image.
2771%
2772% o width: the optimize cache tile width in pixels.
2773%
2774% o height: the optimize cache tile height in pixels.
2775%
2776*/
cristya6577ff2011-09-02 19:54:26 +00002777MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002778 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002779{
cristy4c08aed2011-07-01 19:47:50 +00002780 CacheInfo
2781 *cache_info;
2782
cristyb32b90a2009-09-07 21:45:48 +00002783 assert(image != (Image *) NULL);
2784 assert(image->signature == MagickSignature);
2785 if (image->debug != MagickFalse)
2786 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002787 cache_info=(CacheInfo *) image->cache;
2788 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002789 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002790 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002791 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002792 *height=(*width);
2793}
2794
2795/*
2796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2797% %
2798% %
2799% %
2800+ G e t P i x e l C a c h e T y p e %
2801% %
2802% %
2803% %
2804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2805%
2806% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2807%
2808% The format of the GetPixelCacheType() method is:
2809%
2810% CacheType GetPixelCacheType(const Image *image)
2811%
2812% A description of each parameter follows:
2813%
2814% o image: the image.
2815%
2816*/
cristya6577ff2011-09-02 19:54:26 +00002817MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002818{
2819 CacheInfo
2820 *cache_info;
2821
2822 assert(image != (Image *) NULL);
2823 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002824 assert(image->cache != (Cache) NULL);
2825 cache_info=(CacheInfo *) image->cache;
2826 assert(cache_info->signature == MagickSignature);
2827 return(cache_info->type);
2828}
2829
2830/*
2831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832% %
2833% %
2834% %
cristy3ed852e2009-09-05 21:47:34 +00002835+ 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 %
2836% %
2837% %
2838% %
2839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2840%
2841% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2842% pixel cache. A virtual pixel is any pixel access that is outside the
2843% boundaries of the image cache.
2844%
2845% The format of the GetPixelCacheVirtualMethod() method is:
2846%
2847% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2848%
2849% A description of each parameter follows:
2850%
2851% o image: the image.
2852%
2853*/
cristyd1dd6e42011-09-04 01:46:08 +00002854MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002855{
2856 CacheInfo
2857 *cache_info;
2858
2859 assert(image != (Image *) NULL);
2860 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002861 assert(image->cache != (Cache) NULL);
2862 cache_info=(CacheInfo *) image->cache;
2863 assert(cache_info->signature == MagickSignature);
2864 return(cache_info->virtual_pixel_method);
2865}
2866
2867/*
2868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2869% %
2870% %
2871% %
cristy4c08aed2011-07-01 19:47:50 +00002872+ 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 +00002873% %
2874% %
2875% %
2876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2877%
cristy4c08aed2011-07-01 19:47:50 +00002878% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2879% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002880%
cristy4c08aed2011-07-01 19:47:50 +00002881% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002882%
cristy4c08aed2011-07-01 19:47:50 +00002883% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002884%
2885% A description of each parameter follows:
2886%
2887% o image: the image.
2888%
2889*/
cristy4c08aed2011-07-01 19:47:50 +00002890static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002891{
2892 CacheInfo
2893 *cache_info;
2894
cristy5c9e6f22010-09-17 17:31:01 +00002895 const int
2896 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002897
cristy4c08aed2011-07-01 19:47:50 +00002898 const void
2899 *metacontent;
2900
cristye7cc7cf2010-09-21 13:26:47 +00002901 assert(image != (const Image *) NULL);
2902 assert(image->signature == MagickSignature);
2903 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002904 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002905 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002906 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002907 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2908 cache_info->nexus_info[id]);
2909 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002910}
2911
2912/*
2913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2914% %
2915% %
2916% %
cristy4c08aed2011-07-01 19:47:50 +00002917+ 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 +00002918% %
2919% %
2920% %
2921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2922%
cristy4c08aed2011-07-01 19:47:50 +00002923% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2924% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002925%
cristy4c08aed2011-07-01 19:47:50 +00002926% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002927%
cristy4c08aed2011-07-01 19:47:50 +00002928% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002929% NexusInfo *nexus_info)
2930%
2931% A description of each parameter follows:
2932%
2933% o cache: the pixel cache.
2934%
cristy4c08aed2011-07-01 19:47:50 +00002935% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002936%
2937*/
cristya6577ff2011-09-02 19:54:26 +00002938MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002939 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002940{
2941 CacheInfo
2942 *cache_info;
2943
cristye7cc7cf2010-09-21 13:26:47 +00002944 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002945 cache_info=(CacheInfo *) cache;
2946 assert(cache_info->signature == MagickSignature);
2947 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002948 return((void *) NULL);
2949 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002950}
2951
2952/*
2953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2954% %
2955% %
2956% %
cristy4c08aed2011-07-01 19:47:50 +00002957% 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 +00002958% %
2959% %
2960% %
2961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962%
cristy4c08aed2011-07-01 19:47:50 +00002963% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2964% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2965% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002966%
cristy4c08aed2011-07-01 19:47:50 +00002967% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002968%
cristy4c08aed2011-07-01 19:47:50 +00002969% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002970%
2971% A description of each parameter follows:
2972%
2973% o image: the image.
2974%
2975*/
cristy4c08aed2011-07-01 19:47:50 +00002976MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002977{
2978 CacheInfo
2979 *cache_info;
2980
cristy2036f5c2010-09-19 21:18:17 +00002981 const int
2982 id = GetOpenMPThreadId();
2983
cristy4c08aed2011-07-01 19:47:50 +00002984 const void
2985 *metacontent;
2986
cristy3ed852e2009-09-05 21:47:34 +00002987 assert(image != (const Image *) NULL);
2988 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002989 assert(image->cache != (Cache) NULL);
2990 cache_info=(CacheInfo *) image->cache;
2991 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002992 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2993 (GetVirtualMetacontentFromHandler) NULL)
2994 {
2995 metacontent=cache_info->methods.
2996 get_virtual_metacontent_from_handler(image);
2997 return(metacontent);
2998 }
cristy2036f5c2010-09-19 21:18:17 +00002999 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003000 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3001 cache_info->nexus_info[id]);
3002 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003003}
3004
3005/*
3006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007% %
3008% %
3009% %
3010+ 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 %
3011% %
3012% %
3013% %
3014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3015%
3016% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3017% pixel cache as defined by the geometry parameters. A pointer to the pixels
3018% is returned if the pixels are transferred, otherwise a NULL is returned.
3019%
3020% The format of the GetVirtualPixelsFromNexus() method is:
3021%
cristy4c08aed2011-07-01 19:47:50 +00003022% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003023% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003024% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3025% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003026%
3027% A description of each parameter follows:
3028%
3029% o image: the image.
3030%
3031% o virtual_pixel_method: the virtual pixel method.
3032%
3033% o x,y,columns,rows: These values define the perimeter of a region of
3034% pixels.
3035%
3036% o nexus_info: the cache nexus to acquire.
3037%
3038% o exception: return any errors or warnings in this structure.
3039%
3040*/
3041
cristybb503372010-05-27 20:51:26 +00003042static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003043 DitherMatrix[64] =
3044 {
3045 0, 48, 12, 60, 3, 51, 15, 63,
3046 32, 16, 44, 28, 35, 19, 47, 31,
3047 8, 56, 4, 52, 11, 59, 7, 55,
3048 40, 24, 36, 20, 43, 27, 39, 23,
3049 2, 50, 14, 62, 1, 49, 13, 61,
3050 34, 18, 46, 30, 33, 17, 45, 29,
3051 10, 58, 6, 54, 9, 57, 5, 53,
3052 42, 26, 38, 22, 41, 25, 37, 21
3053 };
3054
cristybb503372010-05-27 20:51:26 +00003055static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003056{
cristybb503372010-05-27 20:51:26 +00003057 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003058 index;
3059
3060 index=x+DitherMatrix[x & 0x07]-32L;
3061 if (index < 0L)
3062 return(0L);
cristybb503372010-05-27 20:51:26 +00003063 if (index >= (ssize_t) columns)
3064 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003065 return(index);
3066}
3067
cristybb503372010-05-27 20:51:26 +00003068static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003069{
cristybb503372010-05-27 20:51:26 +00003070 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003071 index;
3072
3073 index=y+DitherMatrix[y & 0x07]-32L;
3074 if (index < 0L)
3075 return(0L);
cristybb503372010-05-27 20:51:26 +00003076 if (index >= (ssize_t) rows)
3077 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003078 return(index);
3079}
3080
cristybb503372010-05-27 20:51:26 +00003081static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003082{
3083 if (x < 0L)
3084 return(0L);
cristybb503372010-05-27 20:51:26 +00003085 if (x >= (ssize_t) columns)
3086 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003087 return(x);
3088}
3089
cristybb503372010-05-27 20:51:26 +00003090static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003091{
3092 if (y < 0L)
3093 return(0L);
cristybb503372010-05-27 20:51:26 +00003094 if (y >= (ssize_t) rows)
3095 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003096 return(y);
3097}
3098
cristybb503372010-05-27 20:51:26 +00003099static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003100{
cristybb503372010-05-27 20:51:26 +00003101 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003102}
3103
cristybb503372010-05-27 20:51:26 +00003104static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003105{
cristybb503372010-05-27 20:51:26 +00003106 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003107}
3108
cristybb503372010-05-27 20:51:26 +00003109static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3110 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003111{
3112 MagickModulo
3113 modulo;
3114
cristy6162bb42011-07-18 11:34:09 +00003115 /*
3116 Compute the remainder of dividing offset by extent. It returns not only
3117 the quotient (tile the offset falls in) but also the positive remainer
3118 within that tile such that 0 <= remainder < extent. This method is
3119 essentially a ldiv() using a floored modulo division rather than the
3120 normal default truncated modulo division.
3121 */
cristybb503372010-05-27 20:51:26 +00003122 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003123 if (offset < 0L)
3124 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003125 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003126 return(modulo);
3127}
3128
cristya6577ff2011-09-02 19:54:26 +00003129MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003130 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3131 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003132 ExceptionInfo *exception)
3133{
3134 CacheInfo
3135 *cache_info;
3136
3137 MagickOffsetType
3138 offset;
3139
3140 MagickSizeType
3141 length,
3142 number_pixels;
3143
3144 NexusInfo
3145 **virtual_nexus;
3146
cristy4c08aed2011-07-01 19:47:50 +00003147 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003148 *pixels,
cristy105ba3c2011-07-18 02:28:38 +00003149 virtual_pixel[MaxPixelChannels];
cristy3ed852e2009-09-05 21:47:34 +00003150
3151 RectangleInfo
3152 region;
3153
cristy4c08aed2011-07-01 19:47:50 +00003154 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003155 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003156
cristy4c08aed2011-07-01 19:47:50 +00003157 register const void
3158 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003159
cristy4c08aed2011-07-01 19:47:50 +00003160 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003161 *restrict q;
3162
cristybb503372010-05-27 20:51:26 +00003163 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003164 i,
3165 u;
cristy3ed852e2009-09-05 21:47:34 +00003166
cristy4c08aed2011-07-01 19:47:50 +00003167 register unsigned char
3168 *restrict s;
3169
cristy105ba3c2011-07-18 02:28:38 +00003170 ssize_t
3171 v;
3172
cristy4c08aed2011-07-01 19:47:50 +00003173 void
cristy105ba3c2011-07-18 02:28:38 +00003174 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003175
cristy3ed852e2009-09-05 21:47:34 +00003176 /*
3177 Acquire pixels.
3178 */
cristye7cc7cf2010-09-21 13:26:47 +00003179 assert(image != (const Image *) NULL);
3180 assert(image->signature == MagickSignature);
3181 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003182 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003183 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003184 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003185 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003186 region.x=x;
3187 region.y=y;
3188 region.width=columns;
3189 region.height=rows;
3190 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003191 if (pixels == (Quantum *) NULL)
3192 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003193 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003194 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3195 nexus_info->region.x;
3196 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3197 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003198 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3199 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003200 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3201 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003202 {
3203 MagickBooleanType
3204 status;
3205
3206 /*
3207 Pixel request is inside cache extents.
3208 */
cristy4c08aed2011-07-01 19:47:50 +00003209 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003210 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003211 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3212 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003213 return((const Quantum *) NULL);
3214 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003215 {
cristy4c08aed2011-07-01 19:47:50 +00003216 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003217 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003218 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003219 }
cristyacd2ed22011-08-30 01:44:23 +00003220 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003221 }
3222 /*
3223 Pixel request is outside cache extents.
3224 */
cristy4c08aed2011-07-01 19:47:50 +00003225 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003226 virtual_nexus=AcquirePixelCacheNexus(1);
3227 if (virtual_nexus == (NexusInfo **) NULL)
3228 {
cristy4c08aed2011-07-01 19:47:50 +00003229 if (virtual_nexus != (NexusInfo **) NULL)
3230 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003231 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3232 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003233 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003234 }
cristy105ba3c2011-07-18 02:28:38 +00003235 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3236 sizeof(*virtual_pixel));
3237 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003238 switch (virtual_pixel_method)
3239 {
cristy4c08aed2011-07-01 19:47:50 +00003240 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003241 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003242 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003243 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003244 case MaskVirtualPixelMethod:
3245 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003246 case EdgeVirtualPixelMethod:
3247 case CheckerTileVirtualPixelMethod:
3248 case HorizontalTileVirtualPixelMethod:
3249 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003250 {
cristy4c08aed2011-07-01 19:47:50 +00003251 if (cache_info->metacontent_extent != 0)
3252 {
cristy6162bb42011-07-18 11:34:09 +00003253 /*
3254 Acquire a metacontent buffer.
3255 */
cristya64b85d2011-09-14 01:02:31 +00003256 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003257 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003258 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003259 {
cristy4c08aed2011-07-01 19:47:50 +00003260 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3261 (void) ThrowMagickException(exception,GetMagickModule(),
3262 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3263 return((const Quantum *) NULL);
3264 }
cristy105ba3c2011-07-18 02:28:38 +00003265 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003266 cache_info->metacontent_extent);
3267 }
3268 switch (virtual_pixel_method)
3269 {
3270 case BlackVirtualPixelMethod:
3271 {
cristy30301712011-07-18 15:06:51 +00003272 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3273 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003274 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3275 break;
3276 }
3277 case GrayVirtualPixelMethod:
3278 {
cristy30301712011-07-18 15:06:51 +00003279 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003280 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3281 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003282 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3283 break;
3284 }
3285 case TransparentVirtualPixelMethod:
3286 {
cristy30301712011-07-18 15:06:51 +00003287 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3288 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003289 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3290 break;
3291 }
3292 case MaskVirtualPixelMethod:
3293 case WhiteVirtualPixelMethod:
3294 {
cristy30301712011-07-18 15:06:51 +00003295 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3296 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003297 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3298 break;
3299 }
3300 default:
3301 {
3302 SetPixelRed(image,image->background_color.red,virtual_pixel);
3303 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3304 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003305 if (image->colorspace == CMYKColorspace)
3306 SetPixelBlack(image,image->background_color.black,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003307 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3308 break;
3309 }
3310 }
cristy3ed852e2009-09-05 21:47:34 +00003311 break;
3312 }
3313 default:
cristy3ed852e2009-09-05 21:47:34 +00003314 break;
cristy3ed852e2009-09-05 21:47:34 +00003315 }
cristybb503372010-05-27 20:51:26 +00003316 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003317 {
cristybb503372010-05-27 20:51:26 +00003318 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003319 {
3320 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003321 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003322 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3323 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003324 {
3325 MagickModulo
3326 x_modulo,
3327 y_modulo;
3328
3329 /*
3330 Transfer a single pixel.
3331 */
3332 length=(MagickSizeType) 1;
3333 switch (virtual_pixel_method)
3334 {
cristy3ed852e2009-09-05 21:47:34 +00003335 default:
3336 {
3337 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003338 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003339 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003340 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003341 break;
3342 }
3343 case RandomVirtualPixelMethod:
3344 {
3345 if (cache_info->random_info == (RandomInfo *) NULL)
3346 cache_info->random_info=AcquireRandomInfo();
3347 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003348 RandomX(cache_info->random_info,cache_info->columns),
3349 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003350 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003351 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003352 break;
3353 }
3354 case DitherVirtualPixelMethod:
3355 {
3356 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003357 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003358 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003359 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003360 break;
3361 }
3362 case TileVirtualPixelMethod:
3363 {
3364 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3365 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3366 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003367 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003368 exception);
cristy4c08aed2011-07-01 19:47:50 +00003369 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003370 break;
3371 }
3372 case MirrorVirtualPixelMethod:
3373 {
3374 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3375 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003376 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003377 x_modulo.remainder-1L;
3378 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3379 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003380 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003381 y_modulo.remainder-1L;
3382 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003383 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003384 exception);
cristy4c08aed2011-07-01 19:47:50 +00003385 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003386 break;
3387 }
3388 case HorizontalTileEdgeVirtualPixelMethod:
3389 {
3390 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3391 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003392 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003393 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003394 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003395 break;
3396 }
3397 case VerticalTileEdgeVirtualPixelMethod:
3398 {
3399 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3400 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003401 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003402 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003403 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3404 break;
3405 }
3406 case BackgroundVirtualPixelMethod:
3407 case BlackVirtualPixelMethod:
3408 case GrayVirtualPixelMethod:
3409 case TransparentVirtualPixelMethod:
3410 case MaskVirtualPixelMethod:
3411 case WhiteVirtualPixelMethod:
3412 {
3413 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003414 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003415 break;
3416 }
3417 case EdgeVirtualPixelMethod:
3418 case CheckerTileVirtualPixelMethod:
3419 {
3420 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3421 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3422 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3423 {
3424 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003425 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003426 break;
3427 }
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3429 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3430 exception);
3431 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3432 break;
3433 }
3434 case HorizontalTileVirtualPixelMethod:
3435 {
3436 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3437 {
3438 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003439 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003440 break;
3441 }
3442 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3443 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3444 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3445 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3446 exception);
3447 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3448 break;
3449 }
3450 case VerticalTileVirtualPixelMethod:
3451 {
3452 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3453 {
3454 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003455 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003456 break;
3457 }
3458 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3459 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3460 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3461 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3462 exception);
3463 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003464 break;
3465 }
3466 }
cristy4c08aed2011-07-01 19:47:50 +00003467 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003468 break;
cristyed231572011-07-14 02:18:59 +00003469 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003470 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003471 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003472 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003473 {
3474 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3475 s+=cache_info->metacontent_extent;
3476 }
cristy3ed852e2009-09-05 21:47:34 +00003477 continue;
3478 }
3479 /*
3480 Transfer a run of pixels.
3481 */
cristy4c08aed2011-07-01 19:47:50 +00003482 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3483 length,1UL,*virtual_nexus,exception);
3484 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003485 break;
cristy4c08aed2011-07-01 19:47:50 +00003486 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003487 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3488 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003489 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003490 {
cristy4c08aed2011-07-01 19:47:50 +00003491 (void) memcpy(s,r,(size_t) length);
3492 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003493 }
3494 }
3495 }
cristy4c08aed2011-07-01 19:47:50 +00003496 /*
3497 Free resources.
3498 */
cristy105ba3c2011-07-18 02:28:38 +00003499 if (virtual_metacontent != (void *) NULL)
3500 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003501 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3502 return(pixels);
3503}
3504
3505/*
3506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507% %
3508% %
3509% %
3510+ G e t V i r t u a l P i x e l C a c h e %
3511% %
3512% %
3513% %
3514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3515%
3516% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3517% cache as defined by the geometry parameters. A pointer to the pixels
3518% is returned if the pixels are transferred, otherwise a NULL is returned.
3519%
3520% The format of the GetVirtualPixelCache() method is:
3521%
cristy4c08aed2011-07-01 19:47:50 +00003522% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003523% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3524% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003525% ExceptionInfo *exception)
3526%
3527% A description of each parameter follows:
3528%
3529% o image: the image.
3530%
3531% o virtual_pixel_method: the virtual pixel method.
3532%
3533% o x,y,columns,rows: These values define the perimeter of a region of
3534% pixels.
3535%
3536% o exception: return any errors or warnings in this structure.
3537%
3538*/
cristy4c08aed2011-07-01 19:47:50 +00003539static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003540 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3541 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003542{
3543 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003544 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003545
cristy5c9e6f22010-09-17 17:31:01 +00003546 const int
3547 id = GetOpenMPThreadId();
3548
cristy4c08aed2011-07-01 19:47:50 +00003549 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003550 *p;
cristy4c08aed2011-07-01 19:47:50 +00003551
cristye7cc7cf2010-09-21 13:26:47 +00003552 assert(image != (const Image *) NULL);
3553 assert(image->signature == MagickSignature);
3554 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003555 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003556 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003557 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003558 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003559 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003560 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003561}
3562
3563/*
3564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565% %
3566% %
3567% %
3568% G e t V i r t u a l P i x e l Q u e u e %
3569% %
3570% %
3571% %
3572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3573%
cristy4c08aed2011-07-01 19:47:50 +00003574% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3575% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003576%
3577% The format of the GetVirtualPixelQueue() method is:
3578%
cristy4c08aed2011-07-01 19:47:50 +00003579% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003580%
3581% A description of each parameter follows:
3582%
3583% o image: the image.
3584%
3585*/
cristy4c08aed2011-07-01 19:47:50 +00003586MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003587{
3588 CacheInfo
3589 *cache_info;
3590
cristy2036f5c2010-09-19 21:18:17 +00003591 const int
3592 id = GetOpenMPThreadId();
3593
cristy3ed852e2009-09-05 21:47:34 +00003594 assert(image != (const Image *) NULL);
3595 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003596 assert(image->cache != (Cache) NULL);
3597 cache_info=(CacheInfo *) image->cache;
3598 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003599 if (cache_info->methods.get_virtual_pixels_handler !=
3600 (GetVirtualPixelsHandler) NULL)
3601 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003602 assert(id < (int) cache_info->number_threads);
3603 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003604}
3605
3606/*
3607%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608% %
3609% %
3610% %
3611% G e t V i r t u a l P i x e l s %
3612% %
3613% %
3614% %
3615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3616%
3617% GetVirtualPixels() returns an immutable pixel region. If the
3618% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003619% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003620% copy of the pixels or it may point to the original pixels in memory.
3621% Performance is maximized if the selected region is part of one row, or one
3622% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003623% (without a copy) if the image is in memory, or in a memory-mapped file. The
3624% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003625%
3626% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003627% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3628% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3629% access the meta-content (of type void) corresponding to the the
3630% region.
cristy3ed852e2009-09-05 21:47:34 +00003631%
3632% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3633%
3634% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3635% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3636% GetCacheViewAuthenticPixels() instead.
3637%
3638% The format of the GetVirtualPixels() method is:
3639%
cristy4c08aed2011-07-01 19:47:50 +00003640% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003641% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003642% ExceptionInfo *exception)
3643%
3644% A description of each parameter follows:
3645%
3646% o image: the image.
3647%
3648% o x,y,columns,rows: These values define the perimeter of a region of
3649% pixels.
3650%
3651% o exception: return any errors or warnings in this structure.
3652%
3653*/
cristy4c08aed2011-07-01 19:47:50 +00003654MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003655 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3656 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003657{
3658 CacheInfo
3659 *cache_info;
3660
cristy2036f5c2010-09-19 21:18:17 +00003661 const int
3662 id = GetOpenMPThreadId();
3663
cristy4c08aed2011-07-01 19:47:50 +00003664 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003665 *p;
cristy4c08aed2011-07-01 19:47:50 +00003666
cristy3ed852e2009-09-05 21:47:34 +00003667 assert(image != (const Image *) NULL);
3668 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003669 assert(image->cache != (Cache) NULL);
3670 cache_info=(CacheInfo *) image->cache;
3671 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003672 if (cache_info->methods.get_virtual_pixel_handler !=
3673 (GetVirtualPixelHandler) NULL)
3674 return(cache_info->methods.get_virtual_pixel_handler(image,
3675 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003676 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003677 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003678 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003679 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003680}
3681
3682/*
3683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3684% %
3685% %
3686% %
3687+ 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 %
3688% %
3689% %
3690% %
3691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3692%
cristy4c08aed2011-07-01 19:47:50 +00003693% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3694% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003695%
3696% The format of the GetVirtualPixelsCache() method is:
3697%
cristy4c08aed2011-07-01 19:47:50 +00003698% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003699%
3700% A description of each parameter follows:
3701%
3702% o image: the image.
3703%
3704*/
cristy4c08aed2011-07-01 19:47:50 +00003705static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003706{
3707 CacheInfo
3708 *cache_info;
3709
cristy5c9e6f22010-09-17 17:31:01 +00003710 const int
3711 id = GetOpenMPThreadId();
3712
cristye7cc7cf2010-09-21 13:26:47 +00003713 assert(image != (const Image *) NULL);
3714 assert(image->signature == MagickSignature);
3715 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003716 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003717 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003718 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003719 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003720}
3721
3722/*
3723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3724% %
3725% %
3726% %
3727+ G e t V i r t u a l P i x e l s N e x u s %
3728% %
3729% %
3730% %
3731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3732%
3733% GetVirtualPixelsNexus() returns the pixels associated with the specified
3734% cache nexus.
3735%
3736% The format of the GetVirtualPixelsNexus() method is:
3737%
cristy4c08aed2011-07-01 19:47:50 +00003738% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003739% NexusInfo *nexus_info)
3740%
3741% A description of each parameter follows:
3742%
3743% o cache: the pixel cache.
3744%
3745% o nexus_info: the cache nexus to return the colormap pixels.
3746%
3747*/
cristya6577ff2011-09-02 19:54:26 +00003748MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003749 NexusInfo *nexus_info)
3750{
3751 CacheInfo
3752 *cache_info;
3753
cristye7cc7cf2010-09-21 13:26:47 +00003754 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003755 cache_info=(CacheInfo *) cache;
3756 assert(cache_info->signature == MagickSignature);
3757 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003758 return((Quantum *) NULL);
3759 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003760}
3761
3762/*
3763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3764% %
3765% %
3766% %
3767+ M a s k P i x e l C a c h e N e x u s %
3768% %
3769% %
3770% %
3771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3772%
3773% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3774% The method returns MagickTrue if the pixel region is masked, otherwise
3775% MagickFalse.
3776%
3777% The format of the MaskPixelCacheNexus() method is:
3778%
3779% MagickBooleanType MaskPixelCacheNexus(Image *image,
3780% NexusInfo *nexus_info,ExceptionInfo *exception)
3781%
3782% A description of each parameter follows:
3783%
3784% o image: the image.
3785%
3786% o nexus_info: the cache nexus to clip.
3787%
3788% o exception: return any errors or warnings in this structure.
3789%
3790*/
3791
cristy4c08aed2011-07-01 19:47:50 +00003792static inline void MagickPixelCompositeMask(const PixelInfo *p,
3793 const MagickRealType alpha,const PixelInfo *q,
3794 const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003795{
3796 MagickRealType
3797 gamma;
3798
cristyaa83c2c2011-09-21 13:36:25 +00003799 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003800 {
3801 *composite=(*q);
3802 return;
3803 }
3804 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3805 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003806 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3807 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3808 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003809 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003810 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003811}
3812
3813static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3814 ExceptionInfo *exception)
3815{
3816 CacheInfo
3817 *cache_info;
3818
cristy4c08aed2011-07-01 19:47:50 +00003819 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003820 alpha,
3821 beta;
3822
3823 MagickSizeType
3824 number_pixels;
3825
3826 NexusInfo
3827 **clip_nexus,
3828 **image_nexus;
3829
cristy4c08aed2011-07-01 19:47:50 +00003830 register const Quantum
3831 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003832 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003833
cristy4c08aed2011-07-01 19:47:50 +00003834 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003835 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003836
cristye076a6e2010-08-15 19:59:43 +00003837 register ssize_t
3838 i;
3839
cristy3ed852e2009-09-05 21:47:34 +00003840 /*
3841 Apply clip mask.
3842 */
3843 if (image->debug != MagickFalse)
3844 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3845 if (image->mask == (Image *) NULL)
3846 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003847 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003848 if (cache_info == (Cache) NULL)
3849 return(MagickFalse);
3850 image_nexus=AcquirePixelCacheNexus(1);
3851 clip_nexus=AcquirePixelCacheNexus(1);
3852 if ((image_nexus == (NexusInfo **) NULL) ||
3853 (clip_nexus == (NexusInfo **) NULL))
3854 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003855 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3856 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3857 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003858 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003859 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3860 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3861 nexus_info->region.height,clip_nexus[0],&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00003862 GetPixelInfo(image,&alpha);
3863 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003864 number_pixels=(MagickSizeType) nexus_info->region.width*
3865 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003866 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003867 {
cristy4c08aed2011-07-01 19:47:50 +00003868 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003869 break;
cristy4c08aed2011-07-01 19:47:50 +00003870 SetPixelInfo(image,p,&alpha);
3871 SetPixelInfo(image,q,&beta);
3872 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3873 &alpha,alpha.alpha,&beta);
3874 SetPixelRed(image,ClampToQuantum(beta.red),q);
3875 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3876 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3877 if (cache_info->colorspace == CMYKColorspace)
3878 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3879 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003880 p++;
3881 q++;
3882 r++;
3883 }
3884 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3885 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003886 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003887 return(MagickFalse);
3888 return(MagickTrue);
3889}
3890
3891/*
3892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3893% %
3894% %
3895% %
3896+ O p e n P i x e l C a c h e %
3897% %
3898% %
3899% %
3900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3901%
3902% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3903% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003904% metacontent, and memory mapping the cache if it is disk based. The cache
3905% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003906%
3907% The format of the OpenPixelCache() method is:
3908%
3909% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3910% ExceptionInfo *exception)
3911%
3912% A description of each parameter follows:
3913%
3914% o image: the image.
3915%
3916% o mode: ReadMode, WriteMode, or IOMode.
3917%
3918% o exception: return any errors or warnings in this structure.
3919%
3920*/
3921
cristyd43a46b2010-01-21 02:13:41 +00003922static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003923{
3924 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003925 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003926 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003927 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003928 {
3929 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003930 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003931 cache_info->length);
3932 }
3933}
3934
3935static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3936{
3937 CacheInfo
3938 *cache_info;
3939
3940 MagickOffsetType
3941 count,
3942 extent,
3943 offset;
3944
3945 cache_info=(CacheInfo *) image->cache;
3946 if (image->debug != MagickFalse)
3947 {
3948 char
3949 format[MaxTextExtent],
3950 message[MaxTextExtent];
3951
cristyb9080c92009-12-01 20:13:26 +00003952 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003953 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003954 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003955 cache_info->cache_filename,cache_info->file,format);
3956 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3957 }
3958 if (length != (MagickSizeType) ((MagickOffsetType) length))
3959 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003960 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003961 if (extent < 0)
3962 return(MagickFalse);
3963 if ((MagickSizeType) extent >= length)
3964 return(MagickTrue);
3965 offset=(MagickOffsetType) length-1;
3966 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3967 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3968}
3969
3970static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3971 ExceptionInfo *exception)
3972{
cristy3ed852e2009-09-05 21:47:34 +00003973 CacheInfo
3974 *cache_info,
3975 source_info;
3976
cristyf3a6a9d2010-11-07 21:02:56 +00003977 char
3978 format[MaxTextExtent],
3979 message[MaxTextExtent];
3980
cristy4c08aed2011-07-01 19:47:50 +00003981 MagickBooleanType
3982 status;
3983
cristy3ed852e2009-09-05 21:47:34 +00003984 MagickSizeType
3985 length,
3986 number_pixels;
3987
cristy3ed852e2009-09-05 21:47:34 +00003988 size_t
cristye076a6e2010-08-15 19:59:43 +00003989 columns,
cristy3ed852e2009-09-05 21:47:34 +00003990 packet_size;
3991
cristye7cc7cf2010-09-21 13:26:47 +00003992 assert(image != (const Image *) NULL);
3993 assert(image->signature == MagickSignature);
3994 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003995 if (image->debug != MagickFalse)
3996 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3997 if ((image->columns == 0) || (image->rows == 0))
3998 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3999 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004000 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004001 source_info=(*cache_info);
4002 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004003 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004004 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004005 cache_info->storage_class=image->storage_class;
4006 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004007 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004008 cache_info->rows=image->rows;
4009 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004010 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004011 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004012 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004013 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004014 if (image->ping != MagickFalse)
4015 {
cristy73724512010-04-12 14:43:14 +00004016 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004017 cache_info->pixels=(Quantum *) NULL;
4018 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004019 cache_info->length=0;
4020 return(MagickTrue);
4021 }
cristy3ed852e2009-09-05 21:47:34 +00004022 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004023 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004024 if (image->metacontent_extent != 0)
4025 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004026 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004027 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004028 if (cache_info->columns != columns)
4029 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4030 image->filename);
4031 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004032 if ((cache_info->type != UndefinedCache) &&
4033 (cache_info->columns <= source_info.columns) &&
4034 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004035 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004036 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4037 {
4038 /*
4039 Inline pixel cache clone optimization.
4040 */
4041 if ((cache_info->columns == source_info.columns) &&
4042 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004043 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004044 (cache_info->metacontent_extent == source_info.metacontent_extent))
4045 return(MagickTrue);
4046 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4047 }
cristy3ed852e2009-09-05 21:47:34 +00004048 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004049 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004050 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004051 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4052 {
4053 status=AcquireMagickResource(MemoryResource,cache_info->length);
4054 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4055 (cache_info->type == MemoryCache))
4056 {
cristyd43a46b2010-01-21 02:13:41 +00004057 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004058 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004059 cache_info->pixels=source_info.pixels;
4060 else
4061 {
4062 /*
4063 Create memory pixel cache.
4064 */
cristy4c08aed2011-07-01 19:47:50 +00004065 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004066 if (image->debug != MagickFalse)
4067 {
cristy97e7a572009-12-05 15:07:53 +00004068 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004069 format);
cristyb51dff52011-05-19 16:55:47 +00004070 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004071 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4072 cache_info->filename,cache_info->mapped != MagickFalse ?
4073 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004074 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004075 format);
cristy3ed852e2009-09-05 21:47:34 +00004076 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4077 message);
4078 }
cristy3ed852e2009-09-05 21:47:34 +00004079 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004080 cache_info->metacontent=(void *) NULL;
4081 if (cache_info->metacontent_extent != 0)
4082 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004083 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004084 if (source_info.storage_class != UndefinedClass)
4085 {
cristy4c08aed2011-07-01 19:47:50 +00004086 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004087 exception);
4088 RelinquishPixelCachePixels(&source_info);
4089 }
cristy4c08aed2011-07-01 19:47:50 +00004090 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004091 }
4092 }
4093 RelinquishMagickResource(MemoryResource,cache_info->length);
4094 }
4095 /*
4096 Create pixel cache on disk.
4097 */
4098 status=AcquireMagickResource(DiskResource,cache_info->length);
4099 if (status == MagickFalse)
4100 {
4101 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4102 "CacheResourcesExhausted","`%s'",image->filename);
4103 return(MagickFalse);
4104 }
4105 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4106 {
4107 RelinquishMagickResource(DiskResource,cache_info->length);
4108 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4109 image->filename);
4110 return(MagickFalse);
4111 }
4112 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4113 cache_info->length);
4114 if (status == MagickFalse)
4115 {
4116 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4117 image->filename);
4118 return(MagickFalse);
4119 }
cristyed231572011-07-14 02:18:59 +00004120 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004121 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004122 status=AcquireMagickResource(AreaResource,cache_info->length);
4123 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4124 cache_info->type=DiskCache;
4125 else
4126 {
4127 status=AcquireMagickResource(MapResource,cache_info->length);
4128 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4129 (cache_info->type != MemoryCache))
4130 cache_info->type=DiskCache;
4131 else
4132 {
cristy4c08aed2011-07-01 19:47:50 +00004133 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004134 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004135 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004136 {
cristy3ed852e2009-09-05 21:47:34 +00004137 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004138 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004139 }
4140 else
4141 {
4142 /*
4143 Create file-backed memory-mapped pixel cache.
4144 */
cristy4c08aed2011-07-01 19:47:50 +00004145 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004146 (void) ClosePixelCacheOnDisk(cache_info);
4147 cache_info->type=MapCache;
4148 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004149 cache_info->metacontent=(void *) NULL;
4150 if (cache_info->metacontent_extent != 0)
4151 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004152 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004153 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004154 {
4155 status=ClonePixelCachePixels(cache_info,&source_info,
4156 exception);
4157 RelinquishPixelCachePixels(&source_info);
4158 }
4159 if (image->debug != MagickFalse)
4160 {
cristy97e7a572009-12-05 15:07:53 +00004161 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004162 format);
cristyb51dff52011-05-19 16:55:47 +00004163 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004164 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004165 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004166 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004167 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004168 format);
cristy3ed852e2009-09-05 21:47:34 +00004169 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4170 message);
4171 }
cristy4c08aed2011-07-01 19:47:50 +00004172 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004173 }
4174 }
4175 RelinquishMagickResource(MapResource,cache_info->length);
4176 }
cristy4c08aed2011-07-01 19:47:50 +00004177 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004178 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4179 {
4180 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4181 RelinquishPixelCachePixels(&source_info);
4182 }
4183 if (image->debug != MagickFalse)
4184 {
cristyb9080c92009-12-01 20:13:26 +00004185 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004186 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004187 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004188 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004189 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004190 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004191 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4192 }
cristy4c08aed2011-07-01 19:47:50 +00004193 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004194}
4195
4196/*
4197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4198% %
4199% %
4200% %
4201+ P e r s i s t P i x e l C a c h e %
4202% %
4203% %
4204% %
4205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4206%
4207% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4208% persistent pixel cache is one that resides on disk and is not destroyed
4209% when the program exits.
4210%
4211% The format of the PersistPixelCache() method is:
4212%
4213% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4214% const MagickBooleanType attach,MagickOffsetType *offset,
4215% ExceptionInfo *exception)
4216%
4217% A description of each parameter follows:
4218%
4219% o image: the image.
4220%
4221% o filename: the persistent pixel cache filename.
4222%
cristyf3a6a9d2010-11-07 21:02:56 +00004223% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004224%
cristy3ed852e2009-09-05 21:47:34 +00004225% o initialize: A value other than zero initializes the persistent pixel
4226% cache.
4227%
4228% o offset: the offset in the persistent cache to store pixels.
4229%
4230% o exception: return any errors or warnings in this structure.
4231%
4232*/
4233MagickExport MagickBooleanType PersistPixelCache(Image *image,
4234 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4235 ExceptionInfo *exception)
4236{
4237 CacheInfo
4238 *cache_info,
4239 *clone_info;
4240
4241 Image
4242 clone_image;
4243
cristy3ed852e2009-09-05 21:47:34 +00004244 MagickBooleanType
4245 status;
4246
cristye076a6e2010-08-15 19:59:43 +00004247 ssize_t
4248 page_size;
4249
cristy3ed852e2009-09-05 21:47:34 +00004250 assert(image != (Image *) NULL);
4251 assert(image->signature == MagickSignature);
4252 if (image->debug != MagickFalse)
4253 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4254 assert(image->cache != (void *) NULL);
4255 assert(filename != (const char *) NULL);
4256 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004257 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004258 cache_info=(CacheInfo *) image->cache;
4259 assert(cache_info->signature == MagickSignature);
4260 if (attach != MagickFalse)
4261 {
4262 /*
cristy01b7eb02009-09-10 23:10:14 +00004263 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004264 */
4265 if (image->debug != MagickFalse)
4266 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004267 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004268 (void) CopyMagickString(cache_info->cache_filename,filename,
4269 MaxTextExtent);
4270 cache_info->type=DiskCache;
4271 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004272 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004273 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004274 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004275 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004276 }
cristy01b7eb02009-09-10 23:10:14 +00004277 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4278 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004279 {
cristyf84a1932010-01-03 18:00:18 +00004280 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004281 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004282 (cache_info->reference_count == 1))
4283 {
4284 int
4285 status;
4286
4287 /*
cristy01b7eb02009-09-10 23:10:14 +00004288 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004289 */
cristy320684d2011-09-23 14:55:47 +00004290 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004291 if (status == 0)
4292 {
4293 (void) CopyMagickString(cache_info->cache_filename,filename,
4294 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004295 *offset+=cache_info->length+page_size-(cache_info->length %
4296 page_size);
cristyf84a1932010-01-03 18:00:18 +00004297 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004298 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004299 if (image->debug != MagickFalse)
4300 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4301 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004302 return(MagickTrue);
4303 }
4304 }
cristyf84a1932010-01-03 18:00:18 +00004305 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004306 }
4307 /*
cristy01b7eb02009-09-10 23:10:14 +00004308 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004309 */
4310 clone_image=(*image);
4311 clone_info=(CacheInfo *) clone_image.cache;
4312 image->cache=ClonePixelCache(cache_info);
4313 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4314 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4315 cache_info->type=DiskCache;
4316 cache_info->offset=(*offset);
4317 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004318 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004319 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004320 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004321 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004322 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4323 return(status);
4324}
4325
4326/*
4327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4328% %
4329% %
4330% %
4331+ Q u e u e A u t h e n t i c N e x u s %
4332% %
4333% %
4334% %
4335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4336%
4337% QueueAuthenticNexus() allocates an region to store image pixels as defined
4338% by the region rectangle and returns a pointer to the region. This region is
4339% subsequently transferred from the pixel cache with
4340% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4341% pixels are transferred, otherwise a NULL is returned.
4342%
4343% The format of the QueueAuthenticNexus() method is:
4344%
cristy4c08aed2011-07-01 19:47:50 +00004345% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004346% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004347% NexusInfo *nexus_info,ExceptionInfo *exception)
4348%
4349% A description of each parameter follows:
4350%
4351% o image: the image.
4352%
4353% o x,y,columns,rows: These values define the perimeter of a region of
4354% pixels.
4355%
4356% o nexus_info: the cache nexus to set.
4357%
4358% o exception: return any errors or warnings in this structure.
4359%
4360*/
cristya6577ff2011-09-02 19:54:26 +00004361MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004362 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4363 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004364{
4365 CacheInfo
4366 *cache_info;
4367
4368 MagickOffsetType
4369 offset;
4370
4371 MagickSizeType
4372 number_pixels;
4373
4374 RectangleInfo
4375 region;
4376
4377 /*
4378 Validate pixel cache geometry.
4379 */
cristye7cc7cf2010-09-21 13:26:47 +00004380 assert(image != (const Image *) NULL);
4381 assert(image->signature == MagickSignature);
4382 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004383 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4384 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004385 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004386 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004387 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4388 {
4389 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4390 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004391 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004392 }
cristybb503372010-05-27 20:51:26 +00004393 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4394 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004395 {
4396 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4397 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004398 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004399 }
4400 offset=(MagickOffsetType) y*cache_info->columns+x;
4401 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004402 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004403 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4404 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4405 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004406 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004407 /*
4408 Return pixel cache.
4409 */
4410 region.x=x;
4411 region.y=y;
4412 region.width=columns;
4413 region.height=rows;
4414 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4415}
4416
4417/*
4418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4419% %
4420% %
4421% %
4422+ 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 %
4423% %
4424% %
4425% %
4426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4427%
4428% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4429% defined by the region rectangle and returns a pointer to the region. This
4430% region is subsequently transferred from the pixel cache with
4431% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4432% pixels are transferred, otherwise a NULL is returned.
4433%
4434% The format of the QueueAuthenticPixelsCache() method is:
4435%
cristy4c08aed2011-07-01 19:47:50 +00004436% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004437% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004438% ExceptionInfo *exception)
4439%
4440% A description of each parameter follows:
4441%
4442% o image: the image.
4443%
4444% o x,y,columns,rows: These values define the perimeter of a region of
4445% pixels.
4446%
4447% o exception: return any errors or warnings in this structure.
4448%
4449*/
cristy4c08aed2011-07-01 19:47:50 +00004450static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004451 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004452 ExceptionInfo *exception)
4453{
4454 CacheInfo
4455 *cache_info;
4456
cristy5c9e6f22010-09-17 17:31:01 +00004457 const int
4458 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004459
cristy4c08aed2011-07-01 19:47:50 +00004460 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004461 *q;
cristy4c08aed2011-07-01 19:47:50 +00004462
cristye7cc7cf2010-09-21 13:26:47 +00004463 assert(image != (const Image *) NULL);
4464 assert(image->signature == MagickSignature);
4465 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004466 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004467 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004468 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00004469 q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
cristy4c08aed2011-07-01 19:47:50 +00004470 exception);
cristyacd2ed22011-08-30 01:44:23 +00004471 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004472}
4473
4474/*
4475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4476% %
4477% %
4478% %
4479% Q u e u e A u t h e n t i c P i x e l s %
4480% %
4481% %
4482% %
4483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4484%
4485% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004486% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004487% region is returned, otherwise NULL is returned. The returned pointer may
4488% point to a temporary working buffer for the pixels or it may point to the
4489% final location of the pixels in memory.
4490%
4491% Write-only access means that any existing pixel values corresponding to
4492% the region are ignored. This is useful if the initial image is being
4493% created from scratch, or if the existing pixel values are to be
4494% completely replaced without need to refer to their pre-existing values.
4495% The application is free to read and write the pixel buffer returned by
4496% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4497% initialize the pixel array values. Initializing pixel array values is the
4498% application's responsibility.
4499%
4500% Performance is maximized if the selected region is part of one row, or
4501% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004502% pixels in-place (without a copy) if the image is in memory, or in a
4503% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004504% by the user.
4505%
4506% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004507% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4508% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4509% obtain the meta-content (of type void) corresponding to the region.
4510% Once the Quantum (and/or Quantum) array has been updated, the
4511% changes must be saved back to the underlying image using
4512% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004513%
4514% The format of the QueueAuthenticPixels() method is:
4515%
cristy4c08aed2011-07-01 19:47:50 +00004516% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004517% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004518% ExceptionInfo *exception)
4519%
4520% A description of each parameter follows:
4521%
4522% o image: the image.
4523%
4524% o x,y,columns,rows: These values define the perimeter of a region of
4525% pixels.
4526%
4527% o exception: return any errors or warnings in this structure.
4528%
4529*/
cristy4c08aed2011-07-01 19:47:50 +00004530MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004531 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004532 ExceptionInfo *exception)
4533{
4534 CacheInfo
4535 *cache_info;
4536
cristy2036f5c2010-09-19 21:18:17 +00004537 const int
4538 id = GetOpenMPThreadId();
4539
cristy4c08aed2011-07-01 19:47:50 +00004540 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004541 *q;
cristy4c08aed2011-07-01 19:47:50 +00004542
cristy3ed852e2009-09-05 21:47:34 +00004543 assert(image != (Image *) NULL);
4544 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004545 assert(image->cache != (Cache) NULL);
4546 cache_info=(CacheInfo *) image->cache;
4547 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004548 if (cache_info->methods.queue_authentic_pixels_handler !=
4549 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004550 {
cristyacd2ed22011-08-30 01:44:23 +00004551 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004552 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004553 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004554 }
cristy2036f5c2010-09-19 21:18:17 +00004555 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00004556 q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
cristy4c08aed2011-07-01 19:47:50 +00004557 exception);
cristyacd2ed22011-08-30 01:44:23 +00004558 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004559}
4560
4561/*
4562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4563% %
4564% %
4565% %
cristy4c08aed2011-07-01 19:47:50 +00004566+ 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 +00004567% %
4568% %
4569% %
4570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4571%
cristy4c08aed2011-07-01 19:47:50 +00004572% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004573% the pixel cache.
4574%
cristy4c08aed2011-07-01 19:47:50 +00004575% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004576%
cristy4c08aed2011-07-01 19:47:50 +00004577% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004578% NexusInfo *nexus_info,ExceptionInfo *exception)
4579%
4580% A description of each parameter follows:
4581%
4582% o cache_info: the pixel cache.
4583%
cristy4c08aed2011-07-01 19:47:50 +00004584% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004585%
4586% o exception: return any errors or warnings in this structure.
4587%
4588*/
cristy4c08aed2011-07-01 19:47:50 +00004589static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004590 NexusInfo *nexus_info,ExceptionInfo *exception)
4591{
4592 MagickOffsetType
4593 count,
4594 offset;
4595
4596 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004597 extent,
4598 length;
cristy3ed852e2009-09-05 21:47:34 +00004599
cristybb503372010-05-27 20:51:26 +00004600 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004601 y;
4602
cristy4c08aed2011-07-01 19:47:50 +00004603 register unsigned char
4604 *restrict q;
4605
cristybb503372010-05-27 20:51:26 +00004606 size_t
cristy3ed852e2009-09-05 21:47:34 +00004607 rows;
4608
cristy4c08aed2011-07-01 19:47:50 +00004609 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004610 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004611 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004612 return(MagickTrue);
4613 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4614 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004615 length=(MagickSizeType) nexus_info->region.width*
4616 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004617 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004618 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004619 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004620 switch (cache_info->type)
4621 {
4622 case MemoryCache:
4623 case MapCache:
4624 {
cristy4c08aed2011-07-01 19:47:50 +00004625 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004626 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004627
4628 /*
cristy4c08aed2011-07-01 19:47:50 +00004629 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004630 */
cristydd341db2010-03-04 19:06:38 +00004631 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004632 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004633 {
cristy48078b12010-09-23 17:11:01 +00004634 length=extent;
cristydd341db2010-03-04 19:06:38 +00004635 rows=1UL;
4636 }
cristy4c08aed2011-07-01 19:47:50 +00004637 p=(unsigned char *) cache_info->metacontent+offset*
4638 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004639 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004640 {
cristy8f036fe2010-09-18 02:02:00 +00004641 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004642 p+=cache_info->metacontent_extent*cache_info->columns;
4643 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004644 }
4645 break;
4646 }
4647 case DiskCache:
4648 {
4649 /*
cristy4c08aed2011-07-01 19:47:50 +00004650 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004651 */
4652 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4653 {
4654 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4655 cache_info->cache_filename);
4656 return(MagickFalse);
4657 }
cristydd341db2010-03-04 19:06:38 +00004658 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004659 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004660 {
cristy48078b12010-09-23 17:11:01 +00004661 length=extent;
cristydd341db2010-03-04 19:06:38 +00004662 rows=1UL;
4663 }
cristy48078b12010-09-23 17:11:01 +00004664 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004665 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004666 {
cristy48078b12010-09-23 17:11:01 +00004667 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004668 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004669 cache_info->metacontent_extent,length,(unsigned char *) q);
4670 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004671 break;
4672 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004673 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004674 }
cristybb503372010-05-27 20:51:26 +00004675 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004676 {
4677 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4678 cache_info->cache_filename);
4679 return(MagickFalse);
4680 }
4681 break;
4682 }
4683 default:
4684 break;
4685 }
4686 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004687 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004688 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004689 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004690 nexus_info->region.width,(double) nexus_info->region.height,(double)
4691 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004692 return(MagickTrue);
4693}
4694
4695/*
4696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4697% %
4698% %
4699% %
4700+ R e a d P i x e l C a c h e P i x e l s %
4701% %
4702% %
4703% %
4704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4705%
4706% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4707% cache.
4708%
4709% The format of the ReadPixelCachePixels() method is:
4710%
4711% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4712% NexusInfo *nexus_info,ExceptionInfo *exception)
4713%
4714% A description of each parameter follows:
4715%
4716% o cache_info: the pixel cache.
4717%
4718% o nexus_info: the cache nexus to read the pixels.
4719%
4720% o exception: return any errors or warnings in this structure.
4721%
4722*/
4723static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4724 NexusInfo *nexus_info,ExceptionInfo *exception)
4725{
4726 MagickOffsetType
4727 count,
4728 offset;
4729
4730 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004731 extent,
4732 length;
cristy3ed852e2009-09-05 21:47:34 +00004733
cristy4c08aed2011-07-01 19:47:50 +00004734 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004735 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004736
cristye076a6e2010-08-15 19:59:43 +00004737 register ssize_t
4738 y;
4739
cristybb503372010-05-27 20:51:26 +00004740 size_t
cristy3ed852e2009-09-05 21:47:34 +00004741 rows;
4742
cristy4c08aed2011-07-01 19:47:50 +00004743 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004744 return(MagickTrue);
4745 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4746 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004747 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004748 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004749 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004750 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004751 q=nexus_info->pixels;
4752 switch (cache_info->type)
4753 {
4754 case MemoryCache:
4755 case MapCache:
4756 {
cristy4c08aed2011-07-01 19:47:50 +00004757 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004758 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004759
4760 /*
4761 Read pixels from memory.
4762 */
cristydd341db2010-03-04 19:06:38 +00004763 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004764 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004765 {
cristy48078b12010-09-23 17:11:01 +00004766 length=extent;
cristydd341db2010-03-04 19:06:38 +00004767 rows=1UL;
4768 }
cristyed231572011-07-14 02:18:59 +00004769 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004770 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004771 {
cristy8f036fe2010-09-18 02:02:00 +00004772 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004773 p+=cache_info->number_channels*cache_info->columns;
4774 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004775 }
4776 break;
4777 }
4778 case DiskCache:
4779 {
4780 /*
4781 Read pixels from disk.
4782 */
4783 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4784 {
4785 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4786 cache_info->cache_filename);
4787 return(MagickFalse);
4788 }
cristydd341db2010-03-04 19:06:38 +00004789 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004790 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004791 {
cristy48078b12010-09-23 17:11:01 +00004792 length=extent;
cristydd341db2010-03-04 19:06:38 +00004793 rows=1UL;
4794 }
cristybb503372010-05-27 20:51:26 +00004795 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004796 {
4797 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004798 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004799 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004800 break;
4801 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004802 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004803 }
cristybb503372010-05-27 20:51:26 +00004804 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004805 {
4806 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4807 cache_info->cache_filename);
4808 return(MagickFalse);
4809 }
4810 break;
4811 }
4812 default:
4813 break;
4814 }
4815 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004816 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004817 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004818 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004819 nexus_info->region.width,(double) nexus_info->region.height,(double)
4820 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004821 return(MagickTrue);
4822}
4823
4824/*
4825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4826% %
4827% %
4828% %
4829+ R e f e r e n c e P i x e l C a c h e %
4830% %
4831% %
4832% %
4833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4834%
4835% ReferencePixelCache() increments the reference count associated with the
4836% pixel cache returning a pointer to the cache.
4837%
4838% The format of the ReferencePixelCache method is:
4839%
4840% Cache ReferencePixelCache(Cache cache_info)
4841%
4842% A description of each parameter follows:
4843%
4844% o cache_info: the pixel cache.
4845%
4846*/
cristya6577ff2011-09-02 19:54:26 +00004847MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004848{
4849 CacheInfo
4850 *cache_info;
4851
4852 assert(cache != (Cache *) NULL);
4853 cache_info=(CacheInfo *) cache;
4854 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004855 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004856 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004857 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004858 return(cache_info);
4859}
4860
4861/*
4862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4863% %
4864% %
4865% %
4866+ S e t P i x e l C a c h e M e t h o d s %
4867% %
4868% %
4869% %
4870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871%
4872% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4873%
4874% The format of the SetPixelCacheMethods() method is:
4875%
4876% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4877%
4878% A description of each parameter follows:
4879%
4880% o cache: the pixel cache.
4881%
4882% o cache_methods: Specifies a pointer to a CacheMethods structure.
4883%
4884*/
cristya6577ff2011-09-02 19:54:26 +00004885MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004886{
4887 CacheInfo
4888 *cache_info;
4889
4890 GetOneAuthenticPixelFromHandler
4891 get_one_authentic_pixel_from_handler;
4892
4893 GetOneVirtualPixelFromHandler
4894 get_one_virtual_pixel_from_handler;
4895
4896 /*
4897 Set cache pixel methods.
4898 */
4899 assert(cache != (Cache) NULL);
4900 assert(cache_methods != (CacheMethods *) NULL);
4901 cache_info=(CacheInfo *) cache;
4902 assert(cache_info->signature == MagickSignature);
4903 if (cache_info->debug != MagickFalse)
4904 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4905 cache_info->filename);
4906 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4907 cache_info->methods.get_virtual_pixel_handler=
4908 cache_methods->get_virtual_pixel_handler;
4909 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4910 cache_info->methods.destroy_pixel_handler=
4911 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004912 if (cache_methods->get_virtual_metacontent_from_handler !=
4913 (GetVirtualMetacontentFromHandler) NULL)
4914 cache_info->methods.get_virtual_metacontent_from_handler=
4915 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004916 if (cache_methods->get_authentic_pixels_handler !=
4917 (GetAuthenticPixelsHandler) NULL)
4918 cache_info->methods.get_authentic_pixels_handler=
4919 cache_methods->get_authentic_pixels_handler;
4920 if (cache_methods->queue_authentic_pixels_handler !=
4921 (QueueAuthenticPixelsHandler) NULL)
4922 cache_info->methods.queue_authentic_pixels_handler=
4923 cache_methods->queue_authentic_pixels_handler;
4924 if (cache_methods->sync_authentic_pixels_handler !=
4925 (SyncAuthenticPixelsHandler) NULL)
4926 cache_info->methods.sync_authentic_pixels_handler=
4927 cache_methods->sync_authentic_pixels_handler;
4928 if (cache_methods->get_authentic_pixels_from_handler !=
4929 (GetAuthenticPixelsFromHandler) NULL)
4930 cache_info->methods.get_authentic_pixels_from_handler=
4931 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004932 if (cache_methods->get_authentic_metacontent_from_handler !=
4933 (GetAuthenticMetacontentFromHandler) NULL)
4934 cache_info->methods.get_authentic_metacontent_from_handler=
4935 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004936 get_one_virtual_pixel_from_handler=
4937 cache_info->methods.get_one_virtual_pixel_from_handler;
4938 if (get_one_virtual_pixel_from_handler !=
4939 (GetOneVirtualPixelFromHandler) NULL)
4940 cache_info->methods.get_one_virtual_pixel_from_handler=
4941 cache_methods->get_one_virtual_pixel_from_handler;
4942 get_one_authentic_pixel_from_handler=
4943 cache_methods->get_one_authentic_pixel_from_handler;
4944 if (get_one_authentic_pixel_from_handler !=
4945 (GetOneAuthenticPixelFromHandler) NULL)
4946 cache_info->methods.get_one_authentic_pixel_from_handler=
4947 cache_methods->get_one_authentic_pixel_from_handler;
4948}
4949
4950/*
4951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4952% %
4953% %
4954% %
4955+ S e t P i x e l C a c h e N e x u s P i x e l s %
4956% %
4957% %
4958% %
4959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4960%
4961% SetPixelCacheNexusPixels() defines the region of the cache for the
4962% specified cache nexus.
4963%
4964% The format of the SetPixelCacheNexusPixels() method is:
4965%
cristy4c08aed2011-07-01 19:47:50 +00004966% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004967% const RectangleInfo *region,NexusInfo *nexus_info,
4968% ExceptionInfo *exception)
4969%
4970% A description of each parameter follows:
4971%
4972% o image: the image.
4973%
4974% o region: A pointer to the RectangleInfo structure that defines the
4975% region of this particular cache nexus.
4976%
4977% o nexus_info: the cache nexus to set.
4978%
4979% o exception: return any errors or warnings in this structure.
4980%
4981*/
cristyabd6e372010-09-15 19:11:26 +00004982
4983static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4984 NexusInfo *nexus_info,ExceptionInfo *exception)
4985{
4986 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4987 return(MagickFalse);
4988 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00004989 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004990 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004991 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004992 {
4993 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004994 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004995 nexus_info->length);
4996 }
cristy4c08aed2011-07-01 19:47:50 +00004997 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004998 {
4999 (void) ThrowMagickException(exception,GetMagickModule(),
5000 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5001 cache_info->filename);
5002 return(MagickFalse);
5003 }
5004 return(MagickTrue);
5005}
5006
cristy4c08aed2011-07-01 19:47:50 +00005007static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005008 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5009{
5010 CacheInfo
5011 *cache_info;
5012
5013 MagickBooleanType
5014 status;
5015
cristy3ed852e2009-09-05 21:47:34 +00005016 MagickSizeType
5017 length,
5018 number_pixels;
5019
cristy3ed852e2009-09-05 21:47:34 +00005020 cache_info=(CacheInfo *) image->cache;
5021 assert(cache_info->signature == MagickSignature);
5022 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005023 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005024 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005025 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5026 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005027 {
cristybb503372010-05-27 20:51:26 +00005028 ssize_t
cristybad067a2010-02-15 17:20:55 +00005029 x,
5030 y;
cristy3ed852e2009-09-05 21:47:34 +00005031
cristyeaedf062010-05-29 22:36:02 +00005032 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5033 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005034 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5035 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005036 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005037 ((nexus_info->region.width == cache_info->columns) ||
5038 ((nexus_info->region.width % cache_info->columns) == 0)))))
5039 {
5040 MagickOffsetType
5041 offset;
5042
5043 /*
5044 Pixels are accessed directly from memory.
5045 */
5046 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5047 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005048 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005049 offset;
5050 nexus_info->metacontent=(void *) NULL;
5051 if (cache_info->metacontent_extent != 0)
5052 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5053 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005054 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005055 }
5056 }
5057 /*
5058 Pixels are stored in a cache region until they are synced to the cache.
5059 */
5060 number_pixels=(MagickSizeType) nexus_info->region.width*
5061 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005062 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005063 if (cache_info->metacontent_extent != 0)
5064 length+=number_pixels*cache_info->metacontent_extent;
5065 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005066 {
5067 nexus_info->length=length;
5068 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5069 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005070 {
5071 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005072 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005073 }
cristy3ed852e2009-09-05 21:47:34 +00005074 }
5075 else
5076 if (nexus_info->length != length)
5077 {
5078 RelinquishCacheNexusPixels(nexus_info);
5079 nexus_info->length=length;
5080 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5081 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005082 {
5083 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005084 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005085 }
cristy3ed852e2009-09-05 21:47:34 +00005086 }
5087 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005088 nexus_info->metacontent=(void *) NULL;
5089 if (cache_info->metacontent_extent != 0)
5090 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005091 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005092 return(nexus_info->pixels);
5093}
5094
5095/*
5096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5097% %
5098% %
5099% %
5100% 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 %
5101% %
5102% %
5103% %
5104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5105%
5106% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5107% pixel cache and returns the previous setting. A virtual pixel is any pixel
5108% access that is outside the boundaries of the image cache.
5109%
5110% The format of the SetPixelCacheVirtualMethod() method is:
5111%
5112% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5113% const VirtualPixelMethod virtual_pixel_method)
5114%
5115% A description of each parameter follows:
5116%
5117% o image: the image.
5118%
5119% o virtual_pixel_method: choose the type of virtual pixel.
5120%
5121*/
cristyd1dd6e42011-09-04 01:46:08 +00005122MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005123 const VirtualPixelMethod virtual_pixel_method)
5124{
5125 CacheInfo
5126 *cache_info;
5127
5128 VirtualPixelMethod
5129 method;
5130
5131 assert(image != (Image *) NULL);
5132 assert(image->signature == MagickSignature);
5133 if (image->debug != MagickFalse)
5134 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5135 assert(image->cache != (Cache) NULL);
5136 cache_info=(CacheInfo *) image->cache;
5137 assert(cache_info->signature == MagickSignature);
5138 method=cache_info->virtual_pixel_method;
5139 cache_info->virtual_pixel_method=virtual_pixel_method;
5140 return(method);
5141}
5142
5143/*
5144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5145% %
5146% %
5147% %
5148+ 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 %
5149% %
5150% %
5151% %
5152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5153%
5154% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5155% in-memory or disk cache. The method returns MagickTrue if the pixel region
5156% is synced, otherwise MagickFalse.
5157%
5158% The format of the SyncAuthenticPixelCacheNexus() method is:
5159%
5160% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5161% NexusInfo *nexus_info,ExceptionInfo *exception)
5162%
5163% A description of each parameter follows:
5164%
5165% o image: the image.
5166%
5167% o nexus_info: the cache nexus to sync.
5168%
5169% o exception: return any errors or warnings in this structure.
5170%
5171*/
cristya6577ff2011-09-02 19:54:26 +00005172MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005173 NexusInfo *nexus_info,ExceptionInfo *exception)
5174{
5175 CacheInfo
5176 *cache_info;
5177
5178 MagickBooleanType
5179 status;
5180
5181 /*
5182 Transfer pixels to the cache.
5183 */
5184 assert(image != (Image *) NULL);
5185 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005186 if (image->cache == (Cache) NULL)
5187 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5188 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005189 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005190 if (cache_info->type == UndefinedCache)
5191 return(MagickFalse);
5192 if ((image->clip_mask != (Image *) NULL) &&
5193 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5194 return(MagickFalse);
5195 if ((image->mask != (Image *) NULL) &&
5196 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5197 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005198 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005199 return(MagickTrue);
5200 assert(cache_info->signature == MagickSignature);
5201 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005202 if ((cache_info->metacontent_extent != 0) &&
5203 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005204 return(MagickFalse);
5205 return(status);
5206}
5207
5208/*
5209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5210% %
5211% %
5212% %
5213+ S y n c A u t h e n t i c P i x e l C a c h e %
5214% %
5215% %
5216% %
5217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5218%
5219% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5220% or disk cache. The method returns MagickTrue if the pixel region is synced,
5221% otherwise MagickFalse.
5222%
5223% The format of the SyncAuthenticPixelsCache() method is:
5224%
5225% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5226% ExceptionInfo *exception)
5227%
5228% A description of each parameter follows:
5229%
5230% o image: the image.
5231%
5232% o exception: return any errors or warnings in this structure.
5233%
5234*/
5235static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5236 ExceptionInfo *exception)
5237{
5238 CacheInfo
5239 *cache_info;
5240
cristy5c9e6f22010-09-17 17:31:01 +00005241 const int
5242 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005243
cristy4c08aed2011-07-01 19:47:50 +00005244 MagickBooleanType
5245 status;
5246
cristye7cc7cf2010-09-21 13:26:47 +00005247 assert(image != (Image *) NULL);
5248 assert(image->signature == MagickSignature);
5249 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005250 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005251 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005252 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005253 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5254 exception);
5255 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005256}
5257
5258/*
5259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5260% %
5261% %
5262% %
5263% S y n c A u t h e n t i c P i x e l s %
5264% %
5265% %
5266% %
5267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5268%
5269% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5270% The method returns MagickTrue if the pixel region is flushed, otherwise
5271% MagickFalse.
5272%
5273% The format of the SyncAuthenticPixels() method is:
5274%
5275% MagickBooleanType SyncAuthenticPixels(Image *image,
5276% ExceptionInfo *exception)
5277%
5278% A description of each parameter follows:
5279%
5280% o image: the image.
5281%
5282% o exception: return any errors or warnings in this structure.
5283%
5284*/
5285MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5286 ExceptionInfo *exception)
5287{
5288 CacheInfo
5289 *cache_info;
5290
cristy2036f5c2010-09-19 21:18:17 +00005291 const int
5292 id = GetOpenMPThreadId();
5293
cristy4c08aed2011-07-01 19:47:50 +00005294 MagickBooleanType
5295 status;
5296
cristy3ed852e2009-09-05 21:47:34 +00005297 assert(image != (Image *) NULL);
5298 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005299 assert(image->cache != (Cache) NULL);
5300 cache_info=(CacheInfo *) image->cache;
5301 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005302 if (cache_info->methods.sync_authentic_pixels_handler !=
5303 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005304 {
5305 status=cache_info->methods.sync_authentic_pixels_handler(image,
5306 exception);
5307 return(status);
5308 }
cristy2036f5c2010-09-19 21:18:17 +00005309 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005310 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5311 exception);
5312 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005313}
5314
5315/*
5316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5317% %
5318% %
5319% %
cristyd1dd6e42011-09-04 01:46:08 +00005320+ 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 +00005321% %
5322% %
5323% %
5324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5325%
5326% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5327% The method returns MagickTrue if the pixel region is flushed, otherwise
5328% MagickFalse.
5329%
5330% The format of the SyncImagePixelCache() method is:
5331%
5332% MagickBooleanType SyncImagePixelCache(Image *image,
5333% ExceptionInfo *exception)
5334%
5335% A description of each parameter follows:
5336%
5337% o image: the image.
5338%
5339% o exception: return any errors or warnings in this structure.
5340%
5341*/
cristyd1dd6e42011-09-04 01:46:08 +00005342MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005343 ExceptionInfo *exception)
5344{
5345 CacheInfo
5346 *cache_info;
5347
5348 assert(image != (Image *) NULL);
5349 assert(exception != (ExceptionInfo *) NULL);
5350 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5351 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5352}
5353
5354/*
5355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5356% %
5357% %
5358% %
cristy4c08aed2011-07-01 19:47:50 +00005359+ 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 +00005360% %
5361% %
5362% %
5363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5364%
cristy4c08aed2011-07-01 19:47:50 +00005365% WritePixelCacheMetacontent() writes the meta-content to the specified region
5366% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005367%
cristy4c08aed2011-07-01 19:47:50 +00005368% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005369%
cristy4c08aed2011-07-01 19:47:50 +00005370% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005371% NexusInfo *nexus_info,ExceptionInfo *exception)
5372%
5373% A description of each parameter follows:
5374%
5375% o cache_info: the pixel cache.
5376%
cristy4c08aed2011-07-01 19:47:50 +00005377% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005378%
5379% o exception: return any errors or warnings in this structure.
5380%
5381*/
cristy4c08aed2011-07-01 19:47:50 +00005382static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005383 NexusInfo *nexus_info,ExceptionInfo *exception)
5384{
5385 MagickOffsetType
5386 count,
5387 offset;
5388
5389 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005390 extent,
5391 length;
cristy3ed852e2009-09-05 21:47:34 +00005392
cristy4c08aed2011-07-01 19:47:50 +00005393 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005394 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005395
cristybb503372010-05-27 20:51:26 +00005396 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005397 y;
5398
cristybb503372010-05-27 20:51:26 +00005399 size_t
cristy3ed852e2009-09-05 21:47:34 +00005400 rows;
5401
cristy4c08aed2011-07-01 19:47:50 +00005402 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005403 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005404 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005405 return(MagickTrue);
5406 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5407 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005408 length=(MagickSizeType) nexus_info->region.width*
5409 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005410 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005411 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005412 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005413 switch (cache_info->type)
5414 {
5415 case MemoryCache:
5416 case MapCache:
5417 {
cristy4c08aed2011-07-01 19:47:50 +00005418 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005419 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005420
5421 /*
cristy4c08aed2011-07-01 19:47:50 +00005422 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005423 */
cristydd341db2010-03-04 19:06:38 +00005424 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005425 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005426 {
cristy48078b12010-09-23 17:11:01 +00005427 length=extent;
cristydd341db2010-03-04 19:06:38 +00005428 rows=1UL;
5429 }
cristy4c08aed2011-07-01 19:47:50 +00005430 q=(unsigned char *) cache_info->metacontent+offset*
5431 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005432 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005433 {
cristy8f036fe2010-09-18 02:02:00 +00005434 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005435 p+=nexus_info->region.width*cache_info->metacontent_extent;
5436 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005437 }
5438 break;
5439 }
5440 case DiskCache:
5441 {
5442 /*
cristy4c08aed2011-07-01 19:47:50 +00005443 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005444 */
5445 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5446 {
5447 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5448 cache_info->cache_filename);
5449 return(MagickFalse);
5450 }
cristydd341db2010-03-04 19:06:38 +00005451 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005452 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005453 {
cristy48078b12010-09-23 17:11:01 +00005454 length=extent;
cristydd341db2010-03-04 19:06:38 +00005455 rows=1UL;
5456 }
cristy48078b12010-09-23 17:11:01 +00005457 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005458 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005459 {
cristy48078b12010-09-23 17:11:01 +00005460 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005461 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005462 cache_info->metacontent_extent,length,(const unsigned char *) p);
5463 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005464 break;
cristy4c08aed2011-07-01 19:47:50 +00005465 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005466 offset+=cache_info->columns;
5467 }
cristybb503372010-05-27 20:51:26 +00005468 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005469 {
5470 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5471 cache_info->cache_filename);
5472 return(MagickFalse);
5473 }
5474 break;
5475 }
5476 default:
5477 break;
5478 }
5479 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005480 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005481 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005482 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005483 nexus_info->region.width,(double) nexus_info->region.height,(double)
5484 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005485 return(MagickTrue);
5486}
5487
5488/*
5489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5490% %
5491% %
5492% %
5493+ W r i t e C a c h e P i x e l s %
5494% %
5495% %
5496% %
5497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5498%
5499% WritePixelCachePixels() writes image pixels to the specified region of the
5500% pixel cache.
5501%
5502% The format of the WritePixelCachePixels() method is:
5503%
5504% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5505% NexusInfo *nexus_info,ExceptionInfo *exception)
5506%
5507% A description of each parameter follows:
5508%
5509% o cache_info: the pixel cache.
5510%
5511% o nexus_info: the cache nexus to write the pixels.
5512%
5513% o exception: return any errors or warnings in this structure.
5514%
5515*/
5516static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5517 NexusInfo *nexus_info,ExceptionInfo *exception)
5518{
5519 MagickOffsetType
5520 count,
5521 offset;
5522
5523 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005524 extent,
5525 length;
cristy3ed852e2009-09-05 21:47:34 +00005526
cristy4c08aed2011-07-01 19:47:50 +00005527 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005528 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005529
cristybb503372010-05-27 20:51:26 +00005530 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005531 y;
5532
cristybb503372010-05-27 20:51:26 +00005533 size_t
cristy3ed852e2009-09-05 21:47:34 +00005534 rows;
5535
cristy4c08aed2011-07-01 19:47:50 +00005536 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005537 return(MagickTrue);
5538 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5539 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005540 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005541 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005542 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005543 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005544 p=nexus_info->pixels;
5545 switch (cache_info->type)
5546 {
5547 case MemoryCache:
5548 case MapCache:
5549 {
cristy4c08aed2011-07-01 19:47:50 +00005550 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005551 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005552
5553 /*
5554 Write pixels to memory.
5555 */
cristydd341db2010-03-04 19:06:38 +00005556 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005557 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005558 {
cristy48078b12010-09-23 17:11:01 +00005559 length=extent;
cristydd341db2010-03-04 19:06:38 +00005560 rows=1UL;
5561 }
cristyed231572011-07-14 02:18:59 +00005562 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005563 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005564 {
cristy8f036fe2010-09-18 02:02:00 +00005565 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005566 p+=nexus_info->region.width*cache_info->number_channels;
5567 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005568 }
5569 break;
5570 }
5571 case DiskCache:
5572 {
5573 /*
5574 Write pixels to disk.
5575 */
5576 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5577 {
5578 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5579 cache_info->cache_filename);
5580 return(MagickFalse);
5581 }
cristydd341db2010-03-04 19:06:38 +00005582 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005583 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005584 {
cristy48078b12010-09-23 17:11:01 +00005585 length=extent;
cristydd341db2010-03-04 19:06:38 +00005586 rows=1UL;
5587 }
cristybb503372010-05-27 20:51:26 +00005588 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005589 {
5590 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005591 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005592 p);
5593 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005594 break;
cristyed231572011-07-14 02:18:59 +00005595 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005596 offset+=cache_info->columns;
5597 }
cristybb503372010-05-27 20:51:26 +00005598 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005599 {
5600 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5601 cache_info->cache_filename);
5602 return(MagickFalse);
5603 }
5604 break;
5605 }
5606 default:
5607 break;
5608 }
5609 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005610 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005611 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005612 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005613 nexus_info->region.width,(double) nexus_info->region.height,(double)
5614 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005615 return(MagickTrue);
5616}