blob: 1b7e9237764edd4f564869a6dfc155e5e4931d15 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78
79/*
cristy3ed852e2009-09-05 21:47:34 +000080 Typedef declarations.
81*/
82typedef struct _MagickModulo
83{
cristybb503372010-05-27 20:51:26 +000084 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000085 quotient,
86 remainder;
87} MagickModulo;
88
89struct _NexusInfo
90{
91 MagickBooleanType
92 mapped;
93
94 RectangleInfo
95 region;
96
97 MagickSizeType
98 length;
99
cristy4c08aed2011-07-01 19:47:50 +0000100 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000101 *cache,
102 *pixels;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 void
105 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000106
cristybb503372010-05-27 20:51:26 +0000107 size_t
cristy3ed852e2009-09-05 21:47:34 +0000108 signature;
109};
110
111/*
112 Forward declarations.
113*/
114#if defined(__cplusplus) || defined(c_plusplus)
115extern "C" {
116#endif
117
cristy4c08aed2011-07-01 19:47:50 +0000118static const Quantum
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
cristy4c08aed2011-07-01 19:47:50 +0000123static const void
124 *GetVirtualMetacontentFromCache(const Image *);
125
cristy3ed852e2009-09-05 21:47:34 +0000126static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000128 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
137
cristy4c08aed2011-07-01 19:47:50 +0000138static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000144 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146#if defined(__cplusplus) || defined(c_plusplus)
147}
148#endif
149
150/*
151 Global declarations.
152*/
153static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
155
156static SemaphoreInfo
157 *cache_semaphore = (SemaphoreInfo *) NULL;
158
159static SplayTreeInfo
160 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167+ A c q u i r e P i x e l C a c h e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquirePixelCache() acquires a pixel cache.
174%
175% The format of the AcquirePixelCache() method is:
176%
cristybb503372010-05-27 20:51:26 +0000177% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178%
179% A description of each parameter follows:
180%
181% o number_threads: the number of nexus threads.
182%
183*/
cristya6577ff2011-09-02 19:54:26 +0000184MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000185{
186 CacheInfo
187 *cache_info;
188
cristya64b85d2011-09-14 01:02:31 +0000189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000194 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristya6577ff2011-09-02 19:54:26 +0000250MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristya64b85d2011-09-14 01:02:31 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
cristyd1dd6e42011-09-04 01:46:08 +0000301MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
cristy5ff4eaf2011-09-03 01:38:02 +0000339MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
cristy5ff4eaf2011-09-03 01:38:02 +0000363MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000387% mask. It returns MagickTrue if the pixel region is clipped, otherwise
388% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
cristy4c08aed2011-07-01 19:47:50 +0000417 register const Quantum
418 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristy4c08aed2011-07-01 19:47:50 +0000421 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristye076a6e2010-08-15 19:59:43 +0000424 register ssize_t
425 i;
426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
428 Apply clip mask.
429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000434 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000445 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000451 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy4c08aed2011-07-01 19:47:50 +0000453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000454 break;
cristy4c08aed2011-07-01 19:47:50 +0000455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000456 {
cristy4c08aed2011-07-01 19:47:50 +0000457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000463 }
cristyed231572011-07-14 02:18:59 +0000464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000467 }
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000470 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000471 return(MagickFalse);
472 return(MagickTrue);
473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
480+ C l o n e P i x e l C a c h e %
481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
486% ClonePixelCache() clones a pixel cache.
487%
488% The format of the ClonePixelCache() method is:
489%
490% Cache ClonePixelCache(const Cache cache)
491%
492% A description of each parameter follows:
493%
494% o cache: the pixel cache.
495%
496*/
cristya6577ff2011-09-02 19:54:26 +0000497MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000498{
499 CacheInfo
500 *clone_info;
501
502 const CacheInfo
503 *cache_info;
504
cristy9f027d12011-09-21 01:17:17 +0000505 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
516}
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520% %
521% %
522% %
cristy60c44a82009-10-07 00:58:49 +0000523+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000524% %
525% %
526% %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528% ClonePixelCachePixels() clones the source pixel cache to the destination
529% cache.
530%
531% The format of the ClonePixelCachePixels() method is:
532%
533% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534% CacheInfo *source_info,ExceptionInfo *exception)
535%
536% A description of each parameter follows:
537%
538% o cache_info: the pixel cache.
539%
540% o source_info: the source pixel cache.
541%
542% o exception: return any errors or warnings in this structure.
543%
544*/
545
546static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
547{
548 int
549 status;
550
cristy5ee247a2010-02-12 15:42:34 +0000551 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000552 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000553 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000554 {
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
558 }
cristyf84a1932010-01-03 18:00:18 +0000559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000560 return(status == -1 ? MagickFalse : MagickTrue);
561}
562
563static void LimitPixelCacheDescriptors(void)
564{
565 register CacheInfo
566 *p,
567 *q;
568
569 /*
570 Limit # of open file descriptors.
571 */
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
573 return;
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (cache_resources == (SplayTreeInfo *) NULL)
576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return;
579 }
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
583 {
584 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000585 break;
cristy3ed852e2009-09-05 21:47:34 +0000586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 }
588 for (q=p; p != (CacheInfo *) NULL; )
589 {
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000592 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
594 }
595 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000596 {
597 /*
598 Close least recently used cache.
599 */
600 (void) close(q->file);
601 q->file=(-1);
602 }
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604}
605
606static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
608{
609 if (x > y)
610 return(x);
611 return(y);
612}
613
614static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x < y)
618 return(x);
619 return(y);
620}
621
622static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
623 const MapMode mode)
624{
625 int
626 file;
627
628 /*
629 Open pixel cache on disk.
630 */
cristycacc77e2011-12-31 17:20:21 +0000631 if (cache_info->mode != mode)
632 (void) ClosePixelCacheOnDisk(cache_info);
cristyf84a1932010-01-03 18:00:18 +0000633 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000634 if (cache_info->file != -1)
635 {
cristyf84a1932010-01-03 18:00:18 +0000636 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000637 return(MagickTrue); /* cache already open */
638 }
639 LimitPixelCacheDescriptors();
640 if (*cache_info->cache_filename == '\0')
641 file=AcquireUniqueFileResource(cache_info->cache_filename);
642 else
643 switch (mode)
644 {
645 case ReadMode:
646 {
cristy18c6c272011-09-23 14:40:37 +0000647 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000648 break;
649 }
650 case WriteMode:
651 {
cristy18c6c272011-09-23 14:40:37 +0000652 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
653 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000654 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000655 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000656 break;
657 }
658 case IOMode:
659 default:
660 {
cristy18c6c272011-09-23 14:40:37 +0000661 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000662 O_EXCL,S_MODE);
663 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000664 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000665 break;
666 }
667 }
668 if (file == -1)
669 {
cristyf84a1932010-01-03 18:00:18 +0000670 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000671 return(MagickFalse);
672 }
673 (void) AcquireMagickResource(FileResource,1);
cristycacc77e2011-12-31 17:20:21 +0000674 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000694 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000738 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
cristy4c08aed2011-07-01 19:47:50 +0000769static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000773 count;
cristy3ed852e2009-09-05 21:47:34 +0000774
cristy4c08aed2011-07-01 19:47:50 +0000775 register MagickOffsetType
776 i;
cristye076a6e2010-08-15 19:59:43 +0000777
cristybb503372010-05-27 20:51:26 +0000778 size_t
cristy4c08aed2011-07-01 19:47:50 +0000779 length;
cristy3ed852e2009-09-05 21:47:34 +0000780
cristy4c08aed2011-07-01 19:47:50 +0000781 unsigned char
782 *blob;
783
784 /*
785 Clone pixel cache (both caches on disk).
786 */
cristy3ed852e2009-09-05 21:47:34 +0000787 if (cache_info->debug != MagickFalse)
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000789 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000790 sizeof(*blob));
791 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000792 {
cristy4c08aed2011-07-01 19:47:50 +0000793 (void) ThrowMagickException(exception,GetMagickModule(),
794 ResourceLimitError,"MemoryAllocationFailed","`%s'",
795 cache_info->filename);
796 return(MagickFalse);
797 }
cristy3dedf062011-07-02 14:07:40 +0000798 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000799 {
800 blob=(unsigned char *) RelinquishMagickMemory(blob);
801 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
802 cache_info->cache_filename);
803 return(MagickFalse);
804 }
cristy3dedf062011-07-02 14:07:40 +0000805 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000806 {
807 (void) ClosePixelCacheOnDisk(cache_info);
808 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000809 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
810 clone_info->cache_filename);
811 return(MagickFalse);
812 }
cristy4c08aed2011-07-01 19:47:50 +0000813 count=0;
814 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000815 {
cristy4c08aed2011-07-01 19:47:50 +0000816 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
817 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
818 blob);
819 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000820 {
cristy4c08aed2011-07-01 19:47:50 +0000821 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
822 cache_info->cache_filename);
823 break;
cristy3ed852e2009-09-05 21:47:34 +0000824 }
cristy4c08aed2011-07-01 19:47:50 +0000825 length=(size_t) count;
826 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
827 if ((MagickSizeType) count != length)
828 {
829 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
830 clone_info->cache_filename);
831 break;
832 }
833 }
834 (void) ClosePixelCacheOnDisk(clone_info);
835 (void) ClosePixelCacheOnDisk(cache_info);
836 blob=(unsigned char *) RelinquishMagickMemory(blob);
837 if (i < (MagickOffsetType) cache_info->length)
838 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000839 return(MagickTrue);
840}
841
cristy4c08aed2011-07-01 19:47:50 +0000842static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000843 CacheInfo *cache_info,ExceptionInfo *exception)
844{
845 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000846 count;
cristy3ed852e2009-09-05 21:47:34 +0000847
cristy4c08aed2011-07-01 19:47:50 +0000848 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000849 {
cristy3ed852e2009-09-05 21:47:34 +0000850 /*
cristy4c08aed2011-07-01 19:47:50 +0000851 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000852 */
cristy4c08aed2011-07-01 19:47:50 +0000853 if (cache_info->debug != MagickFalse)
854 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
855 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
856 cache_info->length);
857 return(MagickTrue);
858 }
859 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
860 {
861 /*
862 Clone pixel cache (one cache on disk, one in memory).
863 */
864 if (cache_info->debug != MagickFalse)
865 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
866 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000867 {
cristy4c08aed2011-07-01 19:47:50 +0000868 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000869 cache_info->cache_filename);
870 return(MagickFalse);
871 }
cristy4c08aed2011-07-01 19:47:50 +0000872 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
873 cache_info->length,(unsigned char *) clone_info->pixels);
874 (void) ClosePixelCacheOnDisk(cache_info);
875 if ((MagickSizeType) count != cache_info->length)
876 {
877 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
878 cache_info->cache_filename);
879 return(MagickFalse);
880 }
881 return(MagickTrue);
882 }
883 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
884 {
885 /*
886 Clone pixel cache (one cache on disk, one in memory).
887 */
888 if (clone_info->debug != MagickFalse)
889 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
890 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
891 {
892 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
893 clone_info->cache_filename);
894 return(MagickFalse);
895 }
896 count=WritePixelCacheRegion(clone_info,clone_info->offset,
897 clone_info->length,(unsigned char *) cache_info->pixels);
898 (void) ClosePixelCacheOnDisk(clone_info);
899 if ((MagickSizeType) count != clone_info->length)
900 {
901 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
902 clone_info->cache_filename);
903 return(MagickFalse);
904 }
905 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000906 }
907 /*
cristy4c08aed2011-07-01 19:47:50 +0000908 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000909 */
cristy4c08aed2011-07-01 19:47:50 +0000910 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000911}
912
cristy4c08aed2011-07-01 19:47:50 +0000913static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000914 CacheInfo *cache_info,ExceptionInfo *exception)
915{
cristy4c08aed2011-07-01 19:47:50 +0000916 MagickBooleanType
917 status;
cristy3ed852e2009-09-05 21:47:34 +0000918
cristy4c08aed2011-07-01 19:47:50 +0000919 MagickOffsetType
920 cache_offset,
921 clone_offset,
922 count;
923
cristycacc77e2011-12-31 17:20:21 +0000924 Quantum
925 sans;
926
cristy4c08aed2011-07-01 19:47:50 +0000927 register ssize_t
928 x;
929
930 size_t
cristy3ed852e2009-09-05 21:47:34 +0000931 length;
932
cristy4c08aed2011-07-01 19:47:50 +0000933 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000934 y;
935
cristy4c08aed2011-07-01 19:47:50 +0000936 unsigned char
937 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000938
cristy4c08aed2011-07-01 19:47:50 +0000939 /*
940 Clone pixel cache (unoptimized).
941 */
cristy3ed852e2009-09-05 21:47:34 +0000942 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000943 {
cristy4c08aed2011-07-01 19:47:50 +0000944 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
946 else
947 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
948 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
949 else
950 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
952 else
953 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
954 }
cristyed231572011-07-14 02:18:59 +0000955 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
956 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000957 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000958 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000959 if (blob == (unsigned char *) NULL)
960 {
961 (void) ThrowMagickException(exception,GetMagickModule(),
962 ResourceLimitError,"MemoryAllocationFailed","`%s'",
963 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000964 return(MagickFalse);
965 }
cristy4c08aed2011-07-01 19:47:50 +0000966 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
967 cache_offset=0;
968 clone_offset=0;
969 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000970 {
cristy4c08aed2011-07-01 19:47:50 +0000971 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000972 {
cristy4c08aed2011-07-01 19:47:50 +0000973 blob=(unsigned char *) RelinquishMagickMemory(blob);
974 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000975 cache_info->cache_filename);
976 return(MagickFalse);
977 }
cristy4c08aed2011-07-01 19:47:50 +0000978 cache_offset=cache_info->offset;
979 }
980 if (clone_info->type == DiskCache)
981 {
cristy3dedf062011-07-02 14:07:40 +0000982 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 */
cristycacc77e2011-12-31 17:20:21 +0000996 sans=0;
cristy4c08aed2011-07-01 19:47:50 +0000997 status=MagickTrue;
998 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000999 {
cristy4c08aed2011-07-01 19:47:50 +00001000 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001001 {
cristy9e0719b2011-12-29 03:45:45 +00001002 register ssize_t
1003 i;
1004
cristy3ed852e2009-09-05 21:47:34 +00001005 /*
cristy4c08aed2011-07-01 19:47:50 +00001006 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001007 */
cristyed231572011-07-14 02:18:59 +00001008 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001009 if (cache_info->type != DiskCache)
1010 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1011 length);
cristy3ed852e2009-09-05 21:47:34 +00001012 else
1013 {
cristy4c08aed2011-07-01 19:47:50 +00001014 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1015 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001016 {
cristy4c08aed2011-07-01 19:47:50 +00001017 status=MagickFalse;
1018 break;
cristy3ed852e2009-09-05 21:47:34 +00001019 }
1020 }
cristy4c08aed2011-07-01 19:47:50 +00001021 cache_offset+=length;
1022 if ((y < (ssize_t) clone_info->rows) &&
1023 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001024 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001025 {
cristy9e0719b2011-12-29 03:45:45 +00001026 PixelChannel
1027 channel;
1028
1029 PixelTrait
1030 traits;
1031
1032 ssize_t
1033 offset;
1034
cristy4c08aed2011-07-01 19:47:50 +00001035 /*
cristy3b8fe922011-12-29 18:56:23 +00001036 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001037 */
cristy9e0719b2011-12-29 03:45:45 +00001038 channel=clone_info->channel_map[i].channel;
1039 traits=cache_info->channel_map[channel].traits;
1040 if (traits == UndefinedPixelTrait)
1041 {
cristycacc77e2011-12-31 17:20:21 +00001042 if (clone_info->type != DiskCache)
1043 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1044 (unsigned char *) &sans,sizeof(Quantum));
1045 else
1046 {
1047 count=WritePixelCacheRegion(clone_info,clone_offset,
1048 sizeof(Quantum),(unsigned char *) &sans);
1049 if ((MagickSizeType) count != sizeof(Quantum))
1050 {
1051 status=MagickFalse;
1052 break;
1053 }
1054 }
cristy9e0719b2011-12-29 03:45:45 +00001055 }
cristy4c08aed2011-07-01 19:47:50 +00001056 else
1057 {
cristycacc77e2011-12-31 17:20:21 +00001058 offset=cache_info->channel_map[channel].offset;
1059 if (clone_info->type != DiskCache)
1060 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1061 blob+offset*sizeof(Quantum),sizeof(Quantum));
1062 else
cristy4c08aed2011-07-01 19:47:50 +00001063 {
cristycacc77e2011-12-31 17:20:21 +00001064 count=WritePixelCacheRegion(clone_info,clone_offset,
1065 sizeof(Quantum),blob+offset*sizeof(Quantum));
1066 if ((MagickSizeType) count != sizeof(Quantum))
1067 {
1068 status=MagickFalse;
1069 break;
1070 }
cristy4c08aed2011-07-01 19:47:50 +00001071 }
1072 }
cristy9e0719b2011-12-29 03:45:45 +00001073 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001074 }
1075 }
cristyed231572011-07-14 02:18:59 +00001076 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001077 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1078 for ( ; x < (ssize_t) clone_info->columns; x++)
1079 {
1080 /*
cristy9e0719b2011-12-29 03:45:45 +00001081 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001082 */
1083 if (clone_info->type != DiskCache)
1084 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1085 length);
1086 else
1087 {
1088 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1089 if ((MagickSizeType) count != length)
1090 {
1091 status=MagickFalse;
1092 break;
1093 }
1094 }
1095 clone_offset+=length;
1096 }
1097 }
cristyed231572011-07-14 02:18:59 +00001098 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001099 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1100 for ( ; y < (ssize_t) clone_info->rows; y++)
1101 {
1102 /*
cristy9e0719b2011-12-29 03:45:45 +00001103 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001104 */
1105 for (x=0; x < (ssize_t) clone_info->columns; x++)
1106 {
1107 if (clone_info->type != DiskCache)
1108 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1109 length);
1110 else
1111 {
1112 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1113 if ((MagickSizeType) count != length)
1114 {
1115 status=MagickFalse;
1116 break;
1117 }
1118 }
1119 clone_offset+=length;
1120 }
1121 }
cristy9e0719b2011-12-29 03:45:45 +00001122 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001123 (clone_info->metacontent_extent != 0))
1124 {
1125 /*
1126 Clone metacontent.
1127 */
1128 for (y=0; y < (ssize_t) cache_info->rows; y++)
1129 {
1130 for (x=0; x < (ssize_t) cache_info->columns; x++)
1131 {
1132 /*
1133 Read a set of metacontent.
1134 */
1135 length=cache_info->metacontent_extent;
1136 if (cache_info->type != DiskCache)
1137 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1138 cache_offset,length);
1139 else
1140 {
1141 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1142 if ((MagickSizeType) count != length)
1143 {
1144 status=MagickFalse;
1145 break;
1146 }
1147 }
1148 cache_offset+=length;
1149 if ((y < (ssize_t) clone_info->rows) &&
1150 (x < (ssize_t) clone_info->columns))
1151 {
1152 /*
1153 Write a set of metacontent.
1154 */
1155 length=clone_info->metacontent_extent;
1156 if (clone_info->type != DiskCache)
1157 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1158 blob,length);
1159 else
1160 {
1161 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1162 blob);
1163 if ((MagickSizeType) count != length)
1164 {
1165 status=MagickFalse;
1166 break;
1167 }
1168 }
1169 clone_offset+=length;
1170 }
1171 }
1172 length=clone_info->metacontent_extent;
1173 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1174 for ( ; x < (ssize_t) clone_info->columns; x++)
1175 {
1176 /*
cristy9e0719b2011-12-29 03:45:45 +00001177 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001178 */
1179 if (clone_info->type != DiskCache)
1180 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1181 blob,length);
1182 else
1183 {
cristy208b1002011-08-07 18:51:50 +00001184 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001185 if ((MagickSizeType) count != length)
1186 {
1187 status=MagickFalse;
1188 break;
1189 }
1190 }
1191 clone_offset+=length;
1192 }
1193 }
1194 length=clone_info->metacontent_extent;
1195 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1196 for ( ; y < (ssize_t) clone_info->rows; y++)
1197 {
1198 /*
cristy9e0719b2011-12-29 03:45:45 +00001199 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001200 */
1201 for (x=0; x < (ssize_t) clone_info->columns; x++)
1202 {
1203 if (clone_info->type != DiskCache)
1204 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1205 blob,length);
1206 else
1207 {
1208 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1209 if ((MagickSizeType) count != length)
1210 {
1211 status=MagickFalse;
1212 break;
1213 }
1214 }
1215 clone_offset+=length;
1216 }
1217 }
1218 }
1219 if (clone_info->type == DiskCache)
1220 (void) ClosePixelCacheOnDisk(clone_info);
1221 if (cache_info->type == DiskCache)
1222 (void) ClosePixelCacheOnDisk(cache_info);
1223 blob=(unsigned char *) RelinquishMagickMemory(blob);
1224 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001225}
1226
1227static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1228 CacheInfo *cache_info,ExceptionInfo *exception)
1229{
cristy3dfccb22011-12-28 21:47:20 +00001230 PixelChannelMap
1231 *p,
1232 *q;
1233
cristy5a7fbfb2010-11-06 16:10:59 +00001234 if (cache_info->type == PingCache)
1235 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001236 p=cache_info->channel_map;
1237 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001238 if ((cache_info->columns == clone_info->columns) &&
1239 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001240 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001241 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001242 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1243 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1244 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001245}
1246
1247/*
1248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249% %
1250% %
1251% %
1252+ C l o n e P i x e l C a c h e M e t h o d s %
1253% %
1254% %
1255% %
1256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257%
1258% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1259% another.
1260%
1261% The format of the ClonePixelCacheMethods() method is:
1262%
1263% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1264%
1265% A description of each parameter follows:
1266%
1267% o clone: Specifies a pointer to a Cache structure.
1268%
1269% o cache: the pixel cache.
1270%
1271*/
cristya6577ff2011-09-02 19:54:26 +00001272MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001273{
1274 CacheInfo
1275 *cache_info,
1276 *source_info;
1277
1278 assert(clone != (Cache) NULL);
1279 source_info=(CacheInfo *) clone;
1280 assert(source_info->signature == MagickSignature);
1281 if (source_info->debug != MagickFalse)
1282 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1283 source_info->filename);
1284 assert(cache != (Cache) NULL);
1285 cache_info=(CacheInfo *) cache;
1286 assert(cache_info->signature == MagickSignature);
1287 source_info->methods=cache_info->methods;
1288}
1289
1290/*
1291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1292% %
1293% %
1294% %
1295+ D e s t r o y I m a g e P i x e l C a c h e %
1296% %
1297% %
1298% %
1299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300%
1301% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1302%
1303% The format of the DestroyImagePixelCache() method is:
1304%
1305% void DestroyImagePixelCache(Image *image)
1306%
1307% A description of each parameter follows:
1308%
1309% o image: the image.
1310%
1311*/
1312static void DestroyImagePixelCache(Image *image)
1313{
1314 assert(image != (Image *) NULL);
1315 assert(image->signature == MagickSignature);
1316 if (image->debug != MagickFalse)
1317 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1318 if (image->cache == (void *) NULL)
1319 return;
1320 image->cache=DestroyPixelCache(image->cache);
1321}
1322
1323/*
1324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1325% %
1326% %
1327% %
1328+ D e s t r o y I m a g e P i x e l s %
1329% %
1330% %
1331% %
1332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333%
1334% DestroyImagePixels() deallocates memory associated with the pixel cache.
1335%
1336% The format of the DestroyImagePixels() method is:
1337%
1338% void DestroyImagePixels(Image *image)
1339%
1340% A description of each parameter follows:
1341%
1342% o image: the image.
1343%
1344*/
1345MagickExport void DestroyImagePixels(Image *image)
1346{
1347 CacheInfo
1348 *cache_info;
1349
1350 assert(image != (const Image *) NULL);
1351 assert(image->signature == MagickSignature);
1352 if (image->debug != MagickFalse)
1353 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1354 assert(image->cache != (Cache) NULL);
1355 cache_info=(CacheInfo *) image->cache;
1356 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001357 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1358 {
1359 cache_info->methods.destroy_pixel_handler(image);
1360 return;
1361 }
cristy2036f5c2010-09-19 21:18:17 +00001362 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001363}
1364
1365/*
1366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1367% %
1368% %
1369% %
1370+ D e s t r o y P i x e l C a c h e %
1371% %
1372% %
1373% %
1374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375%
1376% DestroyPixelCache() deallocates memory associated with the pixel cache.
1377%
1378% The format of the DestroyPixelCache() method is:
1379%
1380% Cache DestroyPixelCache(Cache cache)
1381%
1382% A description of each parameter follows:
1383%
1384% o cache: the pixel cache.
1385%
1386*/
1387
1388static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1389{
1390 switch (cache_info->type)
1391 {
1392 case MemoryCache:
1393 {
1394 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001395 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001396 cache_info->pixels);
1397 else
cristy4c08aed2011-07-01 19:47:50 +00001398 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001399 (size_t) cache_info->length);
1400 RelinquishMagickResource(MemoryResource,cache_info->length);
1401 break;
1402 }
1403 case MapCache:
1404 {
cristy4c08aed2011-07-01 19:47:50 +00001405 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001406 cache_info->length);
1407 RelinquishMagickResource(MapResource,cache_info->length);
1408 }
1409 case DiskCache:
1410 {
1411 if (cache_info->file != -1)
1412 (void) ClosePixelCacheOnDisk(cache_info);
1413 RelinquishMagickResource(DiskResource,cache_info->length);
1414 break;
1415 }
1416 default:
1417 break;
1418 }
1419 cache_info->type=UndefinedCache;
1420 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001421 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001422}
1423
cristya6577ff2011-09-02 19:54:26 +00001424MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001425{
1426 CacheInfo
1427 *cache_info;
1428
cristy3ed852e2009-09-05 21:47:34 +00001429 assert(cache != (Cache) NULL);
1430 cache_info=(CacheInfo *) cache;
1431 assert(cache_info->signature == MagickSignature);
1432 if (cache_info->debug != MagickFalse)
1433 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1434 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001435 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001436 cache_info->reference_count--;
1437 if (cache_info->reference_count != 0)
1438 {
cristyf84a1932010-01-03 18:00:18 +00001439 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001440 return((Cache) NULL);
1441 }
cristyf84a1932010-01-03 18:00:18 +00001442 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001443 if (cache_resources != (SplayTreeInfo *) NULL)
1444 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001445 if (cache_info->debug != MagickFalse)
1446 {
1447 char
1448 message[MaxTextExtent];
1449
cristyb51dff52011-05-19 16:55:47 +00001450 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001451 cache_info->filename);
1452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1453 }
cristyc2e1bdd2009-09-10 23:43:34 +00001454 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1455 (cache_info->type != DiskCache)))
1456 RelinquishPixelCachePixels(cache_info);
1457 else
1458 {
1459 RelinquishPixelCachePixels(cache_info);
1460 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1461 }
cristy3ed852e2009-09-05 21:47:34 +00001462 *cache_info->cache_filename='\0';
1463 if (cache_info->nexus_info != (NexusInfo **) NULL)
1464 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1465 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001466 if (cache_info->random_info != (RandomInfo *) NULL)
1467 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001468 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1469 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1470 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1471 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001472 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001473 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001474 cache=(Cache) NULL;
1475 return(cache);
1476}
1477
1478/*
1479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480% %
1481% %
1482% %
1483+ D e s t r o y P i x e l C a c h e N e x u s %
1484% %
1485% %
1486% %
1487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1488%
1489% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1490%
1491% The format of the DestroyPixelCacheNexus() method is:
1492%
1493% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001494% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001495%
1496% A description of each parameter follows:
1497%
1498% o nexus_info: the nexus to destroy.
1499%
1500% o number_threads: the number of nexus threads.
1501%
1502*/
1503
1504static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1505{
1506 if (nexus_info->mapped == MagickFalse)
1507 (void) RelinquishMagickMemory(nexus_info->cache);
1508 else
1509 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001510 nexus_info->cache=(Quantum *) NULL;
1511 nexus_info->pixels=(Quantum *) NULL;
1512 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001513 nexus_info->length=0;
1514 nexus_info->mapped=MagickFalse;
1515}
1516
cristya6577ff2011-09-02 19:54:26 +00001517MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001518 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001519{
cristybb503372010-05-27 20:51:26 +00001520 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001521 i;
1522
1523 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001524 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001525 {
cristy4c08aed2011-07-01 19:47:50 +00001526 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001527 RelinquishCacheNexusPixels(nexus_info[i]);
1528 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001529 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001530 }
cristyb41ee102010-10-04 16:46:15 +00001531 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001532 return(nexus_info);
1533}
1534
1535/*
1536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1537% %
1538% %
1539% %
cristy4c08aed2011-07-01 19:47:50 +00001540% 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 +00001541% %
1542% %
1543% %
1544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545%
cristy4c08aed2011-07-01 19:47:50 +00001546% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1547% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1548% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001549%
cristy4c08aed2011-07-01 19:47:50 +00001550% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001551%
cristy4c08aed2011-07-01 19:47:50 +00001552% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001553%
1554% A description of each parameter follows:
1555%
1556% o image: the image.
1557%
1558*/
cristy4c08aed2011-07-01 19:47:50 +00001559MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001560{
1561 CacheInfo
1562 *cache_info;
1563
cristy5c9e6f22010-09-17 17:31:01 +00001564 const int
1565 id = GetOpenMPThreadId();
1566
cristy4c08aed2011-07-01 19:47:50 +00001567 void
1568 *metacontent;
1569
cristye7cc7cf2010-09-21 13:26:47 +00001570 assert(image != (const Image *) NULL);
1571 assert(image->signature == MagickSignature);
1572 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001573 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001574 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001575 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1576 (GetAuthenticMetacontentFromHandler) NULL)
1577 {
1578 metacontent=cache_info->methods.
1579 get_authentic_metacontent_from_handler(image);
1580 return(metacontent);
1581 }
cristy6ebe97c2010-07-03 01:17:28 +00001582 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001583 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1584 cache_info->nexus_info[id]);
1585 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001586}
1587
1588/*
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590% %
1591% %
1592% %
cristy4c08aed2011-07-01 19:47:50 +00001593+ 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 +00001594% %
1595% %
1596% %
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598%
cristy4c08aed2011-07-01 19:47:50 +00001599% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1600% with the last call to QueueAuthenticPixelsCache() or
1601% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001602%
cristy4c08aed2011-07-01 19:47:50 +00001603% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001604%
cristy4c08aed2011-07-01 19:47:50 +00001605% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001606%
1607% A description of each parameter follows:
1608%
1609% o image: the image.
1610%
1611*/
cristy4c08aed2011-07-01 19:47:50 +00001612static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001613{
1614 CacheInfo
1615 *cache_info;
1616
cristy2036f5c2010-09-19 21:18:17 +00001617 const int
1618 id = GetOpenMPThreadId();
1619
cristy4c08aed2011-07-01 19:47:50 +00001620 void
1621 *metacontent;
1622
cristy3ed852e2009-09-05 21:47:34 +00001623 assert(image != (const Image *) NULL);
1624 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001625 assert(image->cache != (Cache) NULL);
1626 cache_info=(CacheInfo *) image->cache;
1627 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001628 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001629 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1630 cache_info->nexus_info[id]);
1631 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001632}
1633
1634/*
1635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636% %
1637% %
1638% %
1639+ 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 %
1640% %
1641% %
1642% %
1643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644%
1645% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1646% disk pixel cache as defined by the geometry parameters. A pointer to the
1647% pixels is returned if the pixels are transferred, otherwise a NULL is
1648% returned.
1649%
1650% The format of the GetAuthenticPixelCacheNexus() method is:
1651%
cristy4c08aed2011-07-01 19:47:50 +00001652% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001653% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001654% NexusInfo *nexus_info,ExceptionInfo *exception)
1655%
1656% A description of each parameter follows:
1657%
1658% o image: the image.
1659%
1660% o x,y,columns,rows: These values define the perimeter of a region of
1661% pixels.
1662%
1663% o nexus_info: the cache nexus to return.
1664%
1665% o exception: return any errors or warnings in this structure.
1666%
1667*/
1668
cristy4c08aed2011-07-01 19:47:50 +00001669static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001670 NexusInfo *nexus_info)
1671{
cristy4c08aed2011-07-01 19:47:50 +00001672 MagickBooleanType
1673 status;
1674
cristy3ed852e2009-09-05 21:47:34 +00001675 MagickOffsetType
1676 offset;
1677
cristy73724512010-04-12 14:43:14 +00001678 if (cache_info->type == PingCache)
1679 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001680 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1681 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001682 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001683 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001684 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001685}
1686
cristya6577ff2011-09-02 19:54:26 +00001687MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001688 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001689 NexusInfo *nexus_info,ExceptionInfo *exception)
1690{
1691 CacheInfo
1692 *cache_info;
1693
cristy4c08aed2011-07-01 19:47:50 +00001694 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001695 *q;
cristy3ed852e2009-09-05 21:47:34 +00001696
1697 /*
1698 Transfer pixels from the cache.
1699 */
1700 assert(image != (Image *) NULL);
1701 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001702 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001703 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001704 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001705 cache_info=(CacheInfo *) image->cache;
1706 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001707 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001708 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001709 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001710 return((Quantum *) NULL);
1711 if (cache_info->metacontent_extent != 0)
1712 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1713 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001714 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001715}
1716
1717/*
1718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1719% %
1720% %
1721% %
1722+ 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 %
1723% %
1724% %
1725% %
1726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727%
1728% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1729% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1730%
1731% The format of the GetAuthenticPixelsFromCache() method is:
1732%
cristy4c08aed2011-07-01 19:47:50 +00001733% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001734%
1735% A description of each parameter follows:
1736%
1737% o image: the image.
1738%
1739*/
cristy4c08aed2011-07-01 19:47:50 +00001740static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001741{
1742 CacheInfo
1743 *cache_info;
1744
cristy5c9e6f22010-09-17 17:31:01 +00001745 const int
1746 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001747
cristye7cc7cf2010-09-21 13:26:47 +00001748 assert(image != (const Image *) NULL);
1749 assert(image->signature == MagickSignature);
1750 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001751 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001752 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001753 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001754 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001755}
1756
1757/*
1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759% %
1760% %
1761% %
1762% G e t A u t h e n t i c P i x e l Q u e u e %
1763% %
1764% %
1765% %
1766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1767%
cristy4c08aed2011-07-01 19:47:50 +00001768% GetAuthenticPixelQueue() returns the authentic pixels associated
1769% corresponding with the last call to QueueAuthenticPixels() or
1770% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001771%
1772% The format of the GetAuthenticPixelQueue() method is:
1773%
cristy4c08aed2011-07-01 19:47:50 +00001774% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001775%
1776% A description of each parameter follows:
1777%
1778% o image: the image.
1779%
1780*/
cristy4c08aed2011-07-01 19:47:50 +00001781MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001782{
1783 CacheInfo
1784 *cache_info;
1785
cristy2036f5c2010-09-19 21:18:17 +00001786 const int
1787 id = GetOpenMPThreadId();
1788
cristy3ed852e2009-09-05 21:47:34 +00001789 assert(image != (const Image *) NULL);
1790 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001791 assert(image->cache != (Cache) NULL);
1792 cache_info=(CacheInfo *) image->cache;
1793 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001794 if (cache_info->methods.get_authentic_pixels_from_handler !=
1795 (GetAuthenticPixelsFromHandler) NULL)
1796 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001797 assert(id < (int) cache_info->number_threads);
1798 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001799}
1800
1801/*
1802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1803% %
1804% %
1805% %
1806% G e t A u t h e n t i c P i x e l s %
1807% %
1808% %
cristy4c08aed2011-07-01 19:47:50 +00001809% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001810%
1811% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001812% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001813% representing the region is returned, otherwise NULL is returned.
1814%
1815% The returned pointer may point to a temporary working copy of the pixels
1816% or it may point to the original pixels in memory. Performance is maximized
1817% if the selected region is part of one row, or one or more full rows, since
1818% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001819% if the image is in memory, or in a memory-mapped file. The returned pointer
1820% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001821%
1822% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001823% Quantum. If the image has corresponding metacontent,call
1824% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1825% meta-content corresponding to the region. Once the Quantum array has
1826% been updated, the changes must be saved back to the underlying image using
1827% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001828%
1829% The format of the GetAuthenticPixels() method is:
1830%
cristy4c08aed2011-07-01 19:47:50 +00001831% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001832% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001833% ExceptionInfo *exception)
1834%
1835% A description of each parameter follows:
1836%
1837% o image: the image.
1838%
1839% o x,y,columns,rows: These values define the perimeter of a region of
1840% pixels.
1841%
1842% o exception: return any errors or warnings in this structure.
1843%
1844*/
cristy4c08aed2011-07-01 19:47:50 +00001845MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001846 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001847 ExceptionInfo *exception)
1848{
1849 CacheInfo
1850 *cache_info;
1851
cristy2036f5c2010-09-19 21:18:17 +00001852 const int
1853 id = GetOpenMPThreadId();
1854
cristy4c08aed2011-07-01 19:47:50 +00001855 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001856 *q;
cristy4c08aed2011-07-01 19:47:50 +00001857
cristy3ed852e2009-09-05 21:47:34 +00001858 assert(image != (Image *) NULL);
1859 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001860 assert(image->cache != (Cache) NULL);
1861 cache_info=(CacheInfo *) image->cache;
1862 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001863 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001864 (GetAuthenticPixelsHandler) NULL)
1865 {
cristyacd2ed22011-08-30 01:44:23 +00001866 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1867 exception);
1868 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001869 }
cristy2036f5c2010-09-19 21:18:17 +00001870 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001871 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001872 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001873 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001874}
1875
1876/*
1877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1878% %
1879% %
1880% %
1881+ G e t A u t h e n t i c P i x e l s C a c h e %
1882% %
1883% %
1884% %
1885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1886%
1887% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1888% as defined by the geometry parameters. A pointer to the pixels is returned
1889% if the pixels are transferred, otherwise a NULL is returned.
1890%
1891% The format of the GetAuthenticPixelsCache() method is:
1892%
cristy4c08aed2011-07-01 19:47:50 +00001893% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001894% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001895% ExceptionInfo *exception)
1896%
1897% A description of each parameter follows:
1898%
1899% o image: the image.
1900%
1901% o x,y,columns,rows: These values define the perimeter of a region of
1902% pixels.
1903%
1904% o exception: return any errors or warnings in this structure.
1905%
1906*/
cristy4c08aed2011-07-01 19:47:50 +00001907static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001908 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001909 ExceptionInfo *exception)
1910{
1911 CacheInfo
1912 *cache_info;
1913
cristy5c9e6f22010-09-17 17:31:01 +00001914 const int
1915 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001916
cristy4c08aed2011-07-01 19:47:50 +00001917 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001918 *q;
cristy4c08aed2011-07-01 19:47:50 +00001919
cristye7cc7cf2010-09-21 13:26:47 +00001920 assert(image != (const Image *) NULL);
1921 assert(image->signature == MagickSignature);
1922 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001923 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001924 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001925 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001926 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001927 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001928 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001929 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001930 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001931}
1932
1933/*
1934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1935% %
1936% %
1937% %
1938+ G e t I m a g e E x t e n t %
1939% %
1940% %
1941% %
1942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943%
cristy4c08aed2011-07-01 19:47:50 +00001944% GetImageExtent() returns the extent of the pixels associated corresponding
1945% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001946%
1947% The format of the GetImageExtent() method is:
1948%
1949% MagickSizeType GetImageExtent(const Image *image)
1950%
1951% A description of each parameter follows:
1952%
1953% o image: the image.
1954%
1955*/
1956MagickExport MagickSizeType GetImageExtent(const Image *image)
1957{
1958 CacheInfo
1959 *cache_info;
1960
cristy5c9e6f22010-09-17 17:31:01 +00001961 const int
1962 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001963
cristy3ed852e2009-09-05 21:47:34 +00001964 assert(image != (Image *) NULL);
1965 assert(image->signature == MagickSignature);
1966 if (image->debug != MagickFalse)
1967 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1968 assert(image->cache != (Cache) NULL);
1969 cache_info=(CacheInfo *) image->cache;
1970 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001971 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001972 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001973}
1974
1975/*
1976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977% %
1978% %
1979% %
1980+ G e t I m a g e P i x e l C a c h e %
1981% %
1982% %
1983% %
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985%
1986% GetImagePixelCache() ensures that there is only a single reference to the
1987% pixel cache to be modified, updating the provided cache pointer to point to
1988% a clone of the original pixel cache if necessary.
1989%
1990% The format of the GetImagePixelCache method is:
1991%
1992% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1993% ExceptionInfo *exception)
1994%
1995% A description of each parameter follows:
1996%
1997% o image: the image.
1998%
1999% o clone: any value other than MagickFalse clones the cache pixels.
2000%
2001% o exception: return any errors or warnings in this structure.
2002%
2003*/
cristyaf894d72011-08-06 23:03:10 +00002004
cristy3ed852e2009-09-05 21:47:34 +00002005static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2006{
2007 CacheInfo
2008 *cache_info;
2009
cristy9e0719b2011-12-29 03:45:45 +00002010 PixelChannelMap
2011 *p,
2012 *q;
2013
cristy3ed852e2009-09-05 21:47:34 +00002014 /*
2015 Does the image match the pixel cache morphology?
2016 */
2017 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00002018 p=image->channel_map;
2019 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00002020 if ((image->storage_class != cache_info->storage_class) ||
2021 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002022 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002023 (image->columns != cache_info->columns) ||
2024 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002025 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002026 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002027 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002028 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2029 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2030 return(MagickFalse);
2031 return(MagickTrue);
2032}
2033
cristycd01fae2011-08-06 23:52:42 +00002034static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2035 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002036{
2037 CacheInfo
2038 *cache_info;
2039
cristy3ed852e2009-09-05 21:47:34 +00002040 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002041 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002042 status;
2043
cristy50a10922010-02-15 18:35:25 +00002044 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002045 cpu_throttle = 0,
2046 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002047 time_limit = 0;
2048
cristy1ea34962010-07-01 19:49:21 +00002049 static time_t
cristy208b1002011-08-07 18:51:50 +00002050 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002051
cristyc4f9f132010-03-04 18:50:01 +00002052 status=MagickTrue;
2053 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002054 if (cpu_throttle == 0)
2055 {
2056 char
2057 *limit;
2058
2059 /*
2060 Set CPU throttle in milleseconds.
2061 */
2062 cpu_throttle=MagickResourceInfinity;
2063 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2064 if (limit == (char *) NULL)
2065 limit=GetPolicyValue("throttle");
2066 if (limit != (char *) NULL)
2067 {
2068 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2069 limit=DestroyString(limit);
2070 }
2071 }
2072 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2073 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002074 if (time_limit == 0)
2075 {
cristy6ebe97c2010-07-03 01:17:28 +00002076 /*
2077 Set the exire time in seconds.
2078 */
cristy1ea34962010-07-01 19:49:21 +00002079 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002080 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002081 }
2082 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002083 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002084 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002085 assert(image->cache != (Cache) NULL);
2086 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002087 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002088 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002089 {
cristyceb55ee2010-11-06 16:05:49 +00002090 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002091 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002092 {
cristyceb55ee2010-11-06 16:05:49 +00002093 Image
2094 clone_image;
2095
2096 CacheInfo
2097 *clone_info;
2098
2099 /*
2100 Clone pixel cache.
2101 */
2102 clone_image=(*image);
2103 clone_image.semaphore=AllocateSemaphoreInfo();
2104 clone_image.reference_count=1;
2105 clone_image.cache=ClonePixelCache(cache_info);
2106 clone_info=(CacheInfo *) clone_image.cache;
2107 status=OpenPixelCache(&clone_image,IOMode,exception);
2108 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002109 {
cristy5a7fbfb2010-11-06 16:10:59 +00002110 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002111 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002112 if (status != MagickFalse)
2113 {
cristy979bf772011-08-08 00:04:15 +00002114 if (cache_info->mode == ReadMode)
2115 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002116 destroy=MagickTrue;
2117 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002118 }
2119 }
cristyceb55ee2010-11-06 16:05:49 +00002120 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002121 }
cristyceb55ee2010-11-06 16:05:49 +00002122 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002123 }
cristy4320e0e2009-09-10 15:00:08 +00002124 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002125 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002126 if (status != MagickFalse)
2127 {
2128 /*
2129 Ensure the image matches the pixel cache morphology.
2130 */
2131 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002132 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002133 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2134 status=OpenPixelCache(image,IOMode,exception);
2135 }
cristyf84a1932010-01-03 18:00:18 +00002136 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002137 if (status == MagickFalse)
2138 return((Cache) NULL);
2139 return(image->cache);
2140}
2141
2142/*
2143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2144% %
2145% %
2146% %
2147% G e t O n e A u t h e n t i c P i x e l %
2148% %
2149% %
2150% %
2151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2152%
2153% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2154% location. The image background color is returned if an error occurs.
2155%
2156% The format of the GetOneAuthenticPixel() method is:
2157%
cristybb503372010-05-27 20:51:26 +00002158% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002159% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002160%
2161% A description of each parameter follows:
2162%
2163% o image: the image.
2164%
2165% o x,y: These values define the location of the pixel to return.
2166%
2167% o pixel: return a pixel at the specified (x,y) location.
2168%
2169% o exception: return any errors or warnings in this structure.
2170%
2171*/
cristyacbbb7c2010-06-30 18:56:48 +00002172MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002173 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002174{
2175 CacheInfo
2176 *cache_info;
2177
cristy4c08aed2011-07-01 19:47:50 +00002178 register Quantum
2179 *q;
cristy2036f5c2010-09-19 21:18:17 +00002180
cristy2ed42f62011-10-02 19:49:57 +00002181 register ssize_t
2182 i;
2183
cristy3ed852e2009-09-05 21:47:34 +00002184 assert(image != (Image *) NULL);
2185 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002186 assert(image->cache != (Cache) NULL);
2187 cache_info=(CacheInfo *) image->cache;
2188 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002189 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002190 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2191 (GetOneAuthenticPixelFromHandler) NULL)
2192 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2193 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002194 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2195 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002196 {
cristy9e0719b2011-12-29 03:45:45 +00002197 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2198 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2199 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2200 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2201 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002202 return(MagickFalse);
2203 }
2204 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2205 {
2206 PixelChannel
2207 channel;
2208
cristye2a912b2011-12-05 20:02:07 +00002209 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002210 pixel[channel]=q[i];
2211 }
cristy2036f5c2010-09-19 21:18:17 +00002212 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002213}
2214
2215/*
2216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2217% %
2218% %
2219% %
2220+ 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 %
2221% %
2222% %
2223% %
2224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225%
2226% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2227% location. The image background color is returned if an error occurs.
2228%
2229% The format of the GetOneAuthenticPixelFromCache() method is:
2230%
2231% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002232% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002233% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002234%
2235% A description of each parameter follows:
2236%
2237% o image: the image.
2238%
2239% o x,y: These values define the location of the pixel to return.
2240%
2241% o pixel: return a pixel at the specified (x,y) location.
2242%
2243% o exception: return any errors or warnings in this structure.
2244%
2245*/
2246static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002247 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002248{
cristy098f78c2010-09-23 17:28:44 +00002249 CacheInfo
2250 *cache_info;
2251
2252 const int
2253 id = GetOpenMPThreadId();
2254
cristy4c08aed2011-07-01 19:47:50 +00002255 register Quantum
2256 *q;
cristy3ed852e2009-09-05 21:47:34 +00002257
cristy2ed42f62011-10-02 19:49:57 +00002258 register ssize_t
2259 i;
2260
cristy0158a4b2010-09-20 13:59:45 +00002261 assert(image != (const Image *) NULL);
2262 assert(image->signature == MagickSignature);
2263 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002264 cache_info=(CacheInfo *) image->cache;
2265 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002266 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002267 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002268 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2269 exception);
2270 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002271 {
cristy9e0719b2011-12-29 03:45:45 +00002272 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2273 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2274 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2275 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2276 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002277 return(MagickFalse);
2278 }
2279 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2280 {
2281 PixelChannel
2282 channel;
2283
cristye2a912b2011-12-05 20:02:07 +00002284 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002285 pixel[channel]=q[i];
2286 }
cristy3ed852e2009-09-05 21:47:34 +00002287 return(MagickTrue);
2288}
2289
2290/*
2291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2292% %
2293% %
2294% %
cristy3ed852e2009-09-05 21:47:34 +00002295% G e t O n e V i r t u a l P i x e l %
2296% %
2297% %
2298% %
2299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2300%
2301% GetOneVirtualPixel() returns a single virtual pixel at the specified
2302% (x,y) location. The image background color is returned if an error occurs.
2303% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2304%
2305% The format of the GetOneVirtualPixel() method is:
2306%
cristybb503372010-05-27 20:51:26 +00002307% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002308% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002309%
2310% A description of each parameter follows:
2311%
2312% o image: the image.
2313%
2314% o x,y: These values define the location of the pixel to return.
2315%
2316% o pixel: return a pixel at the specified (x,y) location.
2317%
2318% o exception: return any errors or warnings in this structure.
2319%
2320*/
2321MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002322 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002323{
cristy3ed852e2009-09-05 21:47:34 +00002324 CacheInfo
2325 *cache_info;
2326
cristy0158a4b2010-09-20 13:59:45 +00002327 const int
2328 id = GetOpenMPThreadId();
2329
cristy4c08aed2011-07-01 19:47:50 +00002330 const Quantum
2331 *p;
cristy2036f5c2010-09-19 21:18:17 +00002332
cristy2ed42f62011-10-02 19:49:57 +00002333 register ssize_t
2334 i;
2335
cristy3ed852e2009-09-05 21:47:34 +00002336 assert(image != (const Image *) NULL);
2337 assert(image->signature == MagickSignature);
2338 assert(image->cache != (Cache) NULL);
2339 cache_info=(CacheInfo *) image->cache;
2340 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002341 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002342 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2343 (GetOneVirtualPixelFromHandler) NULL)
2344 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2345 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002346 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002347 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002348 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002349 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002350 {
cristy9e0719b2011-12-29 03:45:45 +00002351 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2352 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2353 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2354 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2355 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002356 return(MagickFalse);
2357 }
2358 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2359 {
2360 PixelChannel
2361 channel;
2362
cristye2a912b2011-12-05 20:02:07 +00002363 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002364 pixel[channel]=p[i];
2365 }
cristy2036f5c2010-09-19 21:18:17 +00002366 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002367}
2368
2369/*
2370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2371% %
2372% %
2373% %
2374+ 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 %
2375% %
2376% %
2377% %
2378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2379%
2380% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2381% specified (x,y) location. The image background color is returned if an
2382% error occurs.
2383%
2384% The format of the GetOneVirtualPixelFromCache() method is:
2385%
2386% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002387% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002388% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002389%
2390% A description of each parameter follows:
2391%
2392% o image: the image.
2393%
2394% o virtual_pixel_method: the virtual pixel method.
2395%
2396% o x,y: These values define the location of the pixel to return.
2397%
2398% o pixel: return a pixel at the specified (x,y) location.
2399%
2400% o exception: return any errors or warnings in this structure.
2401%
2402*/
2403static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002404 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002405 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002406{
cristy0158a4b2010-09-20 13:59:45 +00002407 CacheInfo
2408 *cache_info;
2409
2410 const int
2411 id = GetOpenMPThreadId();
2412
cristy4c08aed2011-07-01 19:47:50 +00002413 const Quantum
2414 *p;
cristy3ed852e2009-09-05 21:47:34 +00002415
cristy2ed42f62011-10-02 19:49:57 +00002416 register ssize_t
2417 i;
2418
cristye7cc7cf2010-09-21 13:26:47 +00002419 assert(image != (const Image *) NULL);
2420 assert(image->signature == MagickSignature);
2421 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002422 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002423 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002424 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002425 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002426 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002427 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002428 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002429 {
cristy9e0719b2011-12-29 03:45:45 +00002430 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2431 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2432 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2433 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2434 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002435 return(MagickFalse);
2436 }
2437 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2438 {
2439 PixelChannel
2440 channel;
2441
cristye2a912b2011-12-05 20:02:07 +00002442 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002443 pixel[channel]=p[i];
2444 }
cristy3ed852e2009-09-05 21:47:34 +00002445 return(MagickTrue);
2446}
2447
2448/*
2449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2450% %
2451% %
2452% %
cristy3aa93752011-12-18 15:54:24 +00002453% G e t O n e V i r t u a l P i x e l I n f o %
2454% %
2455% %
2456% %
2457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2458%
2459% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2460% location. The image background color is returned if an error occurs. If
2461% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2462%
2463% The format of the GetOneVirtualPixelInfo() method is:
2464%
2465% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2466% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2467% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2468%
2469% A description of each parameter follows:
2470%
2471% o image: the image.
2472%
2473% o virtual_pixel_method: the virtual pixel method.
2474%
2475% o x,y: these values define the location of the pixel to return.
2476%
2477% o pixel: return a pixel at the specified (x,y) location.
2478%
2479% o exception: return any errors or warnings in this structure.
2480%
2481*/
2482MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2483 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2484 PixelInfo *pixel,ExceptionInfo *exception)
2485{
2486 CacheInfo
2487 *cache_info;
2488
2489 const int
2490 id = GetOpenMPThreadId();
2491
2492 register const Quantum
2493 *p;
2494
2495 assert(image != (const Image *) NULL);
2496 assert(image->signature == MagickSignature);
2497 assert(image->cache != (Cache) NULL);
2498 cache_info=(CacheInfo *) image->cache;
2499 assert(cache_info->signature == MagickSignature);
2500 assert(id < (int) cache_info->number_threads);
2501 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2502 cache_info->nexus_info[id],exception);
2503 GetPixelInfo(image,pixel);
2504 if (p == (const Quantum *) NULL)
2505 return(MagickFalse);
2506 GetPixelInfoPixel(image,p,pixel);
2507 return(MagickTrue);
2508}
2509
2510/*
2511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2512% %
2513% %
2514% %
cristy3ed852e2009-09-05 21:47:34 +00002515+ G e t P i x e l C a c h e C o l o r s p a c e %
2516% %
2517% %
2518% %
2519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2520%
2521% GetPixelCacheColorspace() returns the class type of the pixel cache.
2522%
2523% The format of the GetPixelCacheColorspace() method is:
2524%
2525% Colorspace GetPixelCacheColorspace(Cache cache)
2526%
2527% A description of each parameter follows:
2528%
2529% o cache: the pixel cache.
2530%
2531*/
cristya6577ff2011-09-02 19:54:26 +00002532MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002533{
2534 CacheInfo
2535 *cache_info;
2536
2537 assert(cache != (Cache) NULL);
2538 cache_info=(CacheInfo *) cache;
2539 assert(cache_info->signature == MagickSignature);
2540 if (cache_info->debug != MagickFalse)
2541 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2542 cache_info->filename);
2543 return(cache_info->colorspace);
2544}
2545
2546/*
2547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548% %
2549% %
2550% %
2551+ G e t P i x e l C a c h e M e t h o d s %
2552% %
2553% %
2554% %
2555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2556%
2557% GetPixelCacheMethods() initializes the CacheMethods structure.
2558%
2559% The format of the GetPixelCacheMethods() method is:
2560%
2561% void GetPixelCacheMethods(CacheMethods *cache_methods)
2562%
2563% A description of each parameter follows:
2564%
2565% o cache_methods: Specifies a pointer to a CacheMethods structure.
2566%
2567*/
cristya6577ff2011-09-02 19:54:26 +00002568MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002569{
2570 assert(cache_methods != (CacheMethods *) NULL);
2571 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2572 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2573 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002574 cache_methods->get_virtual_metacontent_from_handler=
2575 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002576 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2577 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002578 cache_methods->get_authentic_metacontent_from_handler=
2579 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002580 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2581 cache_methods->get_one_authentic_pixel_from_handler=
2582 GetOneAuthenticPixelFromCache;
2583 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2584 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2585 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2586}
2587
2588/*
2589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2590% %
2591% %
2592% %
2593+ G e t P i x e l C a c h e N e x u s E x t e n t %
2594% %
2595% %
2596% %
2597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2598%
cristy4c08aed2011-07-01 19:47:50 +00002599% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2600% corresponding with the last call to SetPixelCacheNexusPixels() or
2601% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002602%
2603% The format of the GetPixelCacheNexusExtent() method is:
2604%
2605% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2606% NexusInfo *nexus_info)
2607%
2608% A description of each parameter follows:
2609%
2610% o nexus_info: the nexus info.
2611%
2612*/
cristya6577ff2011-09-02 19:54:26 +00002613MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002614 NexusInfo *nexus_info)
2615{
2616 CacheInfo
2617 *cache_info;
2618
2619 MagickSizeType
2620 extent;
2621
cristy9f027d12011-09-21 01:17:17 +00002622 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002623 cache_info=(CacheInfo *) cache;
2624 assert(cache_info->signature == MagickSignature);
2625 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2626 if (extent == 0)
2627 return((MagickSizeType) cache_info->columns*cache_info->rows);
2628 return(extent);
2629}
2630
2631/*
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633% %
2634% %
2635% %
cristy4c08aed2011-07-01 19:47:50 +00002636+ 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 +00002637% %
2638% %
2639% %
2640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641%
cristy4c08aed2011-07-01 19:47:50 +00002642% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2643% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002644%
cristy4c08aed2011-07-01 19:47:50 +00002645% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002646%
cristy4c08aed2011-07-01 19:47:50 +00002647% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002648% NexusInfo *nexus_info)
2649%
2650% A description of each parameter follows:
2651%
2652% o cache: the pixel cache.
2653%
cristy4c08aed2011-07-01 19:47:50 +00002654% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002655%
2656*/
cristya6577ff2011-09-02 19:54:26 +00002657MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002658 NexusInfo *nexus_info)
2659{
2660 CacheInfo
2661 *cache_info;
2662
cristy9f027d12011-09-21 01:17:17 +00002663 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002664 cache_info=(CacheInfo *) cache;
2665 assert(cache_info->signature == MagickSignature);
2666 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002667 return((void *) NULL);
2668 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002669}
2670
2671/*
2672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2673% %
2674% %
2675% %
2676+ G e t P i x e l C a c h e N e x u s P i x e l s %
2677% %
2678% %
2679% %
2680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2681%
2682% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2683% cache nexus.
2684%
2685% The format of the GetPixelCacheNexusPixels() method is:
2686%
cristy4c08aed2011-07-01 19:47:50 +00002687% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002688% NexusInfo *nexus_info)
2689%
2690% A description of each parameter follows:
2691%
2692% o cache: the pixel cache.
2693%
2694% o nexus_info: the cache nexus to return the pixels.
2695%
2696*/
cristya6577ff2011-09-02 19:54:26 +00002697MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002698 NexusInfo *nexus_info)
2699{
2700 CacheInfo
2701 *cache_info;
2702
cristy9f027d12011-09-21 01:17:17 +00002703 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002704 cache_info=(CacheInfo *) cache;
2705 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002706 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002707 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002708 return(nexus_info->pixels);
2709}
2710
2711/*
2712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2713% %
2714% %
2715% %
cristy056ba772010-01-02 23:33:54 +00002716+ G e t P i x e l C a c h e P i x e l s %
2717% %
2718% %
2719% %
2720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2721%
2722% GetPixelCachePixels() returns the pixels associated with the specified image.
2723%
2724% The format of the GetPixelCachePixels() method is:
2725%
cristyf84a1932010-01-03 18:00:18 +00002726% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2727% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002728%
2729% A description of each parameter follows:
2730%
2731% o image: the image.
2732%
2733% o length: the pixel cache length.
2734%
cristyf84a1932010-01-03 18:00:18 +00002735% o exception: return any errors or warnings in this structure.
2736%
cristy056ba772010-01-02 23:33:54 +00002737*/
cristyd1dd6e42011-09-04 01:46:08 +00002738MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002739 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002740{
2741 CacheInfo
2742 *cache_info;
2743
2744 assert(image != (const Image *) NULL);
2745 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002746 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002747 assert(length != (MagickSizeType *) NULL);
2748 assert(exception != (ExceptionInfo *) NULL);
2749 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002750 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002751 assert(cache_info->signature == MagickSignature);
2752 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002753 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002754 return((void *) NULL);
2755 *length=cache_info->length;
2756 return((void *) cache_info->pixels);
2757}
2758
2759/*
2760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761% %
2762% %
2763% %
cristyb32b90a2009-09-07 21:45:48 +00002764+ 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 +00002765% %
2766% %
2767% %
2768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2769%
2770% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2771%
2772% The format of the GetPixelCacheStorageClass() method is:
2773%
2774% ClassType GetPixelCacheStorageClass(Cache cache)
2775%
2776% A description of each parameter follows:
2777%
2778% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2779%
2780% o cache: the pixel cache.
2781%
2782*/
cristya6577ff2011-09-02 19:54:26 +00002783MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002784{
2785 CacheInfo
2786 *cache_info;
2787
2788 assert(cache != (Cache) NULL);
2789 cache_info=(CacheInfo *) cache;
2790 assert(cache_info->signature == MagickSignature);
2791 if (cache_info->debug != MagickFalse)
2792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2793 cache_info->filename);
2794 return(cache_info->storage_class);
2795}
2796
2797/*
2798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2799% %
2800% %
2801% %
cristyb32b90a2009-09-07 21:45:48 +00002802+ G e t P i x e l C a c h e T i l e S i z e %
2803% %
2804% %
2805% %
2806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2807%
2808% GetPixelCacheTileSize() returns the pixel cache tile size.
2809%
2810% The format of the GetPixelCacheTileSize() method is:
2811%
cristybb503372010-05-27 20:51:26 +00002812% void GetPixelCacheTileSize(const Image *image,size_t *width,
2813% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002814%
2815% A description of each parameter follows:
2816%
2817% o image: the image.
2818%
2819% o width: the optimize cache tile width in pixels.
2820%
2821% o height: the optimize cache tile height in pixels.
2822%
2823*/
cristya6577ff2011-09-02 19:54:26 +00002824MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002825 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002826{
cristy4c08aed2011-07-01 19:47:50 +00002827 CacheInfo
2828 *cache_info;
2829
cristyb32b90a2009-09-07 21:45:48 +00002830 assert(image != (Image *) NULL);
2831 assert(image->signature == MagickSignature);
2832 if (image->debug != MagickFalse)
2833 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002834 cache_info=(CacheInfo *) image->cache;
2835 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002836 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002837 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002838 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002839 *height=(*width);
2840}
2841
2842/*
2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844% %
2845% %
2846% %
2847+ G e t P i x e l C a c h e T y p e %
2848% %
2849% %
2850% %
2851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852%
2853% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2854%
2855% The format of the GetPixelCacheType() method is:
2856%
2857% CacheType GetPixelCacheType(const Image *image)
2858%
2859% A description of each parameter follows:
2860%
2861% o image: the image.
2862%
2863*/
cristya6577ff2011-09-02 19:54:26 +00002864MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002865{
2866 CacheInfo
2867 *cache_info;
2868
2869 assert(image != (Image *) NULL);
2870 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002871 assert(image->cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) image->cache;
2873 assert(cache_info->signature == MagickSignature);
2874 return(cache_info->type);
2875}
2876
2877/*
2878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2879% %
2880% %
2881% %
cristy3ed852e2009-09-05 21:47:34 +00002882+ 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 %
2883% %
2884% %
2885% %
2886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887%
2888% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2889% pixel cache. A virtual pixel is any pixel access that is outside the
2890% boundaries of the image cache.
2891%
2892% The format of the GetPixelCacheVirtualMethod() method is:
2893%
2894% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2895%
2896% A description of each parameter follows:
2897%
2898% o image: the image.
2899%
2900*/
cristyd1dd6e42011-09-04 01:46:08 +00002901MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002902{
2903 CacheInfo
2904 *cache_info;
2905
2906 assert(image != (Image *) NULL);
2907 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002908 assert(image->cache != (Cache) NULL);
2909 cache_info=(CacheInfo *) image->cache;
2910 assert(cache_info->signature == MagickSignature);
2911 return(cache_info->virtual_pixel_method);
2912}
2913
2914/*
2915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2916% %
2917% %
2918% %
cristy4c08aed2011-07-01 19:47:50 +00002919+ 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 +00002920% %
2921% %
2922% %
2923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2924%
cristy4c08aed2011-07-01 19:47:50 +00002925% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2926% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002927%
cristy4c08aed2011-07-01 19:47:50 +00002928% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002929%
cristy4c08aed2011-07-01 19:47:50 +00002930% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002931%
2932% A description of each parameter follows:
2933%
2934% o image: the image.
2935%
2936*/
cristy4c08aed2011-07-01 19:47:50 +00002937static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002938{
2939 CacheInfo
2940 *cache_info;
2941
cristy5c9e6f22010-09-17 17:31:01 +00002942 const int
2943 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002944
cristy4c08aed2011-07-01 19:47:50 +00002945 const void
2946 *metacontent;
2947
cristye7cc7cf2010-09-21 13:26:47 +00002948 assert(image != (const Image *) NULL);
2949 assert(image->signature == MagickSignature);
2950 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002951 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002952 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002953 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002954 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2955 cache_info->nexus_info[id]);
2956 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002957}
2958
2959/*
2960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2961% %
2962% %
2963% %
cristy4c08aed2011-07-01 19:47:50 +00002964+ 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 +00002965% %
2966% %
2967% %
2968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2969%
cristy4c08aed2011-07-01 19:47:50 +00002970% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2971% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002972%
cristy4c08aed2011-07-01 19:47:50 +00002973% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002974%
cristy4c08aed2011-07-01 19:47:50 +00002975% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002976% NexusInfo *nexus_info)
2977%
2978% A description of each parameter follows:
2979%
2980% o cache: the pixel cache.
2981%
cristy4c08aed2011-07-01 19:47:50 +00002982% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002983%
2984*/
cristya6577ff2011-09-02 19:54:26 +00002985MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002986 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002987{
2988 CacheInfo
2989 *cache_info;
2990
cristye7cc7cf2010-09-21 13:26:47 +00002991 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002992 cache_info=(CacheInfo *) cache;
2993 assert(cache_info->signature == MagickSignature);
2994 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002995 return((void *) NULL);
2996 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002997}
2998
2999/*
3000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001% %
3002% %
3003% %
cristy4c08aed2011-07-01 19:47:50 +00003004% 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 +00003005% %
3006% %
3007% %
3008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3009%
cristy4c08aed2011-07-01 19:47:50 +00003010% GetVirtualMetacontent() returns the virtual metacontent corresponding with
3011% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3012% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003013%
cristy4c08aed2011-07-01 19:47:50 +00003014% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003015%
cristy4c08aed2011-07-01 19:47:50 +00003016% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003017%
3018% A description of each parameter follows:
3019%
3020% o image: the image.
3021%
3022*/
cristy4c08aed2011-07-01 19:47:50 +00003023MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003024{
3025 CacheInfo
3026 *cache_info;
3027
cristy2036f5c2010-09-19 21:18:17 +00003028 const int
3029 id = GetOpenMPThreadId();
3030
cristy4c08aed2011-07-01 19:47:50 +00003031 const void
3032 *metacontent;
3033
cristy3ed852e2009-09-05 21:47:34 +00003034 assert(image != (const Image *) NULL);
3035 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003036 assert(image->cache != (Cache) NULL);
3037 cache_info=(CacheInfo *) image->cache;
3038 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003039 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3040 (GetVirtualMetacontentFromHandler) NULL)
3041 {
3042 metacontent=cache_info->methods.
3043 get_virtual_metacontent_from_handler(image);
3044 return(metacontent);
3045 }
cristy2036f5c2010-09-19 21:18:17 +00003046 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003047 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3048 cache_info->nexus_info[id]);
3049 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003050}
3051
3052/*
3053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054% %
3055% %
3056% %
3057+ 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 %
3058% %
3059% %
3060% %
3061%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3062%
3063% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3064% pixel cache as defined by the geometry parameters. A pointer to the pixels
3065% is returned if the pixels are transferred, otherwise a NULL is returned.
3066%
3067% The format of the GetVirtualPixelsFromNexus() method is:
3068%
cristy4c08aed2011-07-01 19:47:50 +00003069% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003070% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003071% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3072% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003073%
3074% A description of each parameter follows:
3075%
3076% o image: the image.
3077%
3078% o virtual_pixel_method: the virtual pixel method.
3079%
3080% o x,y,columns,rows: These values define the perimeter of a region of
3081% pixels.
3082%
3083% o nexus_info: the cache nexus to acquire.
3084%
3085% o exception: return any errors or warnings in this structure.
3086%
3087*/
3088
cristybb503372010-05-27 20:51:26 +00003089static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003090 DitherMatrix[64] =
3091 {
3092 0, 48, 12, 60, 3, 51, 15, 63,
3093 32, 16, 44, 28, 35, 19, 47, 31,
3094 8, 56, 4, 52, 11, 59, 7, 55,
3095 40, 24, 36, 20, 43, 27, 39, 23,
3096 2, 50, 14, 62, 1, 49, 13, 61,
3097 34, 18, 46, 30, 33, 17, 45, 29,
3098 10, 58, 6, 54, 9, 57, 5, 53,
3099 42, 26, 38, 22, 41, 25, 37, 21
3100 };
3101
cristybb503372010-05-27 20:51:26 +00003102static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003103{
cristybb503372010-05-27 20:51:26 +00003104 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003105 index;
3106
3107 index=x+DitherMatrix[x & 0x07]-32L;
3108 if (index < 0L)
3109 return(0L);
cristybb503372010-05-27 20:51:26 +00003110 if (index >= (ssize_t) columns)
3111 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003112 return(index);
3113}
3114
cristybb503372010-05-27 20:51:26 +00003115static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003116{
cristybb503372010-05-27 20:51:26 +00003117 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003118 index;
3119
3120 index=y+DitherMatrix[y & 0x07]-32L;
3121 if (index < 0L)
3122 return(0L);
cristybb503372010-05-27 20:51:26 +00003123 if (index >= (ssize_t) rows)
3124 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003125 return(index);
3126}
3127
cristybb503372010-05-27 20:51:26 +00003128static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003129{
3130 if (x < 0L)
3131 return(0L);
cristybb503372010-05-27 20:51:26 +00003132 if (x >= (ssize_t) columns)
3133 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003134 return(x);
3135}
3136
cristybb503372010-05-27 20:51:26 +00003137static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003138{
3139 if (y < 0L)
3140 return(0L);
cristybb503372010-05-27 20:51:26 +00003141 if (y >= (ssize_t) rows)
3142 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003143 return(y);
3144}
3145
cristybb503372010-05-27 20:51:26 +00003146static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003147{
cristybb503372010-05-27 20:51:26 +00003148 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003149}
3150
cristybb503372010-05-27 20:51:26 +00003151static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003152{
cristybb503372010-05-27 20:51:26 +00003153 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003154}
3155
cristybb503372010-05-27 20:51:26 +00003156static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3157 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003158{
3159 MagickModulo
3160 modulo;
3161
cristy6162bb42011-07-18 11:34:09 +00003162 /*
3163 Compute the remainder of dividing offset by extent. It returns not only
3164 the quotient (tile the offset falls in) but also the positive remainer
3165 within that tile such that 0 <= remainder < extent. This method is
3166 essentially a ldiv() using a floored modulo division rather than the
3167 normal default truncated modulo division.
3168 */
cristybb503372010-05-27 20:51:26 +00003169 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003170 if (offset < 0L)
3171 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003172 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003173 return(modulo);
3174}
3175
cristya6577ff2011-09-02 19:54:26 +00003176MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003177 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3178 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003179 ExceptionInfo *exception)
3180{
3181 CacheInfo
3182 *cache_info;
3183
3184 MagickOffsetType
3185 offset;
3186
3187 MagickSizeType
3188 length,
3189 number_pixels;
3190
3191 NexusInfo
3192 **virtual_nexus;
3193
cristy4c08aed2011-07-01 19:47:50 +00003194 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003195 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003196 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003197
3198 RectangleInfo
3199 region;
3200
cristy4c08aed2011-07-01 19:47:50 +00003201 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003202 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003203
cristy4c08aed2011-07-01 19:47:50 +00003204 register const void
3205 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003206
cristy4c08aed2011-07-01 19:47:50 +00003207 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003208 *restrict q;
3209
cristybb503372010-05-27 20:51:26 +00003210 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003211 i,
3212 u;
cristy3ed852e2009-09-05 21:47:34 +00003213
cristy4c08aed2011-07-01 19:47:50 +00003214 register unsigned char
3215 *restrict s;
3216
cristy105ba3c2011-07-18 02:28:38 +00003217 ssize_t
3218 v;
3219
cristy4c08aed2011-07-01 19:47:50 +00003220 void
cristy105ba3c2011-07-18 02:28:38 +00003221 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003222
cristy3ed852e2009-09-05 21:47:34 +00003223 /*
3224 Acquire pixels.
3225 */
cristye7cc7cf2010-09-21 13:26:47 +00003226 assert(image != (const Image *) NULL);
3227 assert(image->signature == MagickSignature);
3228 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003229 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003230 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003231 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003232 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003233 region.x=x;
3234 region.y=y;
3235 region.width=columns;
3236 region.height=rows;
3237 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003238 if (pixels == (Quantum *) NULL)
3239 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003240 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003241 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3242 nexus_info->region.x;
3243 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3244 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003245 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3246 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003247 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3248 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003249 {
3250 MagickBooleanType
3251 status;
3252
3253 /*
3254 Pixel request is inside cache extents.
3255 */
cristy4c08aed2011-07-01 19:47:50 +00003256 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003257 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003258 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3259 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003260 return((const Quantum *) NULL);
3261 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003262 {
cristy4c08aed2011-07-01 19:47:50 +00003263 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003264 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003265 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003266 }
cristyacd2ed22011-08-30 01:44:23 +00003267 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003268 }
3269 /*
3270 Pixel request is outside cache extents.
3271 */
cristy4c08aed2011-07-01 19:47:50 +00003272 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003273 virtual_nexus=AcquirePixelCacheNexus(1);
3274 if (virtual_nexus == (NexusInfo **) NULL)
3275 {
cristy4c08aed2011-07-01 19:47:50 +00003276 if (virtual_nexus != (NexusInfo **) NULL)
3277 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003278 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3279 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003280 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003281 }
cristy105ba3c2011-07-18 02:28:38 +00003282 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3283 sizeof(*virtual_pixel));
3284 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003285 switch (virtual_pixel_method)
3286 {
cristy4c08aed2011-07-01 19:47:50 +00003287 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003288 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003289 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003290 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003291 case MaskVirtualPixelMethod:
3292 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003293 case EdgeVirtualPixelMethod:
3294 case CheckerTileVirtualPixelMethod:
3295 case HorizontalTileVirtualPixelMethod:
3296 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003297 {
cristy4c08aed2011-07-01 19:47:50 +00003298 if (cache_info->metacontent_extent != 0)
3299 {
cristy6162bb42011-07-18 11:34:09 +00003300 /*
3301 Acquire a metacontent buffer.
3302 */
cristya64b85d2011-09-14 01:02:31 +00003303 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003304 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003305 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003306 {
cristy4c08aed2011-07-01 19:47:50 +00003307 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3308 (void) ThrowMagickException(exception,GetMagickModule(),
3309 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3310 return((const Quantum *) NULL);
3311 }
cristy105ba3c2011-07-18 02:28:38 +00003312 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003313 cache_info->metacontent_extent);
3314 }
3315 switch (virtual_pixel_method)
3316 {
3317 case BlackVirtualPixelMethod:
3318 {
cristy30301712011-07-18 15:06:51 +00003319 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3320 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003321 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3322 break;
3323 }
3324 case GrayVirtualPixelMethod:
3325 {
cristy30301712011-07-18 15:06:51 +00003326 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003327 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3328 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003329 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3330 break;
3331 }
3332 case TransparentVirtualPixelMethod:
3333 {
cristy30301712011-07-18 15:06:51 +00003334 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3335 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003336 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3337 break;
3338 }
3339 case MaskVirtualPixelMethod:
3340 case WhiteVirtualPixelMethod:
3341 {
cristy30301712011-07-18 15:06:51 +00003342 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3343 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003344 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3345 break;
3346 }
3347 default:
3348 {
cristy9e0719b2011-12-29 03:45:45 +00003349 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3350 virtual_pixel);
3351 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3352 virtual_pixel);
3353 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3354 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003355 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003356 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3357 virtual_pixel);
3358 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3359 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003360 break;
3361 }
3362 }
cristy3ed852e2009-09-05 21:47:34 +00003363 break;
3364 }
3365 default:
cristy3ed852e2009-09-05 21:47:34 +00003366 break;
cristy3ed852e2009-09-05 21:47:34 +00003367 }
cristybb503372010-05-27 20:51:26 +00003368 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003369 {
cristybb503372010-05-27 20:51:26 +00003370 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003371 {
3372 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003373 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003374 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3375 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003376 {
3377 MagickModulo
3378 x_modulo,
3379 y_modulo;
3380
3381 /*
3382 Transfer a single pixel.
3383 */
3384 length=(MagickSizeType) 1;
3385 switch (virtual_pixel_method)
3386 {
cristy3ed852e2009-09-05 21:47:34 +00003387 default:
3388 {
3389 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003390 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003391 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003392 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003393 break;
3394 }
3395 case RandomVirtualPixelMethod:
3396 {
3397 if (cache_info->random_info == (RandomInfo *) NULL)
3398 cache_info->random_info=AcquireRandomInfo();
3399 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003400 RandomX(cache_info->random_info,cache_info->columns),
3401 RandomY(cache_info->random_info,cache_info->rows),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);
cristy3ed852e2009-09-05 21:47:34 +00003404 break;
3405 }
3406 case DitherVirtualPixelMethod:
3407 {
3408 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003409 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003410 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003411 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003412 break;
3413 }
3414 case TileVirtualPixelMethod:
3415 {
3416 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3417 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3418 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003419 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003420 exception);
cristy4c08aed2011-07-01 19:47:50 +00003421 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003422 break;
3423 }
3424 case MirrorVirtualPixelMethod:
3425 {
3426 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3427 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003428 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003429 x_modulo.remainder-1L;
3430 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3431 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003432 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003433 y_modulo.remainder-1L;
3434 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003435 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003436 exception);
cristy4c08aed2011-07-01 19:47:50 +00003437 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003438 break;
3439 }
3440 case HorizontalTileEdgeVirtualPixelMethod:
3441 {
3442 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3443 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003444 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003445 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003446 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003447 break;
3448 }
3449 case VerticalTileEdgeVirtualPixelMethod:
3450 {
3451 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3452 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003453 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003454 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003455 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3456 break;
3457 }
3458 case BackgroundVirtualPixelMethod:
3459 case BlackVirtualPixelMethod:
3460 case GrayVirtualPixelMethod:
3461 case TransparentVirtualPixelMethod:
3462 case MaskVirtualPixelMethod:
3463 case WhiteVirtualPixelMethod:
3464 {
3465 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003466 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003467 break;
3468 }
3469 case EdgeVirtualPixelMethod:
3470 case CheckerTileVirtualPixelMethod:
3471 {
3472 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3475 {
3476 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003477 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003478 break;
3479 }
3480 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3481 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3482 exception);
3483 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3484 break;
3485 }
3486 case HorizontalTileVirtualPixelMethod:
3487 {
3488 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3489 {
3490 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003491 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003492 break;
3493 }
3494 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3495 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3496 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3497 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3498 exception);
3499 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3500 break;
3501 }
3502 case VerticalTileVirtualPixelMethod:
3503 {
3504 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3505 {
3506 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003507 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003508 break;
3509 }
3510 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3511 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3512 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3513 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3514 exception);
3515 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003516 break;
3517 }
3518 }
cristy4c08aed2011-07-01 19:47:50 +00003519 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003520 break;
cristyed231572011-07-14 02:18:59 +00003521 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003522 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003523 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003524 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003525 {
3526 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3527 s+=cache_info->metacontent_extent;
3528 }
cristy3ed852e2009-09-05 21:47:34 +00003529 continue;
3530 }
3531 /*
3532 Transfer a run of pixels.
3533 */
cristy4c08aed2011-07-01 19:47:50 +00003534 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3535 length,1UL,*virtual_nexus,exception);
3536 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003537 break;
cristy4c08aed2011-07-01 19:47:50 +00003538 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003539 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3540 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003541 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003542 {
cristy4c08aed2011-07-01 19:47:50 +00003543 (void) memcpy(s,r,(size_t) length);
3544 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003545 }
3546 }
3547 }
cristy4c08aed2011-07-01 19:47:50 +00003548 /*
3549 Free resources.
3550 */
cristy105ba3c2011-07-18 02:28:38 +00003551 if (virtual_metacontent != (void *) NULL)
3552 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003553 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3554 return(pixels);
3555}
3556
3557/*
3558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3559% %
3560% %
3561% %
3562+ G e t V i r t u a l P i x e l C a c h e %
3563% %
3564% %
3565% %
3566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3567%
3568% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3569% cache as defined by the geometry parameters. A pointer to the pixels
3570% is returned if the pixels are transferred, otherwise a NULL is returned.
3571%
3572% The format of the GetVirtualPixelCache() method is:
3573%
cristy4c08aed2011-07-01 19:47:50 +00003574% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003575% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3576% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003577% ExceptionInfo *exception)
3578%
3579% A description of each parameter follows:
3580%
3581% o image: the image.
3582%
3583% o virtual_pixel_method: the virtual pixel method.
3584%
3585% o x,y,columns,rows: These values define the perimeter of a region of
3586% pixels.
3587%
3588% o exception: return any errors or warnings in this structure.
3589%
3590*/
cristy4c08aed2011-07-01 19:47:50 +00003591static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003592 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3593 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003594{
3595 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003596 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003597
cristy5c9e6f22010-09-17 17:31:01 +00003598 const int
3599 id = GetOpenMPThreadId();
3600
cristy4c08aed2011-07-01 19:47:50 +00003601 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003602 *p;
cristy4c08aed2011-07-01 19:47:50 +00003603
cristye7cc7cf2010-09-21 13:26:47 +00003604 assert(image != (const Image *) NULL);
3605 assert(image->signature == MagickSignature);
3606 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003607 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003608 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003609 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003610 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003611 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003612 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003613}
3614
3615/*
3616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3617% %
3618% %
3619% %
3620% G e t V i r t u a l P i x e l Q u e u e %
3621% %
3622% %
3623% %
3624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3625%
cristy4c08aed2011-07-01 19:47:50 +00003626% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3627% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003628%
3629% The format of the GetVirtualPixelQueue() method is:
3630%
cristy4c08aed2011-07-01 19:47:50 +00003631% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003632%
3633% A description of each parameter follows:
3634%
3635% o image: the image.
3636%
3637*/
cristy4c08aed2011-07-01 19:47:50 +00003638MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003639{
3640 CacheInfo
3641 *cache_info;
3642
cristy2036f5c2010-09-19 21:18:17 +00003643 const int
3644 id = GetOpenMPThreadId();
3645
cristy3ed852e2009-09-05 21:47:34 +00003646 assert(image != (const Image *) NULL);
3647 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003648 assert(image->cache != (Cache) NULL);
3649 cache_info=(CacheInfo *) image->cache;
3650 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003651 if (cache_info->methods.get_virtual_pixels_handler !=
3652 (GetVirtualPixelsHandler) NULL)
3653 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003654 assert(id < (int) cache_info->number_threads);
3655 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003656}
3657
3658/*
3659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3660% %
3661% %
3662% %
3663% G e t V i r t u a l P i x e l s %
3664% %
3665% %
3666% %
3667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3668%
3669% GetVirtualPixels() returns an immutable pixel region. If the
3670% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003671% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003672% copy of the pixels or it may point to the original pixels in memory.
3673% Performance is maximized if the selected region is part of one row, or one
3674% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003675% (without a copy) if the image is in memory, or in a memory-mapped file. The
3676% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003677%
3678% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003679% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3680% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3681% access the meta-content (of type void) corresponding to the the
3682% region.
cristy3ed852e2009-09-05 21:47:34 +00003683%
3684% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3685%
3686% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3687% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3688% GetCacheViewAuthenticPixels() instead.
3689%
3690% The format of the GetVirtualPixels() method is:
3691%
cristy4c08aed2011-07-01 19:47:50 +00003692% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003693% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003694% ExceptionInfo *exception)
3695%
3696% A description of each parameter follows:
3697%
3698% o image: the image.
3699%
3700% o x,y,columns,rows: These values define the perimeter of a region of
3701% pixels.
3702%
3703% o exception: return any errors or warnings in this structure.
3704%
3705*/
cristy4c08aed2011-07-01 19:47:50 +00003706MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003707 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3708 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003709{
3710 CacheInfo
3711 *cache_info;
3712
cristy2036f5c2010-09-19 21:18:17 +00003713 const int
3714 id = GetOpenMPThreadId();
3715
cristy4c08aed2011-07-01 19:47:50 +00003716 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003717 *p;
cristy4c08aed2011-07-01 19:47:50 +00003718
cristy3ed852e2009-09-05 21:47:34 +00003719 assert(image != (const Image *) NULL);
3720 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003721 assert(image->cache != (Cache) NULL);
3722 cache_info=(CacheInfo *) image->cache;
3723 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003724 if (cache_info->methods.get_virtual_pixel_handler !=
3725 (GetVirtualPixelHandler) NULL)
3726 return(cache_info->methods.get_virtual_pixel_handler(image,
3727 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003728 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003729 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003730 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003731 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003732}
3733
3734/*
3735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3736% %
3737% %
3738% %
3739+ 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 %
3740% %
3741% %
3742% %
3743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3744%
cristy4c08aed2011-07-01 19:47:50 +00003745% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3746% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003747%
3748% The format of the GetVirtualPixelsCache() method is:
3749%
cristy4c08aed2011-07-01 19:47:50 +00003750% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003751%
3752% A description of each parameter follows:
3753%
3754% o image: the image.
3755%
3756*/
cristy4c08aed2011-07-01 19:47:50 +00003757static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003758{
3759 CacheInfo
3760 *cache_info;
3761
cristy5c9e6f22010-09-17 17:31:01 +00003762 const int
3763 id = GetOpenMPThreadId();
3764
cristye7cc7cf2010-09-21 13:26:47 +00003765 assert(image != (const Image *) NULL);
3766 assert(image->signature == MagickSignature);
3767 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003768 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003769 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003770 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003771 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003772}
3773
3774/*
3775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3776% %
3777% %
3778% %
3779+ G e t V i r t u a l P i x e l s N e x u s %
3780% %
3781% %
3782% %
3783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3784%
3785% GetVirtualPixelsNexus() returns the pixels associated with the specified
3786% cache nexus.
3787%
3788% The format of the GetVirtualPixelsNexus() method is:
3789%
cristy4c08aed2011-07-01 19:47:50 +00003790% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003791% NexusInfo *nexus_info)
3792%
3793% A description of each parameter follows:
3794%
3795% o cache: the pixel cache.
3796%
3797% o nexus_info: the cache nexus to return the colormap pixels.
3798%
3799*/
cristya6577ff2011-09-02 19:54:26 +00003800MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003801 NexusInfo *nexus_info)
3802{
3803 CacheInfo
3804 *cache_info;
3805
cristye7cc7cf2010-09-21 13:26:47 +00003806 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003807 cache_info=(CacheInfo *) cache;
3808 assert(cache_info->signature == MagickSignature);
3809 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003810 return((Quantum *) NULL);
3811 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003812}
3813
3814/*
3815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3816% %
3817% %
3818% %
3819+ M a s k P i x e l C a c h e N e x u s %
3820% %
3821% %
3822% %
3823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3824%
3825% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3826% The method returns MagickTrue if the pixel region is masked, otherwise
3827% MagickFalse.
3828%
3829% The format of the MaskPixelCacheNexus() method is:
3830%
3831% MagickBooleanType MaskPixelCacheNexus(Image *image,
3832% NexusInfo *nexus_info,ExceptionInfo *exception)
3833%
3834% A description of each parameter follows:
3835%
3836% o image: the image.
3837%
3838% o nexus_info: the cache nexus to clip.
3839%
3840% o exception: return any errors or warnings in this structure.
3841%
3842*/
3843
cristy3aa93752011-12-18 15:54:24 +00003844static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3845 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003846{
3847 MagickRealType
3848 gamma;
3849
cristyaa83c2c2011-09-21 13:36:25 +00003850 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003851 {
3852 *composite=(*q);
3853 return;
3854 }
3855 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3856 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003857 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3858 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3859 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003860 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003861 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003862}
3863
3864static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3865 ExceptionInfo *exception)
3866{
3867 CacheInfo
3868 *cache_info;
3869
cristy4c08aed2011-07-01 19:47:50 +00003870 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003871 alpha,
3872 beta;
3873
3874 MagickSizeType
3875 number_pixels;
3876
3877 NexusInfo
3878 **clip_nexus,
3879 **image_nexus;
3880
cristy4c08aed2011-07-01 19:47:50 +00003881 register const Quantum
3882 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003883 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003884
cristy4c08aed2011-07-01 19:47:50 +00003885 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003886 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003887
cristye076a6e2010-08-15 19:59:43 +00003888 register ssize_t
3889 i;
3890
cristy3ed852e2009-09-05 21:47:34 +00003891 /*
3892 Apply clip mask.
3893 */
3894 if (image->debug != MagickFalse)
3895 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3896 if (image->mask == (Image *) NULL)
3897 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003898 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003899 if (cache_info == (Cache) NULL)
3900 return(MagickFalse);
3901 image_nexus=AcquirePixelCacheNexus(1);
3902 clip_nexus=AcquirePixelCacheNexus(1);
3903 if ((image_nexus == (NexusInfo **) NULL) ||
3904 (clip_nexus == (NexusInfo **) NULL))
3905 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003906 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3907 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3908 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003909 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003910 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3911 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003912 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003913 GetPixelInfo(image,&alpha);
3914 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003915 number_pixels=(MagickSizeType) nexus_info->region.width*
3916 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003917 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003918 {
cristy4c08aed2011-07-01 19:47:50 +00003919 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003920 break;
cristy803640d2011-11-17 02:11:32 +00003921 GetPixelInfoPixel(image,p,&alpha);
3922 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003923 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003924 &alpha,alpha.alpha,&beta);
3925 SetPixelRed(image,ClampToQuantum(beta.red),q);
3926 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3927 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3928 if (cache_info->colorspace == CMYKColorspace)
3929 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3930 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003931 p++;
3932 q++;
3933 r++;
3934 }
3935 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3936 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003937 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003938 return(MagickFalse);
3939 return(MagickTrue);
3940}
3941
3942/*
3943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3944% %
3945% %
3946% %
3947+ O p e n P i x e l C a c h e %
3948% %
3949% %
3950% %
3951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3952%
3953% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3954% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003955% metacontent, and memory mapping the cache if it is disk based. The cache
3956% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003957%
3958% The format of the OpenPixelCache() method is:
3959%
3960% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3961% ExceptionInfo *exception)
3962%
3963% A description of each parameter follows:
3964%
3965% o image: the image.
3966%
3967% o mode: ReadMode, WriteMode, or IOMode.
3968%
3969% o exception: return any errors or warnings in this structure.
3970%
3971*/
3972
cristyd43a46b2010-01-21 02:13:41 +00003973static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003974{
3975 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003976 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003977 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003978 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003979 {
3980 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003981 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003982 cache_info->length);
3983 }
3984}
3985
3986static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3987{
3988 CacheInfo
3989 *cache_info;
3990
3991 MagickOffsetType
3992 count,
3993 extent,
3994 offset;
3995
3996 cache_info=(CacheInfo *) image->cache;
3997 if (image->debug != MagickFalse)
3998 {
3999 char
4000 format[MaxTextExtent],
4001 message[MaxTextExtent];
4002
cristyb9080c92009-12-01 20:13:26 +00004003 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004004 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004005 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004006 cache_info->cache_filename,cache_info->file,format);
4007 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4008 }
4009 if (length != (MagickSizeType) ((MagickOffsetType) length))
4010 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004011 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004012 if (extent < 0)
4013 return(MagickFalse);
4014 if ((MagickSizeType) extent >= length)
4015 return(MagickTrue);
4016 offset=(MagickOffsetType) length-1;
4017 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4018 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4019}
4020
4021static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4022 ExceptionInfo *exception)
4023{
cristy3ed852e2009-09-05 21:47:34 +00004024 CacheInfo
4025 *cache_info,
4026 source_info;
4027
cristyf3a6a9d2010-11-07 21:02:56 +00004028 char
4029 format[MaxTextExtent],
4030 message[MaxTextExtent];
4031
cristy4c08aed2011-07-01 19:47:50 +00004032 MagickBooleanType
4033 status;
4034
cristy3ed852e2009-09-05 21:47:34 +00004035 MagickSizeType
4036 length,
4037 number_pixels;
4038
cristy3b8fe922011-12-29 18:56:23 +00004039 PixelChannelMap
4040 *p,
4041 *q;
4042
cristy3ed852e2009-09-05 21:47:34 +00004043 size_t
cristye076a6e2010-08-15 19:59:43 +00004044 columns,
cristy3ed852e2009-09-05 21:47:34 +00004045 packet_size;
4046
cristye7cc7cf2010-09-21 13:26:47 +00004047 assert(image != (const Image *) NULL);
4048 assert(image->signature == MagickSignature);
4049 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004050 if (image->debug != MagickFalse)
4051 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4052 if ((image->columns == 0) || (image->rows == 0))
4053 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4054 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004055 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004056 source_info=(*cache_info);
4057 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004058 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004059 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004060 cache_info->storage_class=image->storage_class;
4061 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004062 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004063 cache_info->rows=image->rows;
4064 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004065 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004066 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004067 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4068 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004069 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004070 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004071 if (image->ping != MagickFalse)
4072 {
cristy73724512010-04-12 14:43:14 +00004073 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004074 cache_info->pixels=(Quantum *) NULL;
4075 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004076 cache_info->length=0;
4077 return(MagickTrue);
4078 }
cristy3ed852e2009-09-05 21:47:34 +00004079 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004080 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004081 if (image->metacontent_extent != 0)
4082 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004083 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004084 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004085 if (cache_info->columns != columns)
4086 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4087 image->filename);
4088 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004089 p=cache_info->channel_map;
4090 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004091 if ((cache_info->type != UndefinedCache) &&
4092 (cache_info->columns <= source_info.columns) &&
4093 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004094 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004095 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004096 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4097 {
4098 /*
4099 Inline pixel cache clone optimization.
4100 */
4101 if ((cache_info->columns == source_info.columns) &&
4102 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004103 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004104 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004105 (cache_info->metacontent_extent == source_info.metacontent_extent))
4106 return(MagickTrue);
4107 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4108 }
cristy3ed852e2009-09-05 21:47:34 +00004109 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004110 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004111 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004112 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4113 {
4114 status=AcquireMagickResource(MemoryResource,cache_info->length);
4115 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4116 (cache_info->type == MemoryCache))
4117 {
cristyd43a46b2010-01-21 02:13:41 +00004118 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004119 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004120 cache_info->pixels=source_info.pixels;
4121 else
4122 {
4123 /*
4124 Create memory pixel cache.
4125 */
cristy4c08aed2011-07-01 19:47:50 +00004126 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004127 if (image->debug != MagickFalse)
4128 {
cristy32cacff2011-12-31 03:36:27 +00004129 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004130 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004131 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4132 cache_info->filename,cache_info->mapped != MagickFalse ?
4133 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004134 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004135 format);
cristy3ed852e2009-09-05 21:47:34 +00004136 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4137 message);
4138 }
cristy3ed852e2009-09-05 21:47:34 +00004139 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004140 cache_info->metacontent=(void *) NULL;
4141 if (cache_info->metacontent_extent != 0)
4142 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004143 number_pixels*cache_info->number_channels);
cristycacc77e2011-12-31 17:20:21 +00004144 if (source_info.type != UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00004145 {
cristy4c08aed2011-07-01 19:47:50 +00004146 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004147 exception);
4148 RelinquishPixelCachePixels(&source_info);
4149 }
cristy4c08aed2011-07-01 19:47:50 +00004150 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004151 }
4152 }
4153 RelinquishMagickResource(MemoryResource,cache_info->length);
4154 }
4155 /*
4156 Create pixel cache on disk.
4157 */
4158 status=AcquireMagickResource(DiskResource,cache_info->length);
4159 if (status == MagickFalse)
4160 {
4161 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4162 "CacheResourcesExhausted","`%s'",image->filename);
4163 return(MagickFalse);
4164 }
cristycacc77e2011-12-31 17:20:21 +00004165 if (source_info.type != UndefinedCache)
4166 *cache_info->cache_filename='\0';
cristy3ed852e2009-09-05 21:47:34 +00004167 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4168 {
4169 RelinquishMagickResource(DiskResource,cache_info->length);
4170 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4171 image->filename);
4172 return(MagickFalse);
4173 }
4174 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4175 cache_info->length);
4176 if (status == MagickFalse)
4177 {
4178 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4179 image->filename);
4180 return(MagickFalse);
4181 }
cristyed231572011-07-14 02:18:59 +00004182 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004183 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004184 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004185 cache_info->type=DiskCache;
4186 else
4187 {
4188 status=AcquireMagickResource(MapResource,cache_info->length);
4189 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4190 (cache_info->type != MemoryCache))
4191 cache_info->type=DiskCache;
4192 else
4193 {
cristy4c08aed2011-07-01 19:47:50 +00004194 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004195 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004196 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004197 {
cristy3ed852e2009-09-05 21:47:34 +00004198 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004199 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004200 }
4201 else
4202 {
4203 /*
4204 Create file-backed memory-mapped pixel cache.
4205 */
cristy4c08aed2011-07-01 19:47:50 +00004206 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004207 (void) ClosePixelCacheOnDisk(cache_info);
4208 cache_info->type=MapCache;
4209 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004210 cache_info->metacontent=(void *) NULL;
4211 if (cache_info->metacontent_extent != 0)
4212 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004213 number_pixels*cache_info->number_channels);
cristycacc77e2011-12-31 17:20:21 +00004214 if (source_info.type != UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00004215 {
4216 status=ClonePixelCachePixels(cache_info,&source_info,
4217 exception);
4218 RelinquishPixelCachePixels(&source_info);
4219 }
4220 if (image->debug != MagickFalse)
4221 {
cristy97e7a572009-12-05 15:07:53 +00004222 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004223 format);
cristyb51dff52011-05-19 16:55:47 +00004224 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004225 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004226 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004227 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004228 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004229 format);
cristy3ed852e2009-09-05 21:47:34 +00004230 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4231 message);
4232 }
cristy4c08aed2011-07-01 19:47:50 +00004233 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004234 }
4235 }
4236 RelinquishMagickResource(MapResource,cache_info->length);
4237 }
cristy4c08aed2011-07-01 19:47:50 +00004238 status=MagickTrue;
cristycacc77e2011-12-31 17:20:21 +00004239 if (source_info.type != UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00004240 {
4241 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4242 RelinquishPixelCachePixels(&source_info);
4243 }
4244 if (image->debug != MagickFalse)
4245 {
cristyb9080c92009-12-01 20:13:26 +00004246 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004247 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004248 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004249 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004250 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004251 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004252 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4253 }
cristy4c08aed2011-07-01 19:47:50 +00004254 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004255}
4256
4257/*
4258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4259% %
4260% %
4261% %
4262+ P e r s i s t P i x e l C a c h e %
4263% %
4264% %
4265% %
4266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4267%
4268% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4269% persistent pixel cache is one that resides on disk and is not destroyed
4270% when the program exits.
4271%
4272% The format of the PersistPixelCache() method is:
4273%
4274% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4275% const MagickBooleanType attach,MagickOffsetType *offset,
4276% ExceptionInfo *exception)
4277%
4278% A description of each parameter follows:
4279%
4280% o image: the image.
4281%
4282% o filename: the persistent pixel cache filename.
4283%
cristyf3a6a9d2010-11-07 21:02:56 +00004284% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004285%
cristy3ed852e2009-09-05 21:47:34 +00004286% o initialize: A value other than zero initializes the persistent pixel
4287% cache.
4288%
4289% o offset: the offset in the persistent cache to store pixels.
4290%
4291% o exception: return any errors or warnings in this structure.
4292%
4293*/
4294MagickExport MagickBooleanType PersistPixelCache(Image *image,
4295 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4296 ExceptionInfo *exception)
4297{
4298 CacheInfo
4299 *cache_info,
4300 *clone_info;
4301
4302 Image
4303 clone_image;
4304
cristy3ed852e2009-09-05 21:47:34 +00004305 MagickBooleanType
4306 status;
4307
cristye076a6e2010-08-15 19:59:43 +00004308 ssize_t
4309 page_size;
4310
cristy3ed852e2009-09-05 21:47:34 +00004311 assert(image != (Image *) NULL);
4312 assert(image->signature == MagickSignature);
4313 if (image->debug != MagickFalse)
4314 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4315 assert(image->cache != (void *) NULL);
4316 assert(filename != (const char *) NULL);
4317 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004318 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004319 cache_info=(CacheInfo *) image->cache;
4320 assert(cache_info->signature == MagickSignature);
4321 if (attach != MagickFalse)
4322 {
4323 /*
cristy01b7eb02009-09-10 23:10:14 +00004324 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004325 */
4326 if (image->debug != MagickFalse)
4327 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004328 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004329 (void) CopyMagickString(cache_info->cache_filename,filename,
4330 MaxTextExtent);
4331 cache_info->type=DiskCache;
4332 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004333 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004334 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004335 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004336 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004337 }
cristy01b7eb02009-09-10 23:10:14 +00004338 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4339 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004340 {
cristyf84a1932010-01-03 18:00:18 +00004341 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004342 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004343 (cache_info->reference_count == 1))
4344 {
4345 int
4346 status;
4347
4348 /*
cristy01b7eb02009-09-10 23:10:14 +00004349 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004350 */
cristy320684d2011-09-23 14:55:47 +00004351 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004352 if (status == 0)
4353 {
4354 (void) CopyMagickString(cache_info->cache_filename,filename,
4355 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004356 *offset+=cache_info->length+page_size-(cache_info->length %
4357 page_size);
cristyf84a1932010-01-03 18:00:18 +00004358 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004359 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004360 if (image->debug != MagickFalse)
4361 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4362 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004363 return(MagickTrue);
4364 }
4365 }
cristyf84a1932010-01-03 18:00:18 +00004366 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004367 }
4368 /*
cristy01b7eb02009-09-10 23:10:14 +00004369 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004370 */
4371 clone_image=(*image);
4372 clone_info=(CacheInfo *) clone_image.cache;
4373 image->cache=ClonePixelCache(cache_info);
4374 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4375 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4376 cache_info->type=DiskCache;
4377 cache_info->offset=(*offset);
4378 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004379 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004380 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004381 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004382 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004383 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4384 return(status);
4385}
4386
4387/*
4388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4389% %
4390% %
4391% %
4392+ Q u e u e A u t h e n t i c N e x u s %
4393% %
4394% %
4395% %
4396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4397%
4398% QueueAuthenticNexus() allocates an region to store image pixels as defined
4399% by the region rectangle and returns a pointer to the region. This region is
4400% subsequently transferred from the pixel cache with
4401% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4402% pixels are transferred, otherwise a NULL is returned.
4403%
4404% The format of the QueueAuthenticNexus() method is:
4405%
cristy4c08aed2011-07-01 19:47:50 +00004406% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004407% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004408% const MagickBooleanType clone,NexusInfo *nexus_info,
4409% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004410%
4411% A description of each parameter follows:
4412%
4413% o image: the image.
4414%
4415% o x,y,columns,rows: These values define the perimeter of a region of
4416% pixels.
4417%
4418% o nexus_info: the cache nexus to set.
4419%
cristy65dbf172011-10-06 17:32:04 +00004420% o clone: clone the pixel cache.
4421%
cristy3ed852e2009-09-05 21:47:34 +00004422% o exception: return any errors or warnings in this structure.
4423%
4424*/
cristya6577ff2011-09-02 19:54:26 +00004425MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004426 const ssize_t y,const size_t columns,const size_t rows,
4427 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004428{
4429 CacheInfo
4430 *cache_info;
4431
4432 MagickOffsetType
4433 offset;
4434
4435 MagickSizeType
4436 number_pixels;
4437
4438 RectangleInfo
4439 region;
4440
4441 /*
4442 Validate pixel cache geometry.
4443 */
cristye7cc7cf2010-09-21 13:26:47 +00004444 assert(image != (const Image *) NULL);
4445 assert(image->signature == MagickSignature);
4446 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004447 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004448 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004449 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004450 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004451 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4452 {
4453 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4454 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004455 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004456 }
cristybb503372010-05-27 20:51:26 +00004457 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4458 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004459 {
4460 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4461 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004462 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004463 }
4464 offset=(MagickOffsetType) y*cache_info->columns+x;
4465 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004466 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004467 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4468 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4469 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004470 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004471 /*
4472 Return pixel cache.
4473 */
4474 region.x=x;
4475 region.y=y;
4476 region.width=columns;
4477 region.height=rows;
4478 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4479}
4480
4481/*
4482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4483% %
4484% %
4485% %
4486+ 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 %
4487% %
4488% %
4489% %
4490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4491%
4492% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4493% defined by the region rectangle and returns a pointer to the region. This
4494% region is subsequently transferred from the pixel cache with
4495% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4496% pixels are transferred, otherwise a NULL is returned.
4497%
4498% The format of the QueueAuthenticPixelsCache() method is:
4499%
cristy4c08aed2011-07-01 19:47:50 +00004500% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004501% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004502% ExceptionInfo *exception)
4503%
4504% A description of each parameter follows:
4505%
4506% o image: the image.
4507%
4508% o x,y,columns,rows: These values define the perimeter of a region of
4509% pixels.
4510%
4511% o exception: return any errors or warnings in this structure.
4512%
4513*/
cristy4c08aed2011-07-01 19:47:50 +00004514static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004515 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004516 ExceptionInfo *exception)
4517{
4518 CacheInfo
4519 *cache_info;
4520
cristy5c9e6f22010-09-17 17:31:01 +00004521 const int
4522 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004523
cristy4c08aed2011-07-01 19:47:50 +00004524 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004525 *q;
cristy4c08aed2011-07-01 19:47:50 +00004526
cristye7cc7cf2010-09-21 13:26:47 +00004527 assert(image != (const Image *) NULL);
4528 assert(image->signature == MagickSignature);
4529 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004530 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004531 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004532 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004533 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4534 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004535 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004536}
4537
4538/*
4539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4540% %
4541% %
4542% %
4543% Q u e u e A u t h e n t i c P i x e l s %
4544% %
4545% %
4546% %
4547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4548%
4549% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004550% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004551% region is returned, otherwise NULL is returned. The returned pointer may
4552% point to a temporary working buffer for the pixels or it may point to the
4553% final location of the pixels in memory.
4554%
4555% Write-only access means that any existing pixel values corresponding to
4556% the region are ignored. This is useful if the initial image is being
4557% created from scratch, or if the existing pixel values are to be
4558% completely replaced without need to refer to their pre-existing values.
4559% The application is free to read and write the pixel buffer returned by
4560% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4561% initialize the pixel array values. Initializing pixel array values is the
4562% application's responsibility.
4563%
4564% Performance is maximized if the selected region is part of one row, or
4565% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004566% pixels in-place (without a copy) if the image is in memory, or in a
4567% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004568% by the user.
4569%
4570% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004571% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4572% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4573% obtain the meta-content (of type void) corresponding to the region.
4574% Once the Quantum (and/or Quantum) array has been updated, the
4575% changes must be saved back to the underlying image using
4576% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004577%
4578% The format of the QueueAuthenticPixels() method is:
4579%
cristy4c08aed2011-07-01 19:47:50 +00004580% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004581% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004582% ExceptionInfo *exception)
4583%
4584% A description of each parameter follows:
4585%
4586% o image: the image.
4587%
4588% o x,y,columns,rows: These values define the perimeter of a region of
4589% pixels.
4590%
4591% o exception: return any errors or warnings in this structure.
4592%
4593*/
cristy4c08aed2011-07-01 19:47:50 +00004594MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004595 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004596 ExceptionInfo *exception)
4597{
4598 CacheInfo
4599 *cache_info;
4600
cristy2036f5c2010-09-19 21:18:17 +00004601 const int
4602 id = GetOpenMPThreadId();
4603
cristy4c08aed2011-07-01 19:47:50 +00004604 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004605 *q;
cristy4c08aed2011-07-01 19:47:50 +00004606
cristy3ed852e2009-09-05 21:47:34 +00004607 assert(image != (Image *) NULL);
4608 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004609 assert(image->cache != (Cache) NULL);
4610 cache_info=(CacheInfo *) image->cache;
4611 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004612 if (cache_info->methods.queue_authentic_pixels_handler !=
4613 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004614 {
cristyacd2ed22011-08-30 01:44:23 +00004615 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004616 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004617 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004618 }
cristy2036f5c2010-09-19 21:18:17 +00004619 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004620 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4621 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004622 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004623}
4624
4625/*
4626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4627% %
4628% %
4629% %
cristy4c08aed2011-07-01 19:47:50 +00004630+ 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 +00004631% %
4632% %
4633% %
4634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4635%
cristy4c08aed2011-07-01 19:47:50 +00004636% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004637% the pixel cache.
4638%
cristy4c08aed2011-07-01 19:47:50 +00004639% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004640%
cristy4c08aed2011-07-01 19:47:50 +00004641% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004642% NexusInfo *nexus_info,ExceptionInfo *exception)
4643%
4644% A description of each parameter follows:
4645%
4646% o cache_info: the pixel cache.
4647%
cristy4c08aed2011-07-01 19:47:50 +00004648% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004649%
4650% o exception: return any errors or warnings in this structure.
4651%
4652*/
cristy4c08aed2011-07-01 19:47:50 +00004653static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004654 NexusInfo *nexus_info,ExceptionInfo *exception)
4655{
4656 MagickOffsetType
4657 count,
4658 offset;
4659
4660 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004661 extent,
4662 length;
cristy3ed852e2009-09-05 21:47:34 +00004663
cristybb503372010-05-27 20:51:26 +00004664 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004665 y;
4666
cristy4c08aed2011-07-01 19:47:50 +00004667 register unsigned char
4668 *restrict q;
4669
cristybb503372010-05-27 20:51:26 +00004670 size_t
cristy3ed852e2009-09-05 21:47:34 +00004671 rows;
4672
cristy4c08aed2011-07-01 19:47:50 +00004673 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004674 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004675 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004676 return(MagickTrue);
4677 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4678 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004679 length=(MagickSizeType) nexus_info->region.width*
4680 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004681 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004682 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004683 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004684 switch (cache_info->type)
4685 {
4686 case MemoryCache:
4687 case MapCache:
4688 {
cristy4c08aed2011-07-01 19:47:50 +00004689 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004690 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004691
4692 /*
cristy4c08aed2011-07-01 19:47:50 +00004693 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004694 */
cristydd341db2010-03-04 19:06:38 +00004695 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004696 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004697 {
cristy48078b12010-09-23 17:11:01 +00004698 length=extent;
cristydd341db2010-03-04 19:06:38 +00004699 rows=1UL;
4700 }
cristy4c08aed2011-07-01 19:47:50 +00004701 p=(unsigned char *) cache_info->metacontent+offset*
4702 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004703 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004704 {
cristy8f036fe2010-09-18 02:02:00 +00004705 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004706 p+=cache_info->metacontent_extent*cache_info->columns;
4707 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004708 }
4709 break;
4710 }
4711 case DiskCache:
4712 {
4713 /*
cristy4c08aed2011-07-01 19:47:50 +00004714 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004715 */
4716 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4717 {
4718 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4719 cache_info->cache_filename);
4720 return(MagickFalse);
4721 }
cristydd341db2010-03-04 19:06:38 +00004722 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004723 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004724 {
cristy48078b12010-09-23 17:11:01 +00004725 length=extent;
cristydd341db2010-03-04 19:06:38 +00004726 rows=1UL;
4727 }
cristy48078b12010-09-23 17:11:01 +00004728 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004729 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004730 {
cristy48078b12010-09-23 17:11:01 +00004731 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004732 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004733 cache_info->metacontent_extent,length,(unsigned char *) q);
4734 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004735 break;
4736 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004737 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004738 }
cristybb503372010-05-27 20:51:26 +00004739 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004740 {
4741 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4742 cache_info->cache_filename);
4743 return(MagickFalse);
4744 }
4745 break;
4746 }
4747 default:
4748 break;
4749 }
4750 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004751 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004752 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004753 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004754 nexus_info->region.width,(double) nexus_info->region.height,(double)
4755 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004756 return(MagickTrue);
4757}
4758
4759/*
4760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4761% %
4762% %
4763% %
4764+ R e a d P i x e l C a c h e P i x e l s %
4765% %
4766% %
4767% %
4768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4769%
4770% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4771% cache.
4772%
4773% The format of the ReadPixelCachePixels() method is:
4774%
4775% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4776% NexusInfo *nexus_info,ExceptionInfo *exception)
4777%
4778% A description of each parameter follows:
4779%
4780% o cache_info: the pixel cache.
4781%
4782% o nexus_info: the cache nexus to read the pixels.
4783%
4784% o exception: return any errors or warnings in this structure.
4785%
4786*/
4787static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4788 NexusInfo *nexus_info,ExceptionInfo *exception)
4789{
4790 MagickOffsetType
4791 count,
4792 offset;
4793
4794 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004795 extent,
4796 length;
cristy3ed852e2009-09-05 21:47:34 +00004797
cristy4c08aed2011-07-01 19:47:50 +00004798 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004799 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004800
cristye076a6e2010-08-15 19:59:43 +00004801 register ssize_t
4802 y;
4803
cristybb503372010-05-27 20:51:26 +00004804 size_t
cristy3ed852e2009-09-05 21:47:34 +00004805 rows;
4806
cristy4c08aed2011-07-01 19:47:50 +00004807 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004808 return(MagickTrue);
4809 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4810 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004811 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004812 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004813 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004814 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004815 q=nexus_info->pixels;
4816 switch (cache_info->type)
4817 {
4818 case MemoryCache:
4819 case MapCache:
4820 {
cristy4c08aed2011-07-01 19:47:50 +00004821 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004822 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004823
4824 /*
4825 Read pixels from memory.
4826 */
cristydd341db2010-03-04 19:06:38 +00004827 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004828 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004829 {
cristy48078b12010-09-23 17:11:01 +00004830 length=extent;
cristydd341db2010-03-04 19:06:38 +00004831 rows=1UL;
4832 }
cristyed231572011-07-14 02:18:59 +00004833 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004834 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004835 {
cristy8f036fe2010-09-18 02:02:00 +00004836 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004837 p+=cache_info->number_channels*cache_info->columns;
4838 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004839 }
4840 break;
4841 }
4842 case DiskCache:
4843 {
4844 /*
4845 Read pixels from disk.
4846 */
4847 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4848 {
4849 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4850 cache_info->cache_filename);
4851 return(MagickFalse);
4852 }
cristydd341db2010-03-04 19:06:38 +00004853 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004854 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004855 {
cristy48078b12010-09-23 17:11:01 +00004856 length=extent;
cristydd341db2010-03-04 19:06:38 +00004857 rows=1UL;
4858 }
cristybb503372010-05-27 20:51:26 +00004859 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004860 {
4861 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004862 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004863 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004864 break;
4865 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004866 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004867 }
cristybb503372010-05-27 20:51:26 +00004868 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004869 {
4870 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4871 cache_info->cache_filename);
4872 return(MagickFalse);
4873 }
4874 break;
4875 }
4876 default:
4877 break;
4878 }
4879 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004880 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004881 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004882 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004883 nexus_info->region.width,(double) nexus_info->region.height,(double)
4884 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004885 return(MagickTrue);
4886}
4887
4888/*
4889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4890% %
4891% %
4892% %
4893+ R e f e r e n c e P i x e l C a c h e %
4894% %
4895% %
4896% %
4897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4898%
4899% ReferencePixelCache() increments the reference count associated with the
4900% pixel cache returning a pointer to the cache.
4901%
4902% The format of the ReferencePixelCache method is:
4903%
4904% Cache ReferencePixelCache(Cache cache_info)
4905%
4906% A description of each parameter follows:
4907%
4908% o cache_info: the pixel cache.
4909%
4910*/
cristya6577ff2011-09-02 19:54:26 +00004911MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004912{
4913 CacheInfo
4914 *cache_info;
4915
4916 assert(cache != (Cache *) NULL);
4917 cache_info=(CacheInfo *) cache;
4918 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004919 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004920 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004921 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004922 return(cache_info);
4923}
4924
4925/*
4926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4927% %
4928% %
4929% %
4930+ S e t P i x e l C a c h e M e t h o d s %
4931% %
4932% %
4933% %
4934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4935%
4936% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4937%
4938% The format of the SetPixelCacheMethods() method is:
4939%
4940% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4941%
4942% A description of each parameter follows:
4943%
4944% o cache: the pixel cache.
4945%
4946% o cache_methods: Specifies a pointer to a CacheMethods structure.
4947%
4948*/
cristya6577ff2011-09-02 19:54:26 +00004949MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004950{
4951 CacheInfo
4952 *cache_info;
4953
4954 GetOneAuthenticPixelFromHandler
4955 get_one_authentic_pixel_from_handler;
4956
4957 GetOneVirtualPixelFromHandler
4958 get_one_virtual_pixel_from_handler;
4959
4960 /*
4961 Set cache pixel methods.
4962 */
4963 assert(cache != (Cache) NULL);
4964 assert(cache_methods != (CacheMethods *) NULL);
4965 cache_info=(CacheInfo *) cache;
4966 assert(cache_info->signature == MagickSignature);
4967 if (cache_info->debug != MagickFalse)
4968 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4969 cache_info->filename);
4970 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4971 cache_info->methods.get_virtual_pixel_handler=
4972 cache_methods->get_virtual_pixel_handler;
4973 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4974 cache_info->methods.destroy_pixel_handler=
4975 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004976 if (cache_methods->get_virtual_metacontent_from_handler !=
4977 (GetVirtualMetacontentFromHandler) NULL)
4978 cache_info->methods.get_virtual_metacontent_from_handler=
4979 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004980 if (cache_methods->get_authentic_pixels_handler !=
4981 (GetAuthenticPixelsHandler) NULL)
4982 cache_info->methods.get_authentic_pixels_handler=
4983 cache_methods->get_authentic_pixels_handler;
4984 if (cache_methods->queue_authentic_pixels_handler !=
4985 (QueueAuthenticPixelsHandler) NULL)
4986 cache_info->methods.queue_authentic_pixels_handler=
4987 cache_methods->queue_authentic_pixels_handler;
4988 if (cache_methods->sync_authentic_pixels_handler !=
4989 (SyncAuthenticPixelsHandler) NULL)
4990 cache_info->methods.sync_authentic_pixels_handler=
4991 cache_methods->sync_authentic_pixels_handler;
4992 if (cache_methods->get_authentic_pixels_from_handler !=
4993 (GetAuthenticPixelsFromHandler) NULL)
4994 cache_info->methods.get_authentic_pixels_from_handler=
4995 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004996 if (cache_methods->get_authentic_metacontent_from_handler !=
4997 (GetAuthenticMetacontentFromHandler) NULL)
4998 cache_info->methods.get_authentic_metacontent_from_handler=
4999 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00005000 get_one_virtual_pixel_from_handler=
5001 cache_info->methods.get_one_virtual_pixel_from_handler;
5002 if (get_one_virtual_pixel_from_handler !=
5003 (GetOneVirtualPixelFromHandler) NULL)
5004 cache_info->methods.get_one_virtual_pixel_from_handler=
5005 cache_methods->get_one_virtual_pixel_from_handler;
5006 get_one_authentic_pixel_from_handler=
5007 cache_methods->get_one_authentic_pixel_from_handler;
5008 if (get_one_authentic_pixel_from_handler !=
5009 (GetOneAuthenticPixelFromHandler) NULL)
5010 cache_info->methods.get_one_authentic_pixel_from_handler=
5011 cache_methods->get_one_authentic_pixel_from_handler;
5012}
5013
5014/*
5015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5016% %
5017% %
5018% %
5019+ S e t P i x e l C a c h e N e x u s P i x e l s %
5020% %
5021% %
5022% %
5023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5024%
5025% SetPixelCacheNexusPixels() defines the region of the cache for the
5026% specified cache nexus.
5027%
5028% The format of the SetPixelCacheNexusPixels() method is:
5029%
cristy4c08aed2011-07-01 19:47:50 +00005030% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005031% const RectangleInfo *region,NexusInfo *nexus_info,
5032% ExceptionInfo *exception)
5033%
5034% A description of each parameter follows:
5035%
5036% o image: the image.
5037%
5038% o region: A pointer to the RectangleInfo structure that defines the
5039% region of this particular cache nexus.
5040%
5041% o nexus_info: the cache nexus to set.
5042%
5043% o exception: return any errors or warnings in this structure.
5044%
5045*/
cristyabd6e372010-09-15 19:11:26 +00005046
5047static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5048 NexusInfo *nexus_info,ExceptionInfo *exception)
5049{
5050 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5051 return(MagickFalse);
5052 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005053 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005054 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005055 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005056 {
5057 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005058 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005059 nexus_info->length);
5060 }
cristy4c08aed2011-07-01 19:47:50 +00005061 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005062 {
5063 (void) ThrowMagickException(exception,GetMagickModule(),
5064 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5065 cache_info->filename);
5066 return(MagickFalse);
5067 }
5068 return(MagickTrue);
5069}
5070
cristy4c08aed2011-07-01 19:47:50 +00005071static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005072 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5073{
5074 CacheInfo
5075 *cache_info;
5076
5077 MagickBooleanType
5078 status;
5079
cristy3ed852e2009-09-05 21:47:34 +00005080 MagickSizeType
5081 length,
5082 number_pixels;
5083
cristy3ed852e2009-09-05 21:47:34 +00005084 cache_info=(CacheInfo *) image->cache;
5085 assert(cache_info->signature == MagickSignature);
5086 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005087 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005088 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005089 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5090 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005091 {
cristybb503372010-05-27 20:51:26 +00005092 ssize_t
cristybad067a2010-02-15 17:20:55 +00005093 x,
5094 y;
cristy3ed852e2009-09-05 21:47:34 +00005095
cristyeaedf062010-05-29 22:36:02 +00005096 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5097 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005098 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5099 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005100 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005101 ((nexus_info->region.width == cache_info->columns) ||
5102 ((nexus_info->region.width % cache_info->columns) == 0)))))
5103 {
5104 MagickOffsetType
5105 offset;
5106
5107 /*
5108 Pixels are accessed directly from memory.
5109 */
5110 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5111 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005112 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005113 offset;
5114 nexus_info->metacontent=(void *) NULL;
5115 if (cache_info->metacontent_extent != 0)
5116 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5117 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005118 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005119 }
5120 }
5121 /*
5122 Pixels are stored in a cache region until they are synced to the cache.
5123 */
5124 number_pixels=(MagickSizeType) nexus_info->region.width*
5125 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005126 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005127 if (cache_info->metacontent_extent != 0)
5128 length+=number_pixels*cache_info->metacontent_extent;
5129 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005130 {
5131 nexus_info->length=length;
5132 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5133 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005134 {
5135 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005136 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005137 }
cristy3ed852e2009-09-05 21:47:34 +00005138 }
5139 else
5140 if (nexus_info->length != length)
5141 {
5142 RelinquishCacheNexusPixels(nexus_info);
5143 nexus_info->length=length;
5144 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5145 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005146 {
5147 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005148 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005149 }
cristy3ed852e2009-09-05 21:47:34 +00005150 }
5151 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005152 nexus_info->metacontent=(void *) NULL;
5153 if (cache_info->metacontent_extent != 0)
5154 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005155 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005156 return(nexus_info->pixels);
5157}
5158
5159/*
5160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5161% %
5162% %
5163% %
5164% 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 %
5165% %
5166% %
5167% %
5168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5169%
5170% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5171% pixel cache and returns the previous setting. A virtual pixel is any pixel
5172% access that is outside the boundaries of the image cache.
5173%
5174% The format of the SetPixelCacheVirtualMethod() method is:
5175%
5176% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5177% const VirtualPixelMethod virtual_pixel_method)
5178%
5179% A description of each parameter follows:
5180%
5181% o image: the image.
5182%
5183% o virtual_pixel_method: choose the type of virtual pixel.
5184%
5185*/
cristyd1dd6e42011-09-04 01:46:08 +00005186MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005187 const VirtualPixelMethod virtual_pixel_method)
5188{
5189 CacheInfo
5190 *cache_info;
5191
5192 VirtualPixelMethod
5193 method;
5194
5195 assert(image != (Image *) NULL);
5196 assert(image->signature == MagickSignature);
5197 if (image->debug != MagickFalse)
5198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5199 assert(image->cache != (Cache) NULL);
5200 cache_info=(CacheInfo *) image->cache;
5201 assert(cache_info->signature == MagickSignature);
5202 method=cache_info->virtual_pixel_method;
5203 cache_info->virtual_pixel_method=virtual_pixel_method;
5204 return(method);
5205}
5206
5207/*
5208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5209% %
5210% %
5211% %
5212+ S y n c A u t h e n t i c P i x e l C a c h e N e x u s %
5213% %
5214% %
5215% %
5216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217%
5218% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5219% in-memory or disk cache. The method returns MagickTrue if the pixel region
5220% is synced, otherwise MagickFalse.
5221%
5222% The format of the SyncAuthenticPixelCacheNexus() method is:
5223%
5224% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5225% NexusInfo *nexus_info,ExceptionInfo *exception)
5226%
5227% A description of each parameter follows:
5228%
5229% o image: the image.
5230%
5231% o nexus_info: the cache nexus to sync.
5232%
5233% o exception: return any errors or warnings in this structure.
5234%
5235*/
cristya6577ff2011-09-02 19:54:26 +00005236MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005237 NexusInfo *nexus_info,ExceptionInfo *exception)
5238{
5239 CacheInfo
5240 *cache_info;
5241
5242 MagickBooleanType
5243 status;
5244
5245 /*
5246 Transfer pixels to the cache.
5247 */
5248 assert(image != (Image *) NULL);
5249 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005250 if (image->cache == (Cache) NULL)
5251 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5252 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005253 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005254 if (cache_info->type == UndefinedCache)
5255 return(MagickFalse);
5256 if ((image->clip_mask != (Image *) NULL) &&
5257 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5258 return(MagickFalse);
5259 if ((image->mask != (Image *) NULL) &&
5260 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5261 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005262 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005263 return(MagickTrue);
5264 assert(cache_info->signature == MagickSignature);
5265 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005266 if ((cache_info->metacontent_extent != 0) &&
5267 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005268 return(MagickFalse);
5269 return(status);
5270}
5271
5272/*
5273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5274% %
5275% %
5276% %
5277+ S y n c A u t h e n t i c P i x e l C a c h e %
5278% %
5279% %
5280% %
5281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5282%
5283% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5284% or disk cache. The method returns MagickTrue if the pixel region is synced,
5285% otherwise MagickFalse.
5286%
5287% The format of the SyncAuthenticPixelsCache() method is:
5288%
5289% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5290% ExceptionInfo *exception)
5291%
5292% A description of each parameter follows:
5293%
5294% o image: the image.
5295%
5296% o exception: return any errors or warnings in this structure.
5297%
5298*/
5299static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5300 ExceptionInfo *exception)
5301{
5302 CacheInfo
5303 *cache_info;
5304
cristy5c9e6f22010-09-17 17:31:01 +00005305 const int
5306 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005307
cristy4c08aed2011-07-01 19:47:50 +00005308 MagickBooleanType
5309 status;
5310
cristye7cc7cf2010-09-21 13:26:47 +00005311 assert(image != (Image *) NULL);
5312 assert(image->signature == MagickSignature);
5313 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005314 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005315 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005316 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005317 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5318 exception);
5319 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005320}
5321
5322/*
5323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5324% %
5325% %
5326% %
5327% S y n c A u t h e n t i c P i x e l s %
5328% %
5329% %
5330% %
5331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5332%
5333% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5334% The method returns MagickTrue if the pixel region is flushed, otherwise
5335% MagickFalse.
5336%
5337% The format of the SyncAuthenticPixels() method is:
5338%
5339% MagickBooleanType SyncAuthenticPixels(Image *image,
5340% ExceptionInfo *exception)
5341%
5342% A description of each parameter follows:
5343%
5344% o image: the image.
5345%
5346% o exception: return any errors or warnings in this structure.
5347%
5348*/
5349MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5350 ExceptionInfo *exception)
5351{
5352 CacheInfo
5353 *cache_info;
5354
cristy2036f5c2010-09-19 21:18:17 +00005355 const int
5356 id = GetOpenMPThreadId();
5357
cristy4c08aed2011-07-01 19:47:50 +00005358 MagickBooleanType
5359 status;
5360
cristy3ed852e2009-09-05 21:47:34 +00005361 assert(image != (Image *) NULL);
5362 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005363 assert(image->cache != (Cache) NULL);
5364 cache_info=(CacheInfo *) image->cache;
5365 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005366 if (cache_info->methods.sync_authentic_pixels_handler !=
5367 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005368 {
5369 status=cache_info->methods.sync_authentic_pixels_handler(image,
5370 exception);
5371 return(status);
5372 }
cristy2036f5c2010-09-19 21:18:17 +00005373 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005374 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5375 exception);
5376 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005377}
5378
5379/*
5380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5381% %
5382% %
5383% %
cristyd1dd6e42011-09-04 01:46:08 +00005384+ 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 +00005385% %
5386% %
5387% %
5388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5389%
5390% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5391% The method returns MagickTrue if the pixel region is flushed, otherwise
5392% MagickFalse.
5393%
5394% The format of the SyncImagePixelCache() method is:
5395%
5396% MagickBooleanType SyncImagePixelCache(Image *image,
5397% ExceptionInfo *exception)
5398%
5399% A description of each parameter follows:
5400%
5401% o image: the image.
5402%
5403% o exception: return any errors or warnings in this structure.
5404%
5405*/
cristyd1dd6e42011-09-04 01:46:08 +00005406MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005407 ExceptionInfo *exception)
5408{
5409 CacheInfo
5410 *cache_info;
5411
5412 assert(image != (Image *) NULL);
5413 assert(exception != (ExceptionInfo *) NULL);
5414 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5415 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5416}
5417
5418/*
5419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5420% %
5421% %
5422% %
cristy4c08aed2011-07-01 19:47:50 +00005423+ 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 +00005424% %
5425% %
5426% %
5427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5428%
cristy4c08aed2011-07-01 19:47:50 +00005429% WritePixelCacheMetacontent() writes the meta-content to the specified region
5430% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005431%
cristy4c08aed2011-07-01 19:47:50 +00005432% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005433%
cristy4c08aed2011-07-01 19:47:50 +00005434% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005435% NexusInfo *nexus_info,ExceptionInfo *exception)
5436%
5437% A description of each parameter follows:
5438%
5439% o cache_info: the pixel cache.
5440%
cristy4c08aed2011-07-01 19:47:50 +00005441% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005442%
5443% o exception: return any errors or warnings in this structure.
5444%
5445*/
cristy4c08aed2011-07-01 19:47:50 +00005446static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005447 NexusInfo *nexus_info,ExceptionInfo *exception)
5448{
5449 MagickOffsetType
5450 count,
5451 offset;
5452
5453 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005454 extent,
5455 length;
cristy3ed852e2009-09-05 21:47:34 +00005456
cristy4c08aed2011-07-01 19:47:50 +00005457 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005458 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005459
cristybb503372010-05-27 20:51:26 +00005460 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005461 y;
5462
cristybb503372010-05-27 20:51:26 +00005463 size_t
cristy3ed852e2009-09-05 21:47:34 +00005464 rows;
5465
cristy4c08aed2011-07-01 19:47:50 +00005466 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005467 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005468 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005469 return(MagickTrue);
5470 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5471 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005472 length=(MagickSizeType) nexus_info->region.width*
5473 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005474 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005475 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005476 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005477 switch (cache_info->type)
5478 {
5479 case MemoryCache:
5480 case MapCache:
5481 {
cristy4c08aed2011-07-01 19:47:50 +00005482 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005483 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005484
5485 /*
cristy4c08aed2011-07-01 19:47:50 +00005486 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005487 */
cristydd341db2010-03-04 19:06:38 +00005488 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005489 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005490 {
cristy48078b12010-09-23 17:11:01 +00005491 length=extent;
cristydd341db2010-03-04 19:06:38 +00005492 rows=1UL;
5493 }
cristy4c08aed2011-07-01 19:47:50 +00005494 q=(unsigned char *) cache_info->metacontent+offset*
5495 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005496 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005497 {
cristy8f036fe2010-09-18 02:02:00 +00005498 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005499 p+=nexus_info->region.width*cache_info->metacontent_extent;
5500 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005501 }
5502 break;
5503 }
5504 case DiskCache:
5505 {
5506 /*
cristy4c08aed2011-07-01 19:47:50 +00005507 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005508 */
5509 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5510 {
5511 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5512 cache_info->cache_filename);
5513 return(MagickFalse);
5514 }
cristydd341db2010-03-04 19:06:38 +00005515 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005516 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005517 {
cristy48078b12010-09-23 17:11:01 +00005518 length=extent;
cristydd341db2010-03-04 19:06:38 +00005519 rows=1UL;
5520 }
cristy48078b12010-09-23 17:11:01 +00005521 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005522 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005523 {
cristy48078b12010-09-23 17:11:01 +00005524 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005525 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005526 cache_info->metacontent_extent,length,(const unsigned char *) p);
5527 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005528 break;
cristy4c08aed2011-07-01 19:47:50 +00005529 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005530 offset+=cache_info->columns;
5531 }
cristybb503372010-05-27 20:51:26 +00005532 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005533 {
5534 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5535 cache_info->cache_filename);
5536 return(MagickFalse);
5537 }
5538 break;
5539 }
5540 default:
5541 break;
5542 }
5543 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005544 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005545 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005546 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005547 nexus_info->region.width,(double) nexus_info->region.height,(double)
5548 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005549 return(MagickTrue);
5550}
5551
5552/*
5553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5554% %
5555% %
5556% %
5557+ W r i t e C a c h e P i x e l s %
5558% %
5559% %
5560% %
5561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5562%
5563% WritePixelCachePixels() writes image pixels to the specified region of the
5564% pixel cache.
5565%
5566% The format of the WritePixelCachePixels() method is:
5567%
5568% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5569% NexusInfo *nexus_info,ExceptionInfo *exception)
5570%
5571% A description of each parameter follows:
5572%
5573% o cache_info: the pixel cache.
5574%
5575% o nexus_info: the cache nexus to write the pixels.
5576%
5577% o exception: return any errors or warnings in this structure.
5578%
5579*/
5580static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5581 NexusInfo *nexus_info,ExceptionInfo *exception)
5582{
5583 MagickOffsetType
5584 count,
5585 offset;
5586
5587 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005588 extent,
5589 length;
cristy3ed852e2009-09-05 21:47:34 +00005590
cristy4c08aed2011-07-01 19:47:50 +00005591 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005592 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005593
cristybb503372010-05-27 20:51:26 +00005594 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005595 y;
5596
cristybb503372010-05-27 20:51:26 +00005597 size_t
cristy3ed852e2009-09-05 21:47:34 +00005598 rows;
5599
cristy4c08aed2011-07-01 19:47:50 +00005600 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005601 return(MagickTrue);
5602 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5603 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005604 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005605 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005606 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005607 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005608 p=nexus_info->pixels;
5609 switch (cache_info->type)
5610 {
5611 case MemoryCache:
5612 case MapCache:
5613 {
cristy4c08aed2011-07-01 19:47:50 +00005614 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005615 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005616
5617 /*
5618 Write pixels to memory.
5619 */
cristydd341db2010-03-04 19:06:38 +00005620 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005621 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005622 {
cristy48078b12010-09-23 17:11:01 +00005623 length=extent;
cristydd341db2010-03-04 19:06:38 +00005624 rows=1UL;
5625 }
cristyed231572011-07-14 02:18:59 +00005626 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005627 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005628 {
cristy8f036fe2010-09-18 02:02:00 +00005629 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005630 p+=nexus_info->region.width*cache_info->number_channels;
5631 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005632 }
5633 break;
5634 }
5635 case DiskCache:
5636 {
5637 /*
5638 Write pixels to disk.
5639 */
5640 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5641 {
5642 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5643 cache_info->cache_filename);
5644 return(MagickFalse);
5645 }
cristydd341db2010-03-04 19:06:38 +00005646 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005647 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005648 {
cristy48078b12010-09-23 17:11:01 +00005649 length=extent;
cristydd341db2010-03-04 19:06:38 +00005650 rows=1UL;
5651 }
cristybb503372010-05-27 20:51:26 +00005652 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005653 {
5654 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005655 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005656 p);
5657 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005658 break;
cristyed231572011-07-14 02:18:59 +00005659 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005660 offset+=cache_info->columns;
5661 }
cristybb503372010-05-27 20:51:26 +00005662 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005663 {
5664 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5665 cache_info->cache_filename);
5666 return(MagickFalse);
5667 }
5668 break;
5669 }
5670 default:
5671 break;
5672 }
5673 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005674 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005675 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005676 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005677 nexus_info->region.width,(double) nexus_info->region.height,(double)
5678 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005679 return(MagickTrue);
5680}