blob: 50dd77b1c4bdd14e44b93a2b3da40e7598eb0aa9 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000069#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000070#if defined(MAGICKCORE_ZLIB_DELEGATE)
71#include "zlib.h"
72#endif
73
74/*
cristy30097232010-07-01 02:16:30 +000075 Define declarations.
76*/
77#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78
79/*
cristy3ed852e2009-09-05 21:47:34 +000080 Typedef declarations.
81*/
82typedef struct _MagickModulo
83{
cristybb503372010-05-27 20:51:26 +000084 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000085 quotient,
86 remainder;
87} MagickModulo;
88
89struct _NexusInfo
90{
91 MagickBooleanType
92 mapped;
93
94 RectangleInfo
95 region;
96
97 MagickSizeType
98 length;
99
cristy4c08aed2011-07-01 19:47:50 +0000100 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000101 *cache,
102 *pixels;
103
cristy4c08aed2011-07-01 19:47:50 +0000104 void
105 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000106
cristybb503372010-05-27 20:51:26 +0000107 size_t
cristy3ed852e2009-09-05 21:47:34 +0000108 signature;
109};
110
111/*
112 Forward declarations.
113*/
114#if defined(__cplusplus) || defined(c_plusplus)
115extern "C" {
116#endif
117
cristy4c08aed2011-07-01 19:47:50 +0000118static const Quantum
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
cristy4c08aed2011-07-01 19:47:50 +0000123static const void
124 *GetVirtualMetacontentFromCache(const Image *);
125
cristy3ed852e2009-09-05 21:47:34 +0000126static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000128 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
137
cristy4c08aed2011-07-01 19:47:50 +0000138static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000144 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146#if defined(__cplusplus) || defined(c_plusplus)
147}
148#endif
149
150/*
151 Global declarations.
152*/
153static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
155
156static SemaphoreInfo
157 *cache_semaphore = (SemaphoreInfo *) NULL;
158
159static SplayTreeInfo
160 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000161
162/*
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164% %
165% %
166% %
167+ A c q u i r e P i x e l C a c h e %
168% %
169% %
170% %
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%
173% AcquirePixelCache() acquires a pixel cache.
174%
175% The format of the AcquirePixelCache() method is:
176%
cristybb503372010-05-27 20:51:26 +0000177% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178%
179% A description of each parameter follows:
180%
181% o number_threads: the number of nexus threads.
182%
183*/
cristya6577ff2011-09-02 19:54:26 +0000184MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000185{
186 CacheInfo
187 *cache_info;
188
cristya64b85d2011-09-14 01:02:31 +0000189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000194 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristya6577ff2011-09-02 19:54:26 +0000250MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristya64b85d2011-09-14 01:02:31 +0000258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
cristy6a924af2010-09-23 14:02:54 +0000264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
cristyd1dd6e42011-09-04 01:46:08 +0000301MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
cristy5ff4eaf2011-09-03 01:38:02 +0000339MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
cristy5ff4eaf2011-09-03 01:38:02 +0000363MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000387% mask. It returns MagickTrue if the pixel region is clipped, otherwise
388% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
cristy4c08aed2011-07-01 19:47:50 +0000417 register const Quantum
418 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristy4c08aed2011-07-01 19:47:50 +0000421 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristye076a6e2010-08-15 19:59:43 +0000424 register ssize_t
425 i;
426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
428 Apply clip mask.
429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000434 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000445 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000451 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000452 {
cristy4c08aed2011-07-01 19:47:50 +0000453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000454 break;
cristy4c08aed2011-07-01 19:47:50 +0000455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000456 {
cristy4c08aed2011-07-01 19:47:50 +0000457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000463 }
cristyed231572011-07-14 02:18:59 +0000464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000467 }
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000470 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000471 return(MagickFalse);
472 return(MagickTrue);
473}
474
475/*
476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477% %
478% %
479% %
480+ C l o n e P i x e l C a c h e %
481% %
482% %
483% %
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485%
486% ClonePixelCache() clones a pixel cache.
487%
488% The format of the ClonePixelCache() method is:
489%
490% Cache ClonePixelCache(const Cache cache)
491%
492% A description of each parameter follows:
493%
494% o cache: the pixel cache.
495%
496*/
cristya6577ff2011-09-02 19:54:26 +0000497MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000498{
499 CacheInfo
500 *clone_info;
501
502 const CacheInfo
503 *cache_info;
504
cristy9f027d12011-09-21 01:17:17 +0000505 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
516}
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520% %
521% %
522% %
cristy60c44a82009-10-07 00:58:49 +0000523+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000524% %
525% %
526% %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528% ClonePixelCachePixels() clones the source pixel cache to the destination
529% cache.
530%
531% The format of the ClonePixelCachePixels() method is:
532%
533% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534% CacheInfo *source_info,ExceptionInfo *exception)
535%
536% A description of each parameter follows:
537%
538% o cache_info: the pixel cache.
539%
540% o source_info: the source pixel cache.
541%
542% o exception: return any errors or warnings in this structure.
543%
544*/
545
546static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
547{
548 int
549 status;
550
cristy5ee247a2010-02-12 15:42:34 +0000551 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000552 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000553 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000554 {
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
558 }
cristyf84a1932010-01-03 18:00:18 +0000559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000560 return(status == -1 ? MagickFalse : MagickTrue);
561}
562
563static void LimitPixelCacheDescriptors(void)
564{
565 register CacheInfo
566 *p,
567 *q;
568
569 /*
570 Limit # of open file descriptors.
571 */
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
573 return;
cristyf84a1932010-01-03 18:00:18 +0000574 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 if (cache_resources == (SplayTreeInfo *) NULL)
576 {
cristyf84a1932010-01-03 18:00:18 +0000577 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 return;
579 }
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
583 {
584 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000585 break;
cristy3ed852e2009-09-05 21:47:34 +0000586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587 }
588 for (q=p; p != (CacheInfo *) NULL; )
589 {
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000592 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
594 }
595 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000596 {
597 /*
598 Close least recently used cache.
599 */
600 (void) close(q->file);
601 q->file=(-1);
602 }
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604}
605
606static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
608{
609 if (x > y)
610 return(x);
611 return(y);
612}
613
614static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
616{
617 if (x < y)
618 return(x);
619 return(y);
620}
621
622static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
623 const MapMode mode)
624{
625 int
626 file;
627
628 /*
629 Open pixel cache on disk.
630 */
cristyf84a1932010-01-03 18:00:18 +0000631 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000632 if (cache_info->file != -1)
633 {
cristyf84a1932010-01-03 18:00:18 +0000634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 return(MagickTrue); /* cache already open */
636 }
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
640 else
641 switch (mode)
642 {
643 case ReadMode:
644 {
cristy18c6c272011-09-23 14:40:37 +0000645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 case WriteMode:
649 {
cristy18c6c272011-09-23 14:40:37 +0000650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000652 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case IOMode:
657 default:
658 {
cristy18c6c272011-09-23 14:40:37 +0000659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000660 O_EXCL,S_MODE);
661 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
664 }
665 }
666 if (file == -1)
667 {
cristyf84a1932010-01-03 18:00:18 +0000668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000669 return(MagickFalse);
670 }
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000673 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000674 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000675 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000676 return(MagickTrue);
677}
678
679static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
680 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000681 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000682{
683 register MagickOffsetType
684 i;
685
686 ssize_t
687 count;
688
cristy08a88202010-03-04 19:18:05 +0000689 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000690#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000691 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000692 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000693 {
cristyf84a1932010-01-03 18:00:18 +0000694 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000695 return((MagickOffsetType) -1);
696 }
697#endif
698 count=0;
699 for (i=0; i < (MagickOffsetType) length; i+=count)
700 {
701#if !defined(MAGICKCORE_HAVE_PREAD)
702 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
703 (MagickSizeType) SSIZE_MAX));
704#else
705 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000706 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000707#endif
708 if (count > 0)
709 continue;
710 count=0;
711 if (errno != EINTR)
712 {
713 i=(-1);
714 break;
715 }
716 }
717#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000718 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000719#endif
720 return(i);
721}
722
723static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
724 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000725 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000726{
727 register MagickOffsetType
728 i;
729
730 ssize_t
731 count;
732
cristy08a88202010-03-04 19:18:05 +0000733 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000734#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000735 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000736 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000737 {
cristyf84a1932010-01-03 18:00:18 +0000738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 return((MagickOffsetType) -1);
740 }
741#endif
742 count=0;
743 for (i=0; i < (MagickOffsetType) length; i+=count)
744 {
745#if !defined(MAGICKCORE_HAVE_PWRITE)
746 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
747 (MagickSizeType) SSIZE_MAX));
748#else
749 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000750 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000751#endif
752 if (count > 0)
753 continue;
754 count=0;
755 if (errno != EINTR)
756 {
757 i=(-1);
758 break;
759 }
760 }
761#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000762 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000763#endif
764 return(i);
765}
766
cristy4c08aed2011-07-01 19:47:50 +0000767static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000768 CacheInfo *cache_info,ExceptionInfo *exception)
769{
770 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000771 count;
cristy3ed852e2009-09-05 21:47:34 +0000772
cristy4c08aed2011-07-01 19:47:50 +0000773 register MagickOffsetType
774 i;
cristye076a6e2010-08-15 19:59:43 +0000775
cristybb503372010-05-27 20:51:26 +0000776 size_t
cristy4c08aed2011-07-01 19:47:50 +0000777 length;
cristy3ed852e2009-09-05 21:47:34 +0000778
cristy4c08aed2011-07-01 19:47:50 +0000779 unsigned char
780 *blob;
781
782 /*
783 Clone pixel cache (both caches on disk).
784 */
cristy3ed852e2009-09-05 21:47:34 +0000785 if (cache_info->debug != MagickFalse)
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000787 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000788 sizeof(*blob));
789 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000790 {
cristy4c08aed2011-07-01 19:47:50 +0000791 (void) ThrowMagickException(exception,GetMagickModule(),
792 ResourceLimitError,"MemoryAllocationFailed","`%s'",
793 cache_info->filename);
794 return(MagickFalse);
795 }
cristy3dedf062011-07-02 14:07:40 +0000796 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000797 {
798 blob=(unsigned char *) RelinquishMagickMemory(blob);
799 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
800 cache_info->cache_filename);
801 return(MagickFalse);
802 }
cristy3dedf062011-07-02 14:07:40 +0000803 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000804 {
805 (void) ClosePixelCacheOnDisk(cache_info);
806 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000807 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
808 clone_info->cache_filename);
809 return(MagickFalse);
810 }
cristy4c08aed2011-07-01 19:47:50 +0000811 count=0;
812 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000813 {
cristy4c08aed2011-07-01 19:47:50 +0000814 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
815 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
816 blob);
817 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000818 {
cristy4c08aed2011-07-01 19:47:50 +0000819 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
820 cache_info->cache_filename);
821 break;
cristy3ed852e2009-09-05 21:47:34 +0000822 }
cristy4c08aed2011-07-01 19:47:50 +0000823 length=(size_t) count;
824 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
825 if ((MagickSizeType) count != length)
826 {
827 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
828 clone_info->cache_filename);
829 break;
830 }
831 }
832 (void) ClosePixelCacheOnDisk(clone_info);
833 (void) ClosePixelCacheOnDisk(cache_info);
834 blob=(unsigned char *) RelinquishMagickMemory(blob);
835 if (i < (MagickOffsetType) cache_info->length)
836 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000837 return(MagickTrue);
838}
839
cristyfd24a062012-01-02 14:46:34 +0000840static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000841 CacheInfo *cache_info,ExceptionInfo *exception)
842{
843 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000844 count;
cristy3ed852e2009-09-05 21:47:34 +0000845
cristy4c08aed2011-07-01 19:47:50 +0000846 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000847 {
cristy3ed852e2009-09-05 21:47:34 +0000848 /*
cristy4c08aed2011-07-01 19:47:50 +0000849 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000850 */
cristy4c08aed2011-07-01 19:47:50 +0000851 if (cache_info->debug != MagickFalse)
852 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
853 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
854 cache_info->length);
855 return(MagickTrue);
856 }
857 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
858 {
859 /*
860 Clone pixel cache (one cache on disk, one in memory).
861 */
862 if (cache_info->debug != MagickFalse)
863 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
864 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
cristy4c08aed2011-07-01 19:47:50 +0000866 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000867 cache_info->cache_filename);
868 return(MagickFalse);
869 }
cristy4c08aed2011-07-01 19:47:50 +0000870 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
871 cache_info->length,(unsigned char *) clone_info->pixels);
872 (void) ClosePixelCacheOnDisk(cache_info);
873 if ((MagickSizeType) count != cache_info->length)
874 {
875 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
876 cache_info->cache_filename);
877 return(MagickFalse);
878 }
879 return(MagickTrue);
880 }
881 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
882 {
883 /*
884 Clone pixel cache (one cache on disk, one in memory).
885 */
886 if (clone_info->debug != MagickFalse)
887 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
888 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
889 {
890 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
891 clone_info->cache_filename);
892 return(MagickFalse);
893 }
894 count=WritePixelCacheRegion(clone_info,clone_info->offset,
895 clone_info->length,(unsigned char *) cache_info->pixels);
896 (void) ClosePixelCacheOnDisk(clone_info);
897 if ((MagickSizeType) count != clone_info->length)
898 {
899 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
900 clone_info->cache_filename);
901 return(MagickFalse);
902 }
903 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000904 }
905 /*
cristy4c08aed2011-07-01 19:47:50 +0000906 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000907 */
cristy4c08aed2011-07-01 19:47:50 +0000908 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000909}
910
cristyfd24a062012-01-02 14:46:34 +0000911static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000912 CacheInfo *cache_info,ExceptionInfo *exception)
913{
cristy4c08aed2011-07-01 19:47:50 +0000914 MagickBooleanType
915 status;
cristy3ed852e2009-09-05 21:47:34 +0000916
cristy4c08aed2011-07-01 19:47:50 +0000917 MagickOffsetType
918 cache_offset,
919 clone_offset,
920 count;
921
922 register ssize_t
923 x;
924
cristyfd24a062012-01-02 14:46:34 +0000925 register unsigned char
926 *p;
927
cristy4c08aed2011-07-01 19:47:50 +0000928 size_t
cristy3ed852e2009-09-05 21:47:34 +0000929 length;
930
cristy4c08aed2011-07-01 19:47:50 +0000931 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000932 y;
933
cristy4c08aed2011-07-01 19:47:50 +0000934 unsigned char
935 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000936
cristy4c08aed2011-07-01 19:47:50 +0000937 /*
938 Clone pixel cache (unoptimized).
939 */
cristy3ed852e2009-09-05 21:47:34 +0000940 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000941 {
cristy4c08aed2011-07-01 19:47:50 +0000942 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
943 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
944 else
945 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
947 else
948 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
949 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
950 else
951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
952 }
cristyed231572011-07-14 02:18:59 +0000953 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
954 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000955 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000956 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000957 if (blob == (unsigned char *) NULL)
958 {
959 (void) ThrowMagickException(exception,GetMagickModule(),
960 ResourceLimitError,"MemoryAllocationFailed","`%s'",
961 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000962 return(MagickFalse);
963 }
cristy4c08aed2011-07-01 19:47:50 +0000964 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
965 cache_offset=0;
966 clone_offset=0;
967 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000968 {
cristy4c08aed2011-07-01 19:47:50 +0000969 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000970 {
cristy4c08aed2011-07-01 19:47:50 +0000971 blob=(unsigned char *) RelinquishMagickMemory(blob);
972 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000973 cache_info->cache_filename);
974 return(MagickFalse);
975 }
cristy4c08aed2011-07-01 19:47:50 +0000976 cache_offset=cache_info->offset;
977 }
978 if (clone_info->type == DiskCache)
979 {
cristy3dedf062011-07-02 14:07:40 +0000980 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000981 {
cristy4c08aed2011-07-01 19:47:50 +0000982 blob=(unsigned char *) RelinquishMagickMemory(blob);
983 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
984 clone_info->cache_filename);
985 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000986 }
cristy4c08aed2011-07-01 19:47:50 +0000987 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000988 }
989 /*
cristy4c08aed2011-07-01 19:47:50 +0000990 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000991 */
cristy4c08aed2011-07-01 19:47:50 +0000992 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000993 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000994 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000995 {
cristy4c08aed2011-07-01 19:47:50 +0000996 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000997 {
cristy9e0719b2011-12-29 03:45:45 +0000998 register ssize_t
999 i;
1000
cristy3ed852e2009-09-05 21:47:34 +00001001 /*
cristy4c08aed2011-07-01 19:47:50 +00001002 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001003 */
cristyed231572011-07-14 02:18:59 +00001004 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001005 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001006 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +00001007 else
1008 {
cristyfd24a062012-01-02 14:46:34 +00001009 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001010 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001011 {
cristy4c08aed2011-07-01 19:47:50 +00001012 status=MagickFalse;
1013 break;
cristy3ed852e2009-09-05 21:47:34 +00001014 }
1015 }
cristy4c08aed2011-07-01 19:47:50 +00001016 cache_offset+=length;
1017 if ((y < (ssize_t) clone_info->rows) &&
1018 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001019 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001020 {
cristy9e0719b2011-12-29 03:45:45 +00001021 PixelChannel
1022 channel;
1023
1024 PixelTrait
1025 traits;
1026
1027 ssize_t
1028 offset;
1029
cristy4c08aed2011-07-01 19:47:50 +00001030 /*
cristy3b8fe922011-12-29 18:56:23 +00001031 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001032 */
cristy9e0719b2011-12-29 03:45:45 +00001033 channel=clone_info->channel_map[i].channel;
1034 traits=cache_info->channel_map[channel].traits;
1035 if (traits == UndefinedPixelTrait)
1036 {
cristy0f4425e2011-12-31 20:33:02 +00001037 clone_offset+=sizeof(Quantum);
1038 continue;
cristy9e0719b2011-12-29 03:45:45 +00001039 }
cristy0f4425e2011-12-31 20:33:02 +00001040 offset=cache_info->channel_map[channel].offset;
1041 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001042 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
1043 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +00001044 else
1045 {
cristy0f4425e2011-12-31 20:33:02 +00001046 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +00001047 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +00001048 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +00001049 {
cristy0f4425e2011-12-31 20:33:02 +00001050 status=MagickFalse;
1051 break;
cristy4c08aed2011-07-01 19:47:50 +00001052 }
1053 }
cristy9e0719b2011-12-29 03:45:45 +00001054 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001055 }
1056 }
cristyed231572011-07-14 02:18:59 +00001057 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001058 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1059 for ( ; x < (ssize_t) clone_info->columns; x++)
1060 {
1061 /*
cristy9e0719b2011-12-29 03:45:45 +00001062 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001063 */
1064 if (clone_info->type != DiskCache)
1065 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1066 length);
1067 else
1068 {
1069 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1070 if ((MagickSizeType) count != length)
1071 {
1072 status=MagickFalse;
1073 break;
1074 }
1075 }
1076 clone_offset+=length;
1077 }
1078 }
cristyed231572011-07-14 02:18:59 +00001079 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001080 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1081 for ( ; y < (ssize_t) clone_info->rows; y++)
1082 {
1083 /*
cristy9e0719b2011-12-29 03:45:45 +00001084 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001085 */
1086 for (x=0; x < (ssize_t) clone_info->columns; x++)
1087 {
1088 if (clone_info->type != DiskCache)
1089 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1090 length);
1091 else
1092 {
1093 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1094 if ((MagickSizeType) count != length)
1095 {
1096 status=MagickFalse;
1097 break;
1098 }
1099 }
1100 clone_offset+=length;
1101 }
1102 }
cristy9e0719b2011-12-29 03:45:45 +00001103 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001104 (clone_info->metacontent_extent != 0))
1105 {
1106 /*
1107 Clone metacontent.
1108 */
1109 for (y=0; y < (ssize_t) cache_info->rows; y++)
1110 {
1111 for (x=0; x < (ssize_t) cache_info->columns; x++)
1112 {
1113 /*
1114 Read a set of metacontent.
1115 */
1116 length=cache_info->metacontent_extent;
1117 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +00001118 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +00001119 else
1120 {
cristyfd24a062012-01-02 14:46:34 +00001121 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001122 if ((MagickSizeType) count != length)
1123 {
1124 status=MagickFalse;
1125 break;
1126 }
1127 }
1128 cache_offset+=length;
1129 if ((y < (ssize_t) clone_info->rows) &&
1130 (x < (ssize_t) clone_info->columns))
1131 {
1132 /*
1133 Write a set of metacontent.
1134 */
1135 length=clone_info->metacontent_extent;
1136 if (clone_info->type != DiskCache)
1137 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +00001138 p,length);
cristy4c08aed2011-07-01 19:47:50 +00001139 else
1140 {
cristyfd24a062012-01-02 14:46:34 +00001141 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +00001142 if ((MagickSizeType) count != length)
1143 {
1144 status=MagickFalse;
1145 break;
1146 }
1147 }
1148 clone_offset+=length;
1149 }
1150 }
1151 length=clone_info->metacontent_extent;
1152 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1153 for ( ; x < (ssize_t) clone_info->columns; x++)
1154 {
1155 /*
cristy9e0719b2011-12-29 03:45:45 +00001156 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001157 */
1158 if (clone_info->type != DiskCache)
1159 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1160 blob,length);
1161 else
1162 {
cristy208b1002011-08-07 18:51:50 +00001163 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001164 if ((MagickSizeType) count != length)
1165 {
1166 status=MagickFalse;
1167 break;
1168 }
1169 }
1170 clone_offset+=length;
1171 }
1172 }
1173 length=clone_info->metacontent_extent;
1174 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1175 for ( ; y < (ssize_t) clone_info->rows; y++)
1176 {
1177 /*
cristy9e0719b2011-12-29 03:45:45 +00001178 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001179 */
1180 for (x=0; x < (ssize_t) clone_info->columns; x++)
1181 {
1182 if (clone_info->type != DiskCache)
1183 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1184 blob,length);
1185 else
1186 {
1187 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1188 if ((MagickSizeType) count != length)
1189 {
1190 status=MagickFalse;
1191 break;
1192 }
1193 }
1194 clone_offset+=length;
1195 }
1196 }
1197 }
1198 if (clone_info->type == DiskCache)
1199 (void) ClosePixelCacheOnDisk(clone_info);
1200 if (cache_info->type == DiskCache)
1201 (void) ClosePixelCacheOnDisk(cache_info);
1202 blob=(unsigned char *) RelinquishMagickMemory(blob);
1203 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001204}
1205
1206static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1207 CacheInfo *cache_info,ExceptionInfo *exception)
1208{
cristy3dfccb22011-12-28 21:47:20 +00001209 PixelChannelMap
1210 *p,
1211 *q;
1212
cristy5a7fbfb2010-11-06 16:10:59 +00001213 if (cache_info->type == PingCache)
1214 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001215 p=cache_info->channel_map;
1216 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001217 if ((cache_info->columns == clone_info->columns) &&
1218 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001219 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001220 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001221 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001222 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1223 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001224}
1225
1226/*
1227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1228% %
1229% %
1230% %
1231+ C l o n e P i x e l C a c h e M e t h o d s %
1232% %
1233% %
1234% %
1235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1236%
1237% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1238% another.
1239%
1240% The format of the ClonePixelCacheMethods() method is:
1241%
1242% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1243%
1244% A description of each parameter follows:
1245%
1246% o clone: Specifies a pointer to a Cache structure.
1247%
1248% o cache: the pixel cache.
1249%
1250*/
cristya6577ff2011-09-02 19:54:26 +00001251MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001252{
1253 CacheInfo
1254 *cache_info,
1255 *source_info;
1256
1257 assert(clone != (Cache) NULL);
1258 source_info=(CacheInfo *) clone;
1259 assert(source_info->signature == MagickSignature);
1260 if (source_info->debug != MagickFalse)
1261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1262 source_info->filename);
1263 assert(cache != (Cache) NULL);
1264 cache_info=(CacheInfo *) cache;
1265 assert(cache_info->signature == MagickSignature);
1266 source_info->methods=cache_info->methods;
1267}
1268
1269/*
1270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1271% %
1272% %
1273% %
1274+ D e s t r o y I m a g e P i x e l C a c h e %
1275% %
1276% %
1277% %
1278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1279%
1280% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1281%
1282% The format of the DestroyImagePixelCache() method is:
1283%
1284% void DestroyImagePixelCache(Image *image)
1285%
1286% A description of each parameter follows:
1287%
1288% o image: the image.
1289%
1290*/
1291static void DestroyImagePixelCache(Image *image)
1292{
1293 assert(image != (Image *) NULL);
1294 assert(image->signature == MagickSignature);
1295 if (image->debug != MagickFalse)
1296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1297 if (image->cache == (void *) NULL)
1298 return;
1299 image->cache=DestroyPixelCache(image->cache);
1300}
1301
1302/*
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304% %
1305% %
1306% %
1307+ D e s t r o y I m a g e P i x e l s %
1308% %
1309% %
1310% %
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312%
1313% DestroyImagePixels() deallocates memory associated with the pixel cache.
1314%
1315% The format of the DestroyImagePixels() method is:
1316%
1317% void DestroyImagePixels(Image *image)
1318%
1319% A description of each parameter follows:
1320%
1321% o image: the image.
1322%
1323*/
1324MagickExport void DestroyImagePixels(Image *image)
1325{
1326 CacheInfo
1327 *cache_info;
1328
1329 assert(image != (const Image *) NULL);
1330 assert(image->signature == MagickSignature);
1331 if (image->debug != MagickFalse)
1332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1333 assert(image->cache != (Cache) NULL);
1334 cache_info=(CacheInfo *) image->cache;
1335 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001336 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1337 {
1338 cache_info->methods.destroy_pixel_handler(image);
1339 return;
1340 }
cristy2036f5c2010-09-19 21:18:17 +00001341 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001342}
1343
1344/*
1345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346% %
1347% %
1348% %
1349+ D e s t r o y P i x e l C a c h e %
1350% %
1351% %
1352% %
1353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354%
1355% DestroyPixelCache() deallocates memory associated with the pixel cache.
1356%
1357% The format of the DestroyPixelCache() method is:
1358%
1359% Cache DestroyPixelCache(Cache cache)
1360%
1361% A description of each parameter follows:
1362%
1363% o cache: the pixel cache.
1364%
1365*/
1366
1367static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1368{
1369 switch (cache_info->type)
1370 {
1371 case MemoryCache:
1372 {
1373 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001374 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001375 cache_info->pixels);
1376 else
cristy4c08aed2011-07-01 19:47:50 +00001377 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001378 (size_t) cache_info->length);
1379 RelinquishMagickResource(MemoryResource,cache_info->length);
1380 break;
1381 }
1382 case MapCache:
1383 {
cristy4c08aed2011-07-01 19:47:50 +00001384 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001385 cache_info->length);
1386 RelinquishMagickResource(MapResource,cache_info->length);
1387 }
1388 case DiskCache:
1389 {
1390 if (cache_info->file != -1)
1391 (void) ClosePixelCacheOnDisk(cache_info);
1392 RelinquishMagickResource(DiskResource,cache_info->length);
1393 break;
1394 }
1395 default:
1396 break;
1397 }
1398 cache_info->type=UndefinedCache;
1399 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001400 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001401}
1402
cristya6577ff2011-09-02 19:54:26 +00001403MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001404{
1405 CacheInfo
1406 *cache_info;
1407
cristy3ed852e2009-09-05 21:47:34 +00001408 assert(cache != (Cache) NULL);
1409 cache_info=(CacheInfo *) cache;
1410 assert(cache_info->signature == MagickSignature);
1411 if (cache_info->debug != MagickFalse)
1412 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1413 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001414 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001415 cache_info->reference_count--;
1416 if (cache_info->reference_count != 0)
1417 {
cristyf84a1932010-01-03 18:00:18 +00001418 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001419 return((Cache) NULL);
1420 }
cristyf84a1932010-01-03 18:00:18 +00001421 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001422 if (cache_resources != (SplayTreeInfo *) NULL)
1423 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001424 if (cache_info->debug != MagickFalse)
1425 {
1426 char
1427 message[MaxTextExtent];
1428
cristyb51dff52011-05-19 16:55:47 +00001429 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001430 cache_info->filename);
1431 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1432 }
cristyc2e1bdd2009-09-10 23:43:34 +00001433 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1434 (cache_info->type != DiskCache)))
1435 RelinquishPixelCachePixels(cache_info);
1436 else
1437 {
1438 RelinquishPixelCachePixels(cache_info);
1439 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1440 }
cristy3ed852e2009-09-05 21:47:34 +00001441 *cache_info->cache_filename='\0';
1442 if (cache_info->nexus_info != (NexusInfo **) NULL)
1443 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1444 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001445 if (cache_info->random_info != (RandomInfo *) NULL)
1446 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001447 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1448 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1449 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1450 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001451 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001452 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001453 cache=(Cache) NULL;
1454 return(cache);
1455}
1456
1457/*
1458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459% %
1460% %
1461% %
1462+ D e s t r o y P i x e l C a c h e N e x u s %
1463% %
1464% %
1465% %
1466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467%
1468% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1469%
1470% The format of the DestroyPixelCacheNexus() method is:
1471%
1472% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001473% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001474%
1475% A description of each parameter follows:
1476%
1477% o nexus_info: the nexus to destroy.
1478%
1479% o number_threads: the number of nexus threads.
1480%
1481*/
1482
1483static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1484{
1485 if (nexus_info->mapped == MagickFalse)
1486 (void) RelinquishMagickMemory(nexus_info->cache);
1487 else
1488 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001489 nexus_info->cache=(Quantum *) NULL;
1490 nexus_info->pixels=(Quantum *) NULL;
1491 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001492 nexus_info->length=0;
1493 nexus_info->mapped=MagickFalse;
1494}
1495
cristya6577ff2011-09-02 19:54:26 +00001496MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001497 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001498{
cristybb503372010-05-27 20:51:26 +00001499 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001500 i;
1501
1502 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001503 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001504 {
cristy4c08aed2011-07-01 19:47:50 +00001505 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001506 RelinquishCacheNexusPixels(nexus_info[i]);
1507 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001508 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001509 }
cristyb41ee102010-10-04 16:46:15 +00001510 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001511 return(nexus_info);
1512}
1513
1514/*
1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1516% %
1517% %
1518% %
cristy4c08aed2011-07-01 19:47:50 +00001519% 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 +00001520% %
1521% %
1522% %
1523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1524%
cristy4c08aed2011-07-01 19:47:50 +00001525% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1526% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1527% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001528%
cristy4c08aed2011-07-01 19:47:50 +00001529% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001530%
cristy4c08aed2011-07-01 19:47:50 +00001531% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001532%
1533% A description of each parameter follows:
1534%
1535% o image: the image.
1536%
1537*/
cristy4c08aed2011-07-01 19:47:50 +00001538MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001539{
1540 CacheInfo
1541 *cache_info;
1542
cristy5c9e6f22010-09-17 17:31:01 +00001543 const int
1544 id = GetOpenMPThreadId();
1545
cristy4c08aed2011-07-01 19:47:50 +00001546 void
1547 *metacontent;
1548
cristye7cc7cf2010-09-21 13:26:47 +00001549 assert(image != (const Image *) NULL);
1550 assert(image->signature == MagickSignature);
1551 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001552 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001553 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001554 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1555 (GetAuthenticMetacontentFromHandler) NULL)
1556 {
1557 metacontent=cache_info->methods.
1558 get_authentic_metacontent_from_handler(image);
1559 return(metacontent);
1560 }
cristy6ebe97c2010-07-03 01:17:28 +00001561 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001562 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1563 cache_info->nexus_info[id]);
1564 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001565}
1566
1567/*
1568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1569% %
1570% %
1571% %
cristy4c08aed2011-07-01 19:47:50 +00001572+ 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 +00001573% %
1574% %
1575% %
1576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577%
cristy4c08aed2011-07-01 19:47:50 +00001578% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1579% with the last call to QueueAuthenticPixelsCache() or
1580% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001581%
cristy4c08aed2011-07-01 19:47:50 +00001582% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001583%
cristy4c08aed2011-07-01 19:47:50 +00001584% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001585%
1586% A description of each parameter follows:
1587%
1588% o image: the image.
1589%
1590*/
cristy4c08aed2011-07-01 19:47:50 +00001591static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001592{
1593 CacheInfo
1594 *cache_info;
1595
cristy2036f5c2010-09-19 21:18:17 +00001596 const int
1597 id = GetOpenMPThreadId();
1598
cristy4c08aed2011-07-01 19:47:50 +00001599 void
1600 *metacontent;
1601
cristy3ed852e2009-09-05 21:47:34 +00001602 assert(image != (const Image *) NULL);
1603 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001604 assert(image->cache != (Cache) NULL);
1605 cache_info=(CacheInfo *) image->cache;
1606 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001607 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001608 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1609 cache_info->nexus_info[id]);
1610 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001611}
1612
1613/*
1614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615% %
1616% %
1617% %
1618+ 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 %
1619% %
1620% %
1621% %
1622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623%
1624% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1625% disk pixel cache as defined by the geometry parameters. A pointer to the
1626% pixels is returned if the pixels are transferred, otherwise a NULL is
1627% returned.
1628%
1629% The format of the GetAuthenticPixelCacheNexus() method is:
1630%
cristy4c08aed2011-07-01 19:47:50 +00001631% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001632% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001633% NexusInfo *nexus_info,ExceptionInfo *exception)
1634%
1635% A description of each parameter follows:
1636%
1637% o image: the image.
1638%
1639% o x,y,columns,rows: These values define the perimeter of a region of
1640% pixels.
1641%
1642% o nexus_info: the cache nexus to return.
1643%
1644% o exception: return any errors or warnings in this structure.
1645%
1646*/
1647
cristy4c08aed2011-07-01 19:47:50 +00001648static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001649 NexusInfo *nexus_info)
1650{
cristy4c08aed2011-07-01 19:47:50 +00001651 MagickBooleanType
1652 status;
1653
cristy3ed852e2009-09-05 21:47:34 +00001654 MagickOffsetType
1655 offset;
1656
cristy73724512010-04-12 14:43:14 +00001657 if (cache_info->type == PingCache)
1658 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001659 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1660 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001661 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001662 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001663 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001664}
1665
cristya6577ff2011-09-02 19:54:26 +00001666MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001667 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001668 NexusInfo *nexus_info,ExceptionInfo *exception)
1669{
1670 CacheInfo
1671 *cache_info;
1672
cristy4c08aed2011-07-01 19:47:50 +00001673 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001674 *q;
cristy3ed852e2009-09-05 21:47:34 +00001675
1676 /*
1677 Transfer pixels from the cache.
1678 */
1679 assert(image != (Image *) NULL);
1680 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001681 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001682 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001683 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001684 cache_info=(CacheInfo *) image->cache;
1685 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001686 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001687 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001688 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001689 return((Quantum *) NULL);
1690 if (cache_info->metacontent_extent != 0)
1691 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1692 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001693 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001694}
1695
1696/*
1697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1698% %
1699% %
1700% %
1701+ 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 %
1702% %
1703% %
1704% %
1705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1706%
1707% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1708% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1709%
1710% The format of the GetAuthenticPixelsFromCache() method is:
1711%
cristy4c08aed2011-07-01 19:47:50 +00001712% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001713%
1714% A description of each parameter follows:
1715%
1716% o image: the image.
1717%
1718*/
cristy4c08aed2011-07-01 19:47:50 +00001719static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001720{
1721 CacheInfo
1722 *cache_info;
1723
cristy5c9e6f22010-09-17 17:31:01 +00001724 const int
1725 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001726
cristye7cc7cf2010-09-21 13:26:47 +00001727 assert(image != (const Image *) NULL);
1728 assert(image->signature == MagickSignature);
1729 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001730 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001731 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001732 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001733 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001734}
1735
1736/*
1737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1738% %
1739% %
1740% %
1741% G e t A u t h e n t i c P i x e l Q u e u e %
1742% %
1743% %
1744% %
1745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1746%
cristy4c08aed2011-07-01 19:47:50 +00001747% GetAuthenticPixelQueue() returns the authentic pixels associated
1748% corresponding with the last call to QueueAuthenticPixels() or
1749% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001750%
1751% The format of the GetAuthenticPixelQueue() method is:
1752%
cristy4c08aed2011-07-01 19:47:50 +00001753% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001754%
1755% A description of each parameter follows:
1756%
1757% o image: the image.
1758%
1759*/
cristy4c08aed2011-07-01 19:47:50 +00001760MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001761{
1762 CacheInfo
1763 *cache_info;
1764
cristy2036f5c2010-09-19 21:18:17 +00001765 const int
1766 id = GetOpenMPThreadId();
1767
cristy3ed852e2009-09-05 21:47:34 +00001768 assert(image != (const Image *) NULL);
1769 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001770 assert(image->cache != (Cache) NULL);
1771 cache_info=(CacheInfo *) image->cache;
1772 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001773 if (cache_info->methods.get_authentic_pixels_from_handler !=
1774 (GetAuthenticPixelsFromHandler) NULL)
1775 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001776 assert(id < (int) cache_info->number_threads);
1777 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001778}
1779
1780/*
1781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1782% %
1783% %
1784% %
1785% G e t A u t h e n t i c P i x e l s %
1786% %
1787% %
cristy4c08aed2011-07-01 19:47:50 +00001788% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001789%
1790% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001791% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001792% representing the region is returned, otherwise NULL is returned.
1793%
1794% The returned pointer may point to a temporary working copy of the pixels
1795% or it may point to the original pixels in memory. Performance is maximized
1796% if the selected region is part of one row, or one or more full rows, since
1797% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001798% if the image is in memory, or in a memory-mapped file. The returned pointer
1799% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001800%
1801% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001802% Quantum. If the image has corresponding metacontent,call
1803% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1804% meta-content corresponding to the region. Once the Quantum array has
1805% been updated, the changes must be saved back to the underlying image using
1806% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001807%
1808% The format of the GetAuthenticPixels() method is:
1809%
cristy4c08aed2011-07-01 19:47:50 +00001810% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001811% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001812% ExceptionInfo *exception)
1813%
1814% A description of each parameter follows:
1815%
1816% o image: the image.
1817%
1818% o x,y,columns,rows: These values define the perimeter of a region of
1819% pixels.
1820%
1821% o exception: return any errors or warnings in this structure.
1822%
1823*/
cristy4c08aed2011-07-01 19:47:50 +00001824MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001825 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001826 ExceptionInfo *exception)
1827{
1828 CacheInfo
1829 *cache_info;
1830
cristy2036f5c2010-09-19 21:18:17 +00001831 const int
1832 id = GetOpenMPThreadId();
1833
cristy4c08aed2011-07-01 19:47:50 +00001834 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001835 *q;
cristy4c08aed2011-07-01 19:47:50 +00001836
cristy3ed852e2009-09-05 21:47:34 +00001837 assert(image != (Image *) NULL);
1838 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001839 assert(image->cache != (Cache) NULL);
1840 cache_info=(CacheInfo *) image->cache;
1841 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001842 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001843 (GetAuthenticPixelsHandler) NULL)
1844 {
cristyacd2ed22011-08-30 01:44:23 +00001845 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1846 exception);
1847 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001848 }
cristy2036f5c2010-09-19 21:18:17 +00001849 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001850 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001851 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001852 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001853}
1854
1855/*
1856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1857% %
1858% %
1859% %
1860+ G e t A u t h e n t i c P i x e l s C a c h e %
1861% %
1862% %
1863% %
1864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1865%
1866% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1867% as defined by the geometry parameters. A pointer to the pixels is returned
1868% if the pixels are transferred, otherwise a NULL is returned.
1869%
1870% The format of the GetAuthenticPixelsCache() method is:
1871%
cristy4c08aed2011-07-01 19:47:50 +00001872% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001873% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001874% ExceptionInfo *exception)
1875%
1876% A description of each parameter follows:
1877%
1878% o image: the image.
1879%
1880% o x,y,columns,rows: These values define the perimeter of a region of
1881% pixels.
1882%
1883% o exception: return any errors or warnings in this structure.
1884%
1885*/
cristy4c08aed2011-07-01 19:47:50 +00001886static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001887 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001888 ExceptionInfo *exception)
1889{
1890 CacheInfo
1891 *cache_info;
1892
cristy5c9e6f22010-09-17 17:31:01 +00001893 const int
1894 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001895
cristy4c08aed2011-07-01 19:47:50 +00001896 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001897 *q;
cristy4c08aed2011-07-01 19:47:50 +00001898
cristye7cc7cf2010-09-21 13:26:47 +00001899 assert(image != (const Image *) NULL);
1900 assert(image->signature == MagickSignature);
1901 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001902 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001903 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001904 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001905 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001906 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001907 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001908 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001909 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001910}
1911
1912/*
1913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1914% %
1915% %
1916% %
1917+ G e t I m a g e E x t e n t %
1918% %
1919% %
1920% %
1921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1922%
cristy4c08aed2011-07-01 19:47:50 +00001923% GetImageExtent() returns the extent of the pixels associated corresponding
1924% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001925%
1926% The format of the GetImageExtent() method is:
1927%
1928% MagickSizeType GetImageExtent(const Image *image)
1929%
1930% A description of each parameter follows:
1931%
1932% o image: the image.
1933%
1934*/
1935MagickExport MagickSizeType GetImageExtent(const Image *image)
1936{
1937 CacheInfo
1938 *cache_info;
1939
cristy5c9e6f22010-09-17 17:31:01 +00001940 const int
1941 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001942
cristy3ed852e2009-09-05 21:47:34 +00001943 assert(image != (Image *) NULL);
1944 assert(image->signature == MagickSignature);
1945 if (image->debug != MagickFalse)
1946 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1947 assert(image->cache != (Cache) NULL);
1948 cache_info=(CacheInfo *) image->cache;
1949 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001950 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001951 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001952}
1953
1954/*
1955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1956% %
1957% %
1958% %
1959+ G e t I m a g e P i x e l C a c h e %
1960% %
1961% %
1962% %
1963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964%
1965% GetImagePixelCache() ensures that there is only a single reference to the
1966% pixel cache to be modified, updating the provided cache pointer to point to
1967% a clone of the original pixel cache if necessary.
1968%
1969% The format of the GetImagePixelCache method is:
1970%
1971% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1972% ExceptionInfo *exception)
1973%
1974% A description of each parameter follows:
1975%
1976% o image: the image.
1977%
1978% o clone: any value other than MagickFalse clones the cache pixels.
1979%
1980% o exception: return any errors or warnings in this structure.
1981%
1982*/
cristyaf894d72011-08-06 23:03:10 +00001983
cristy3ed852e2009-09-05 21:47:34 +00001984static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1985{
1986 CacheInfo
1987 *cache_info;
1988
cristy9e0719b2011-12-29 03:45:45 +00001989 PixelChannelMap
1990 *p,
1991 *q;
1992
cristy3ed852e2009-09-05 21:47:34 +00001993 /*
1994 Does the image match the pixel cache morphology?
1995 */
1996 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001997 p=image->channel_map;
1998 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001999 if ((image->storage_class != cache_info->storage_class) ||
2000 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002001 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002002 (image->columns != cache_info->columns) ||
2003 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002004 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002005 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002006 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002007 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2008 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2009 return(MagickFalse);
2010 return(MagickTrue);
2011}
2012
cristycd01fae2011-08-06 23:52:42 +00002013static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2014 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002015{
2016 CacheInfo
2017 *cache_info;
2018
cristy3ed852e2009-09-05 21:47:34 +00002019 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002020 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002021 status;
2022
cristy50a10922010-02-15 18:35:25 +00002023 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002024 cpu_throttle = 0,
2025 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002026 time_limit = 0;
2027
cristy1ea34962010-07-01 19:49:21 +00002028 static time_t
cristy208b1002011-08-07 18:51:50 +00002029 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002030
cristyc4f9f132010-03-04 18:50:01 +00002031 status=MagickTrue;
2032 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002033 if (cpu_throttle == 0)
2034 {
2035 char
2036 *limit;
2037
2038 /*
2039 Set CPU throttle in milleseconds.
2040 */
2041 cpu_throttle=MagickResourceInfinity;
2042 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2043 if (limit == (char *) NULL)
2044 limit=GetPolicyValue("throttle");
2045 if (limit != (char *) NULL)
2046 {
2047 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2048 limit=DestroyString(limit);
2049 }
2050 }
2051 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2052 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002053 if (time_limit == 0)
2054 {
cristy6ebe97c2010-07-03 01:17:28 +00002055 /*
2056 Set the exire time in seconds.
2057 */
cristy1ea34962010-07-01 19:49:21 +00002058 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002059 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002060 }
2061 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002062 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002063 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002064 assert(image->cache != (Cache) NULL);
2065 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002066 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002067 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002068 {
cristyceb55ee2010-11-06 16:05:49 +00002069 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002070 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002071 {
cristyceb55ee2010-11-06 16:05:49 +00002072 Image
2073 clone_image;
2074
2075 CacheInfo
2076 *clone_info;
2077
2078 /*
2079 Clone pixel cache.
2080 */
2081 clone_image=(*image);
2082 clone_image.semaphore=AllocateSemaphoreInfo();
2083 clone_image.reference_count=1;
2084 clone_image.cache=ClonePixelCache(cache_info);
2085 clone_info=(CacheInfo *) clone_image.cache;
2086 status=OpenPixelCache(&clone_image,IOMode,exception);
2087 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002088 {
cristy5a7fbfb2010-11-06 16:10:59 +00002089 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002090 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002091 if (status != MagickFalse)
2092 {
cristy979bf772011-08-08 00:04:15 +00002093 if (cache_info->mode == ReadMode)
2094 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002095 destroy=MagickTrue;
2096 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002097 }
2098 }
cristyceb55ee2010-11-06 16:05:49 +00002099 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002100 }
cristyceb55ee2010-11-06 16:05:49 +00002101 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002102 }
cristy4320e0e2009-09-10 15:00:08 +00002103 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002104 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002105 if (status != MagickFalse)
2106 {
2107 /*
2108 Ensure the image matches the pixel cache morphology.
2109 */
2110 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002111 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002112 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2113 status=OpenPixelCache(image,IOMode,exception);
2114 }
cristyf84a1932010-01-03 18:00:18 +00002115 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002116 if (status == MagickFalse)
2117 return((Cache) NULL);
2118 return(image->cache);
2119}
2120
2121/*
2122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123% %
2124% %
2125% %
2126% G e t O n e A u t h e n t i c P i x e l %
2127% %
2128% %
2129% %
2130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2131%
2132% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2133% location. The image background color is returned if an error occurs.
2134%
2135% The format of the GetOneAuthenticPixel() method is:
2136%
cristybb503372010-05-27 20:51:26 +00002137% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002138% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002139%
2140% A description of each parameter follows:
2141%
2142% o image: the image.
2143%
2144% o x,y: These values define the location of the pixel to return.
2145%
2146% o pixel: return a pixel at the specified (x,y) location.
2147%
2148% o exception: return any errors or warnings in this structure.
2149%
2150*/
cristyacbbb7c2010-06-30 18:56:48 +00002151MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002152 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002153{
2154 CacheInfo
2155 *cache_info;
2156
cristy4c08aed2011-07-01 19:47:50 +00002157 register Quantum
2158 *q;
cristy2036f5c2010-09-19 21:18:17 +00002159
cristy2ed42f62011-10-02 19:49:57 +00002160 register ssize_t
2161 i;
2162
cristy3ed852e2009-09-05 21:47:34 +00002163 assert(image != (Image *) NULL);
2164 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002165 assert(image->cache != (Cache) NULL);
2166 cache_info=(CacheInfo *) image->cache;
2167 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002168 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002169 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2170 (GetOneAuthenticPixelFromHandler) NULL)
2171 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2172 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002173 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2174 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002175 {
cristy9e0719b2011-12-29 03:45:45 +00002176 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2177 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2178 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2179 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2180 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002181 return(MagickFalse);
2182 }
2183 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2184 {
2185 PixelChannel
2186 channel;
2187
cristye2a912b2011-12-05 20:02:07 +00002188 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002189 pixel[channel]=q[i];
2190 }
cristy2036f5c2010-09-19 21:18:17 +00002191 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002192}
2193
2194/*
2195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2196% %
2197% %
2198% %
2199+ 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 %
2200% %
2201% %
2202% %
2203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204%
2205% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2206% location. The image background color is returned if an error occurs.
2207%
2208% The format of the GetOneAuthenticPixelFromCache() method is:
2209%
2210% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002211% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002212% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002213%
2214% A description of each parameter follows:
2215%
2216% o image: the image.
2217%
2218% o x,y: These values define the location of the pixel to return.
2219%
2220% o pixel: return a pixel at the specified (x,y) location.
2221%
2222% o exception: return any errors or warnings in this structure.
2223%
2224*/
2225static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002226 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002227{
cristy098f78c2010-09-23 17:28:44 +00002228 CacheInfo
2229 *cache_info;
2230
2231 const int
2232 id = GetOpenMPThreadId();
2233
cristy4c08aed2011-07-01 19:47:50 +00002234 register Quantum
2235 *q;
cristy3ed852e2009-09-05 21:47:34 +00002236
cristy2ed42f62011-10-02 19:49:57 +00002237 register ssize_t
2238 i;
2239
cristy0158a4b2010-09-20 13:59:45 +00002240 assert(image != (const Image *) NULL);
2241 assert(image->signature == MagickSignature);
2242 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002243 cache_info=(CacheInfo *) image->cache;
2244 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002245 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002246 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002247 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2248 exception);
2249 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002250 {
cristy9e0719b2011-12-29 03:45:45 +00002251 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2252 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2253 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2254 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2255 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002256 return(MagickFalse);
2257 }
2258 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2259 {
2260 PixelChannel
2261 channel;
2262
cristye2a912b2011-12-05 20:02:07 +00002263 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002264 pixel[channel]=q[i];
2265 }
cristy3ed852e2009-09-05 21:47:34 +00002266 return(MagickTrue);
2267}
2268
2269/*
2270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2271% %
2272% %
2273% %
cristy3ed852e2009-09-05 21:47:34 +00002274% G e t O n e V i r t u a l P i x e l %
2275% %
2276% %
2277% %
2278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279%
2280% GetOneVirtualPixel() returns a single virtual pixel at the specified
2281% (x,y) location. The image background color is returned if an error occurs.
2282% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2283%
2284% The format of the GetOneVirtualPixel() method is:
2285%
cristybb503372010-05-27 20:51:26 +00002286% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002287% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002288%
2289% A description of each parameter follows:
2290%
2291% o image: the image.
2292%
2293% o x,y: These values define the location of the pixel to return.
2294%
2295% o pixel: return a pixel at the specified (x,y) location.
2296%
2297% o exception: return any errors or warnings in this structure.
2298%
2299*/
2300MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002301 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002302{
cristy3ed852e2009-09-05 21:47:34 +00002303 CacheInfo
2304 *cache_info;
2305
cristy0158a4b2010-09-20 13:59:45 +00002306 const int
2307 id = GetOpenMPThreadId();
2308
cristy4c08aed2011-07-01 19:47:50 +00002309 const Quantum
2310 *p;
cristy2036f5c2010-09-19 21:18:17 +00002311
cristy2ed42f62011-10-02 19:49:57 +00002312 register ssize_t
2313 i;
2314
cristy3ed852e2009-09-05 21:47:34 +00002315 assert(image != (const Image *) NULL);
2316 assert(image->signature == MagickSignature);
2317 assert(image->cache != (Cache) NULL);
2318 cache_info=(CacheInfo *) image->cache;
2319 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002320 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002321 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2322 (GetOneVirtualPixelFromHandler) NULL)
2323 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2324 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002325 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002326 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002327 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002328 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002329 {
cristy9e0719b2011-12-29 03:45:45 +00002330 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2331 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2332 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2333 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2334 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002335 return(MagickFalse);
2336 }
2337 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2338 {
2339 PixelChannel
2340 channel;
2341
cristye2a912b2011-12-05 20:02:07 +00002342 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002343 pixel[channel]=p[i];
2344 }
cristy2036f5c2010-09-19 21:18:17 +00002345 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002346}
2347
2348/*
2349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2350% %
2351% %
2352% %
2353+ 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 %
2354% %
2355% %
2356% %
2357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358%
2359% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2360% specified (x,y) location. The image background color is returned if an
2361% error occurs.
2362%
2363% The format of the GetOneVirtualPixelFromCache() method is:
2364%
2365% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002366% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002367% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002368%
2369% A description of each parameter follows:
2370%
2371% o image: the image.
2372%
2373% o virtual_pixel_method: the virtual pixel method.
2374%
2375% o x,y: These values define the location of the pixel to return.
2376%
2377% o pixel: return a pixel at the specified (x,y) location.
2378%
2379% o exception: return any errors or warnings in this structure.
2380%
2381*/
2382static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002383 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002384 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002385{
cristy0158a4b2010-09-20 13:59:45 +00002386 CacheInfo
2387 *cache_info;
2388
2389 const int
2390 id = GetOpenMPThreadId();
2391
cristy4c08aed2011-07-01 19:47:50 +00002392 const Quantum
2393 *p;
cristy3ed852e2009-09-05 21:47:34 +00002394
cristy2ed42f62011-10-02 19:49:57 +00002395 register ssize_t
2396 i;
2397
cristye7cc7cf2010-09-21 13:26:47 +00002398 assert(image != (const Image *) NULL);
2399 assert(image->signature == MagickSignature);
2400 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002401 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002402 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002403 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002404 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002405 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002406 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002407 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002408 {
cristy9e0719b2011-12-29 03:45:45 +00002409 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2410 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2411 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2412 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2413 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002414 return(MagickFalse);
2415 }
2416 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2417 {
2418 PixelChannel
2419 channel;
2420
cristye2a912b2011-12-05 20:02:07 +00002421 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002422 pixel[channel]=p[i];
2423 }
cristy3ed852e2009-09-05 21:47:34 +00002424 return(MagickTrue);
2425}
2426
2427/*
2428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2429% %
2430% %
2431% %
cristy3aa93752011-12-18 15:54:24 +00002432% G e t O n e V i r t u a l P i x e l I n f o %
2433% %
2434% %
2435% %
2436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2437%
2438% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2439% location. The image background color is returned if an error occurs. If
2440% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2441%
2442% The format of the GetOneVirtualPixelInfo() method is:
2443%
2444% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2445% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2446% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2447%
2448% A description of each parameter follows:
2449%
2450% o image: the image.
2451%
2452% o virtual_pixel_method: the virtual pixel method.
2453%
2454% o x,y: these values define the location of the pixel to return.
2455%
2456% o pixel: return a pixel at the specified (x,y) location.
2457%
2458% o exception: return any errors or warnings in this structure.
2459%
2460*/
2461MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2462 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2463 PixelInfo *pixel,ExceptionInfo *exception)
2464{
2465 CacheInfo
2466 *cache_info;
2467
2468 const int
2469 id = GetOpenMPThreadId();
2470
2471 register const Quantum
2472 *p;
2473
2474 assert(image != (const Image *) NULL);
2475 assert(image->signature == MagickSignature);
2476 assert(image->cache != (Cache) NULL);
2477 cache_info=(CacheInfo *) image->cache;
2478 assert(cache_info->signature == MagickSignature);
2479 assert(id < (int) cache_info->number_threads);
2480 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2481 cache_info->nexus_info[id],exception);
2482 GetPixelInfo(image,pixel);
2483 if (p == (const Quantum *) NULL)
2484 return(MagickFalse);
2485 GetPixelInfoPixel(image,p,pixel);
2486 return(MagickTrue);
2487}
2488
2489/*
2490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2491% %
2492% %
2493% %
cristy3ed852e2009-09-05 21:47:34 +00002494+ G e t P i x e l C a c h e C o l o r s p a c e %
2495% %
2496% %
2497% %
2498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2499%
2500% GetPixelCacheColorspace() returns the class type of the pixel cache.
2501%
2502% The format of the GetPixelCacheColorspace() method is:
2503%
2504% Colorspace GetPixelCacheColorspace(Cache cache)
2505%
2506% A description of each parameter follows:
2507%
2508% o cache: the pixel cache.
2509%
2510*/
cristya6577ff2011-09-02 19:54:26 +00002511MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002512{
2513 CacheInfo
2514 *cache_info;
2515
2516 assert(cache != (Cache) NULL);
2517 cache_info=(CacheInfo *) cache;
2518 assert(cache_info->signature == MagickSignature);
2519 if (cache_info->debug != MagickFalse)
2520 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2521 cache_info->filename);
2522 return(cache_info->colorspace);
2523}
2524
2525/*
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527% %
2528% %
2529% %
2530+ G e t P i x e l C a c h e M e t h o d s %
2531% %
2532% %
2533% %
2534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535%
2536% GetPixelCacheMethods() initializes the CacheMethods structure.
2537%
2538% The format of the GetPixelCacheMethods() method is:
2539%
2540% void GetPixelCacheMethods(CacheMethods *cache_methods)
2541%
2542% A description of each parameter follows:
2543%
2544% o cache_methods: Specifies a pointer to a CacheMethods structure.
2545%
2546*/
cristya6577ff2011-09-02 19:54:26 +00002547MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002548{
2549 assert(cache_methods != (CacheMethods *) NULL);
2550 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2551 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2552 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002553 cache_methods->get_virtual_metacontent_from_handler=
2554 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002555 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2556 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002557 cache_methods->get_authentic_metacontent_from_handler=
2558 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002559 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2560 cache_methods->get_one_authentic_pixel_from_handler=
2561 GetOneAuthenticPixelFromCache;
2562 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2563 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2564 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2565}
2566
2567/*
2568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2569% %
2570% %
2571% %
2572+ G e t P i x e l C a c h e N e x u s E x t e n t %
2573% %
2574% %
2575% %
2576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2577%
cristy4c08aed2011-07-01 19:47:50 +00002578% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2579% corresponding with the last call to SetPixelCacheNexusPixels() or
2580% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002581%
2582% The format of the GetPixelCacheNexusExtent() method is:
2583%
2584% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2585% NexusInfo *nexus_info)
2586%
2587% A description of each parameter follows:
2588%
2589% o nexus_info: the nexus info.
2590%
2591*/
cristya6577ff2011-09-02 19:54:26 +00002592MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002593 NexusInfo *nexus_info)
2594{
2595 CacheInfo
2596 *cache_info;
2597
2598 MagickSizeType
2599 extent;
2600
cristy9f027d12011-09-21 01:17:17 +00002601 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002602 cache_info=(CacheInfo *) cache;
2603 assert(cache_info->signature == MagickSignature);
2604 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2605 if (extent == 0)
2606 return((MagickSizeType) cache_info->columns*cache_info->rows);
2607 return(extent);
2608}
2609
2610/*
2611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2612% %
2613% %
2614% %
cristy4c08aed2011-07-01 19:47:50 +00002615+ 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 +00002616% %
2617% %
2618% %
2619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620%
cristy4c08aed2011-07-01 19:47:50 +00002621% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2622% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002623%
cristy4c08aed2011-07-01 19:47:50 +00002624% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002625%
cristy4c08aed2011-07-01 19:47:50 +00002626% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002627% NexusInfo *nexus_info)
2628%
2629% A description of each parameter follows:
2630%
2631% o cache: the pixel cache.
2632%
cristy4c08aed2011-07-01 19:47:50 +00002633% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002634%
2635*/
cristya6577ff2011-09-02 19:54:26 +00002636MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002637 NexusInfo *nexus_info)
2638{
2639 CacheInfo
2640 *cache_info;
2641
cristy9f027d12011-09-21 01:17:17 +00002642 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002643 cache_info=(CacheInfo *) cache;
2644 assert(cache_info->signature == MagickSignature);
2645 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002646 return((void *) NULL);
2647 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002648}
2649
2650/*
2651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2652% %
2653% %
2654% %
2655+ G e t P i x e l C a c h e N e x u s P i x e l s %
2656% %
2657% %
2658% %
2659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2660%
2661% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2662% cache nexus.
2663%
2664% The format of the GetPixelCacheNexusPixels() method is:
2665%
cristy4c08aed2011-07-01 19:47:50 +00002666% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002667% NexusInfo *nexus_info)
2668%
2669% A description of each parameter follows:
2670%
2671% o cache: the pixel cache.
2672%
2673% o nexus_info: the cache nexus to return the pixels.
2674%
2675*/
cristya6577ff2011-09-02 19:54:26 +00002676MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002677 NexusInfo *nexus_info)
2678{
2679 CacheInfo
2680 *cache_info;
2681
cristy9f027d12011-09-21 01:17:17 +00002682 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002683 cache_info=(CacheInfo *) cache;
2684 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002685 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002686 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002687 return(nexus_info->pixels);
2688}
2689
2690/*
2691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2692% %
2693% %
2694% %
cristy056ba772010-01-02 23:33:54 +00002695+ G e t P i x e l C a c h e P i x e l s %
2696% %
2697% %
2698% %
2699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700%
2701% GetPixelCachePixels() returns the pixels associated with the specified image.
2702%
2703% The format of the GetPixelCachePixels() method is:
2704%
cristyf84a1932010-01-03 18:00:18 +00002705% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2706% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002707%
2708% A description of each parameter follows:
2709%
2710% o image: the image.
2711%
2712% o length: the pixel cache length.
2713%
cristyf84a1932010-01-03 18:00:18 +00002714% o exception: return any errors or warnings in this structure.
2715%
cristy056ba772010-01-02 23:33:54 +00002716*/
cristyd1dd6e42011-09-04 01:46:08 +00002717MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002718 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002719{
2720 CacheInfo
2721 *cache_info;
2722
2723 assert(image != (const Image *) NULL);
2724 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002725 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002726 assert(length != (MagickSizeType *) NULL);
2727 assert(exception != (ExceptionInfo *) NULL);
2728 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002729 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002730 assert(cache_info->signature == MagickSignature);
2731 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002732 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002733 return((void *) NULL);
2734 *length=cache_info->length;
2735 return((void *) cache_info->pixels);
2736}
2737
2738/*
2739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2740% %
2741% %
2742% %
cristyb32b90a2009-09-07 21:45:48 +00002743+ 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 +00002744% %
2745% %
2746% %
2747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2748%
2749% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2750%
2751% The format of the GetPixelCacheStorageClass() method is:
2752%
2753% ClassType GetPixelCacheStorageClass(Cache cache)
2754%
2755% A description of each parameter follows:
2756%
2757% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2758%
2759% o cache: the pixel cache.
2760%
2761*/
cristya6577ff2011-09-02 19:54:26 +00002762MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002763{
2764 CacheInfo
2765 *cache_info;
2766
2767 assert(cache != (Cache) NULL);
2768 cache_info=(CacheInfo *) cache;
2769 assert(cache_info->signature == MagickSignature);
2770 if (cache_info->debug != MagickFalse)
2771 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2772 cache_info->filename);
2773 return(cache_info->storage_class);
2774}
2775
2776/*
2777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2778% %
2779% %
2780% %
cristyb32b90a2009-09-07 21:45:48 +00002781+ G e t P i x e l C a c h e T i l e S i z e %
2782% %
2783% %
2784% %
2785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2786%
2787% GetPixelCacheTileSize() returns the pixel cache tile size.
2788%
2789% The format of the GetPixelCacheTileSize() method is:
2790%
cristybb503372010-05-27 20:51:26 +00002791% void GetPixelCacheTileSize(const Image *image,size_t *width,
2792% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002793%
2794% A description of each parameter follows:
2795%
2796% o image: the image.
2797%
2798% o width: the optimize cache tile width in pixels.
2799%
2800% o height: the optimize cache tile height in pixels.
2801%
2802*/
cristya6577ff2011-09-02 19:54:26 +00002803MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002804 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002805{
cristy4c08aed2011-07-01 19:47:50 +00002806 CacheInfo
2807 *cache_info;
2808
cristyb32b90a2009-09-07 21:45:48 +00002809 assert(image != (Image *) NULL);
2810 assert(image->signature == MagickSignature);
2811 if (image->debug != MagickFalse)
2812 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002813 cache_info=(CacheInfo *) image->cache;
2814 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002815 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002816 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002817 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002818 *height=(*width);
2819}
2820
2821/*
2822%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2823% %
2824% %
2825% %
2826+ G e t P i x e l C a c h e T y p e %
2827% %
2828% %
2829% %
2830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831%
2832% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2833%
2834% The format of the GetPixelCacheType() method is:
2835%
2836% CacheType GetPixelCacheType(const Image *image)
2837%
2838% A description of each parameter follows:
2839%
2840% o image: the image.
2841%
2842*/
cristya6577ff2011-09-02 19:54:26 +00002843MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002844{
2845 CacheInfo
2846 *cache_info;
2847
2848 assert(image != (Image *) NULL);
2849 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002850 assert(image->cache != (Cache) NULL);
2851 cache_info=(CacheInfo *) image->cache;
2852 assert(cache_info->signature == MagickSignature);
2853 return(cache_info->type);
2854}
2855
2856/*
2857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2858% %
2859% %
2860% %
cristy3ed852e2009-09-05 21:47:34 +00002861+ 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 %
2862% %
2863% %
2864% %
2865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866%
2867% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2868% pixel cache. A virtual pixel is any pixel access that is outside the
2869% boundaries of the image cache.
2870%
2871% The format of the GetPixelCacheVirtualMethod() method is:
2872%
2873% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2874%
2875% A description of each parameter follows:
2876%
2877% o image: the image.
2878%
2879*/
cristyd1dd6e42011-09-04 01:46:08 +00002880MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002881{
2882 CacheInfo
2883 *cache_info;
2884
2885 assert(image != (Image *) NULL);
2886 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002887 assert(image->cache != (Cache) NULL);
2888 cache_info=(CacheInfo *) image->cache;
2889 assert(cache_info->signature == MagickSignature);
2890 return(cache_info->virtual_pixel_method);
2891}
2892
2893/*
2894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895% %
2896% %
2897% %
cristy4c08aed2011-07-01 19:47:50 +00002898+ 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 +00002899% %
2900% %
2901% %
2902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903%
cristy4c08aed2011-07-01 19:47:50 +00002904% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2905% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002906%
cristy4c08aed2011-07-01 19:47:50 +00002907% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002908%
cristy4c08aed2011-07-01 19:47:50 +00002909% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002910%
2911% A description of each parameter follows:
2912%
2913% o image: the image.
2914%
2915*/
cristy4c08aed2011-07-01 19:47:50 +00002916static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002917{
2918 CacheInfo
2919 *cache_info;
2920
cristy5c9e6f22010-09-17 17:31:01 +00002921 const int
2922 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002923
cristy4c08aed2011-07-01 19:47:50 +00002924 const void
2925 *metacontent;
2926
cristye7cc7cf2010-09-21 13:26:47 +00002927 assert(image != (const Image *) NULL);
2928 assert(image->signature == MagickSignature);
2929 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002930 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002931 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002932 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002933 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2934 cache_info->nexus_info[id]);
2935 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002936}
2937
2938/*
2939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2940% %
2941% %
2942% %
cristy4c08aed2011-07-01 19:47:50 +00002943+ 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 +00002944% %
2945% %
2946% %
2947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2948%
cristy4c08aed2011-07-01 19:47:50 +00002949% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2950% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002951%
cristy4c08aed2011-07-01 19:47:50 +00002952% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002953%
cristy4c08aed2011-07-01 19:47:50 +00002954% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002955% NexusInfo *nexus_info)
2956%
2957% A description of each parameter follows:
2958%
2959% o cache: the pixel cache.
2960%
cristy4c08aed2011-07-01 19:47:50 +00002961% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002962%
2963*/
cristya6577ff2011-09-02 19:54:26 +00002964MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002965 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002966{
2967 CacheInfo
2968 *cache_info;
2969
cristye7cc7cf2010-09-21 13:26:47 +00002970 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002971 cache_info=(CacheInfo *) cache;
2972 assert(cache_info->signature == MagickSignature);
2973 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002974 return((void *) NULL);
2975 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002976}
2977
2978/*
2979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2980% %
2981% %
2982% %
cristy4c08aed2011-07-01 19:47:50 +00002983% 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 +00002984% %
2985% %
2986% %
2987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988%
cristy4c08aed2011-07-01 19:47:50 +00002989% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2990% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2991% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002992%
cristy4c08aed2011-07-01 19:47:50 +00002993% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002994%
cristy4c08aed2011-07-01 19:47:50 +00002995% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002996%
2997% A description of each parameter follows:
2998%
2999% o image: the image.
3000%
3001*/
cristy4c08aed2011-07-01 19:47:50 +00003002MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003003{
3004 CacheInfo
3005 *cache_info;
3006
cristy2036f5c2010-09-19 21:18:17 +00003007 const int
3008 id = GetOpenMPThreadId();
3009
cristy4c08aed2011-07-01 19:47:50 +00003010 const void
3011 *metacontent;
3012
cristy3ed852e2009-09-05 21:47:34 +00003013 assert(image != (const Image *) NULL);
3014 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003015 assert(image->cache != (Cache) NULL);
3016 cache_info=(CacheInfo *) image->cache;
3017 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003018 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3019 (GetVirtualMetacontentFromHandler) NULL)
3020 {
3021 metacontent=cache_info->methods.
3022 get_virtual_metacontent_from_handler(image);
3023 return(metacontent);
3024 }
cristy2036f5c2010-09-19 21:18:17 +00003025 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003026 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3027 cache_info->nexus_info[id]);
3028 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003029}
3030
3031/*
3032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3033% %
3034% %
3035% %
3036+ 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 %
3037% %
3038% %
3039% %
3040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3041%
3042% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3043% pixel cache as defined by the geometry parameters. A pointer to the pixels
3044% is returned if the pixels are transferred, otherwise a NULL is returned.
3045%
3046% The format of the GetVirtualPixelsFromNexus() method is:
3047%
cristy4c08aed2011-07-01 19:47:50 +00003048% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003049% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003050% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3051% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003052%
3053% A description of each parameter follows:
3054%
3055% o image: the image.
3056%
3057% o virtual_pixel_method: the virtual pixel method.
3058%
3059% o x,y,columns,rows: These values define the perimeter of a region of
3060% pixels.
3061%
3062% o nexus_info: the cache nexus to acquire.
3063%
3064% o exception: return any errors or warnings in this structure.
3065%
3066*/
3067
cristybb503372010-05-27 20:51:26 +00003068static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003069 DitherMatrix[64] =
3070 {
3071 0, 48, 12, 60, 3, 51, 15, 63,
3072 32, 16, 44, 28, 35, 19, 47, 31,
3073 8, 56, 4, 52, 11, 59, 7, 55,
3074 40, 24, 36, 20, 43, 27, 39, 23,
3075 2, 50, 14, 62, 1, 49, 13, 61,
3076 34, 18, 46, 30, 33, 17, 45, 29,
3077 10, 58, 6, 54, 9, 57, 5, 53,
3078 42, 26, 38, 22, 41, 25, 37, 21
3079 };
3080
cristybb503372010-05-27 20:51:26 +00003081static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003082{
cristybb503372010-05-27 20:51:26 +00003083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003084 index;
3085
3086 index=x+DitherMatrix[x & 0x07]-32L;
3087 if (index < 0L)
3088 return(0L);
cristybb503372010-05-27 20:51:26 +00003089 if (index >= (ssize_t) columns)
3090 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003091 return(index);
3092}
3093
cristybb503372010-05-27 20:51:26 +00003094static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003095{
cristybb503372010-05-27 20:51:26 +00003096 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003097 index;
3098
3099 index=y+DitherMatrix[y & 0x07]-32L;
3100 if (index < 0L)
3101 return(0L);
cristybb503372010-05-27 20:51:26 +00003102 if (index >= (ssize_t) rows)
3103 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003104 return(index);
3105}
3106
cristybb503372010-05-27 20:51:26 +00003107static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003108{
3109 if (x < 0L)
3110 return(0L);
cristybb503372010-05-27 20:51:26 +00003111 if (x >= (ssize_t) columns)
3112 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003113 return(x);
3114}
3115
cristybb503372010-05-27 20:51:26 +00003116static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003117{
3118 if (y < 0L)
3119 return(0L);
cristybb503372010-05-27 20:51:26 +00003120 if (y >= (ssize_t) rows)
3121 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003122 return(y);
3123}
3124
cristybb503372010-05-27 20:51:26 +00003125static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003126{
cristybb503372010-05-27 20:51:26 +00003127 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003128}
3129
cristybb503372010-05-27 20:51:26 +00003130static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003131{
cristybb503372010-05-27 20:51:26 +00003132 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003133}
3134
cristybb503372010-05-27 20:51:26 +00003135static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3136 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003137{
3138 MagickModulo
3139 modulo;
3140
cristy6162bb42011-07-18 11:34:09 +00003141 /*
3142 Compute the remainder of dividing offset by extent. It returns not only
3143 the quotient (tile the offset falls in) but also the positive remainer
3144 within that tile such that 0 <= remainder < extent. This method is
3145 essentially a ldiv() using a floored modulo division rather than the
3146 normal default truncated modulo division.
3147 */
cristybb503372010-05-27 20:51:26 +00003148 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003149 if (offset < 0L)
3150 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003151 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003152 return(modulo);
3153}
3154
cristya6577ff2011-09-02 19:54:26 +00003155MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003156 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3157 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003158 ExceptionInfo *exception)
3159{
3160 CacheInfo
3161 *cache_info;
3162
3163 MagickOffsetType
3164 offset;
3165
3166 MagickSizeType
3167 length,
3168 number_pixels;
3169
3170 NexusInfo
3171 **virtual_nexus;
3172
cristy4c08aed2011-07-01 19:47:50 +00003173 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003174 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003175 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003176
3177 RectangleInfo
3178 region;
3179
cristy4c08aed2011-07-01 19:47:50 +00003180 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003181 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003182
cristy4c08aed2011-07-01 19:47:50 +00003183 register const void
3184 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003185
cristy4c08aed2011-07-01 19:47:50 +00003186 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003187 *restrict q;
3188
cristybb503372010-05-27 20:51:26 +00003189 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003190 i,
3191 u;
cristy3ed852e2009-09-05 21:47:34 +00003192
cristy4c08aed2011-07-01 19:47:50 +00003193 register unsigned char
3194 *restrict s;
3195
cristy105ba3c2011-07-18 02:28:38 +00003196 ssize_t
3197 v;
3198
cristy4c08aed2011-07-01 19:47:50 +00003199 void
cristy105ba3c2011-07-18 02:28:38 +00003200 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003201
cristy3ed852e2009-09-05 21:47:34 +00003202 /*
3203 Acquire pixels.
3204 */
cristye7cc7cf2010-09-21 13:26:47 +00003205 assert(image != (const Image *) NULL);
3206 assert(image->signature == MagickSignature);
3207 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003208 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003209 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003210 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003211 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003212 region.x=x;
3213 region.y=y;
3214 region.width=columns;
3215 region.height=rows;
3216 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003217 if (pixels == (Quantum *) NULL)
3218 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003219 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003220 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3221 nexus_info->region.x;
3222 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3223 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003224 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3225 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003226 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3227 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003228 {
3229 MagickBooleanType
3230 status;
3231
3232 /*
3233 Pixel request is inside cache extents.
3234 */
cristy4c08aed2011-07-01 19:47:50 +00003235 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003236 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003237 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3238 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003239 return((const Quantum *) NULL);
3240 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003241 {
cristy4c08aed2011-07-01 19:47:50 +00003242 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003243 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003244 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003245 }
cristyacd2ed22011-08-30 01:44:23 +00003246 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003247 }
3248 /*
3249 Pixel request is outside cache extents.
3250 */
cristy4c08aed2011-07-01 19:47:50 +00003251 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003252 virtual_nexus=AcquirePixelCacheNexus(1);
3253 if (virtual_nexus == (NexusInfo **) NULL)
3254 {
cristy4c08aed2011-07-01 19:47:50 +00003255 if (virtual_nexus != (NexusInfo **) NULL)
3256 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003257 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3258 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003259 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003260 }
cristy105ba3c2011-07-18 02:28:38 +00003261 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3262 sizeof(*virtual_pixel));
3263 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003264 switch (virtual_pixel_method)
3265 {
cristy4c08aed2011-07-01 19:47:50 +00003266 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003267 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003268 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003269 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003270 case MaskVirtualPixelMethod:
3271 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003272 case EdgeVirtualPixelMethod:
3273 case CheckerTileVirtualPixelMethod:
3274 case HorizontalTileVirtualPixelMethod:
3275 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003276 {
cristy4c08aed2011-07-01 19:47:50 +00003277 if (cache_info->metacontent_extent != 0)
3278 {
cristy6162bb42011-07-18 11:34:09 +00003279 /*
3280 Acquire a metacontent buffer.
3281 */
cristya64b85d2011-09-14 01:02:31 +00003282 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003283 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003284 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003285 {
cristy4c08aed2011-07-01 19:47:50 +00003286 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3287 (void) ThrowMagickException(exception,GetMagickModule(),
3288 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3289 return((const Quantum *) NULL);
3290 }
cristy105ba3c2011-07-18 02:28:38 +00003291 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003292 cache_info->metacontent_extent);
3293 }
3294 switch (virtual_pixel_method)
3295 {
3296 case BlackVirtualPixelMethod:
3297 {
cristy30301712011-07-18 15:06:51 +00003298 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3299 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003300 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3301 break;
3302 }
3303 case GrayVirtualPixelMethod:
3304 {
cristy30301712011-07-18 15:06:51 +00003305 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003306 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3307 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003308 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3309 break;
3310 }
3311 case TransparentVirtualPixelMethod:
3312 {
cristy30301712011-07-18 15:06:51 +00003313 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3314 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003315 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3316 break;
3317 }
3318 case MaskVirtualPixelMethod:
3319 case WhiteVirtualPixelMethod:
3320 {
cristy30301712011-07-18 15:06:51 +00003321 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3322 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003323 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3324 break;
3325 }
3326 default:
3327 {
cristy9e0719b2011-12-29 03:45:45 +00003328 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3329 virtual_pixel);
3330 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3331 virtual_pixel);
3332 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3333 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003334 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003335 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3336 virtual_pixel);
3337 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3338 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003339 break;
3340 }
3341 }
cristy3ed852e2009-09-05 21:47:34 +00003342 break;
3343 }
3344 default:
cristy3ed852e2009-09-05 21:47:34 +00003345 break;
cristy3ed852e2009-09-05 21:47:34 +00003346 }
cristybb503372010-05-27 20:51:26 +00003347 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003348 {
cristybb503372010-05-27 20:51:26 +00003349 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003350 {
3351 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003352 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003353 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3354 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003355 {
3356 MagickModulo
3357 x_modulo,
3358 y_modulo;
3359
3360 /*
3361 Transfer a single pixel.
3362 */
3363 length=(MagickSizeType) 1;
3364 switch (virtual_pixel_method)
3365 {
cristy3ed852e2009-09-05 21:47:34 +00003366 default:
3367 {
3368 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003369 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003370 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003371 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003372 break;
3373 }
3374 case RandomVirtualPixelMethod:
3375 {
3376 if (cache_info->random_info == (RandomInfo *) NULL)
3377 cache_info->random_info=AcquireRandomInfo();
3378 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003379 RandomX(cache_info->random_info,cache_info->columns),
3380 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003381 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003382 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003383 break;
3384 }
3385 case DitherVirtualPixelMethod:
3386 {
3387 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003388 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003389 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003390 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003391 break;
3392 }
3393 case TileVirtualPixelMethod:
3394 {
3395 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3396 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3397 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003398 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003399 exception);
cristy4c08aed2011-07-01 19:47:50 +00003400 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003401 break;
3402 }
3403 case MirrorVirtualPixelMethod:
3404 {
3405 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3406 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003407 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003408 x_modulo.remainder-1L;
3409 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3410 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003411 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003412 y_modulo.remainder-1L;
3413 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003414 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003415 exception);
cristy4c08aed2011-07-01 19:47:50 +00003416 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003417 break;
3418 }
3419 case HorizontalTileEdgeVirtualPixelMethod:
3420 {
3421 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3422 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003423 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003424 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003425 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 case VerticalTileEdgeVirtualPixelMethod:
3429 {
3430 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3431 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003432 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003433 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003434 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3435 break;
3436 }
3437 case BackgroundVirtualPixelMethod:
3438 case BlackVirtualPixelMethod:
3439 case GrayVirtualPixelMethod:
3440 case TransparentVirtualPixelMethod:
3441 case MaskVirtualPixelMethod:
3442 case WhiteVirtualPixelMethod:
3443 {
3444 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003445 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003446 break;
3447 }
3448 case EdgeVirtualPixelMethod:
3449 case CheckerTileVirtualPixelMethod:
3450 {
3451 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3452 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3453 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3454 {
3455 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003456 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003457 break;
3458 }
3459 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3460 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3461 exception);
3462 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3463 break;
3464 }
3465 case HorizontalTileVirtualPixelMethod:
3466 {
3467 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3468 {
3469 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003470 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003471 break;
3472 }
3473 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3474 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3475 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3476 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3477 exception);
3478 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3479 break;
3480 }
3481 case VerticalTileVirtualPixelMethod:
3482 {
3483 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3484 {
3485 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003486 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003487 break;
3488 }
3489 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3490 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3491 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3492 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3493 exception);
3494 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003495 break;
3496 }
3497 }
cristy4c08aed2011-07-01 19:47:50 +00003498 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003499 break;
cristyed231572011-07-14 02:18:59 +00003500 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003501 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003502 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003503 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003504 {
3505 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3506 s+=cache_info->metacontent_extent;
3507 }
cristy3ed852e2009-09-05 21:47:34 +00003508 continue;
3509 }
3510 /*
3511 Transfer a run of pixels.
3512 */
cristy4c08aed2011-07-01 19:47:50 +00003513 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3514 length,1UL,*virtual_nexus,exception);
3515 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003516 break;
cristy4c08aed2011-07-01 19:47:50 +00003517 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003518 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3519 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003520 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003521 {
cristy4c08aed2011-07-01 19:47:50 +00003522 (void) memcpy(s,r,(size_t) length);
3523 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003524 }
3525 }
3526 }
cristy4c08aed2011-07-01 19:47:50 +00003527 /*
3528 Free resources.
3529 */
cristy105ba3c2011-07-18 02:28:38 +00003530 if (virtual_metacontent != (void *) NULL)
3531 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003532 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3533 return(pixels);
3534}
3535
3536/*
3537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3538% %
3539% %
3540% %
3541+ G e t V i r t u a l P i x e l C a c h e %
3542% %
3543% %
3544% %
3545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3546%
3547% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3548% cache as defined by the geometry parameters. A pointer to the pixels
3549% is returned if the pixels are transferred, otherwise a NULL is returned.
3550%
3551% The format of the GetVirtualPixelCache() method is:
3552%
cristy4c08aed2011-07-01 19:47:50 +00003553% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003554% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3555% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003556% ExceptionInfo *exception)
3557%
3558% A description of each parameter follows:
3559%
3560% o image: the image.
3561%
3562% o virtual_pixel_method: the virtual pixel method.
3563%
3564% o x,y,columns,rows: These values define the perimeter of a region of
3565% pixels.
3566%
3567% o exception: return any errors or warnings in this structure.
3568%
3569*/
cristy4c08aed2011-07-01 19:47:50 +00003570static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003571 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3572 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003573{
3574 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003575 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003576
cristy5c9e6f22010-09-17 17:31:01 +00003577 const int
3578 id = GetOpenMPThreadId();
3579
cristy4c08aed2011-07-01 19:47:50 +00003580 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003581 *p;
cristy4c08aed2011-07-01 19:47:50 +00003582
cristye7cc7cf2010-09-21 13:26:47 +00003583 assert(image != (const Image *) NULL);
3584 assert(image->signature == MagickSignature);
3585 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003586 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003587 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003588 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003589 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003590 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003591 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003592}
3593
3594/*
3595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596% %
3597% %
3598% %
3599% G e t V i r t u a l P i x e l Q u e u e %
3600% %
3601% %
3602% %
3603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604%
cristy4c08aed2011-07-01 19:47:50 +00003605% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3606% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003607%
3608% The format of the GetVirtualPixelQueue() method is:
3609%
cristy4c08aed2011-07-01 19:47:50 +00003610% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003611%
3612% A description of each parameter follows:
3613%
3614% o image: the image.
3615%
3616*/
cristy4c08aed2011-07-01 19:47:50 +00003617MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003618{
3619 CacheInfo
3620 *cache_info;
3621
cristy2036f5c2010-09-19 21:18:17 +00003622 const int
3623 id = GetOpenMPThreadId();
3624
cristy3ed852e2009-09-05 21:47:34 +00003625 assert(image != (const Image *) NULL);
3626 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003627 assert(image->cache != (Cache) NULL);
3628 cache_info=(CacheInfo *) image->cache;
3629 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003630 if (cache_info->methods.get_virtual_pixels_handler !=
3631 (GetVirtualPixelsHandler) NULL)
3632 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003633 assert(id < (int) cache_info->number_threads);
3634 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003635}
3636
3637/*
3638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3639% %
3640% %
3641% %
3642% G e t V i r t u a l P i x e l s %
3643% %
3644% %
3645% %
3646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647%
3648% GetVirtualPixels() returns an immutable pixel region. If the
3649% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003650% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003651% copy of the pixels or it may point to the original pixels in memory.
3652% Performance is maximized if the selected region is part of one row, or one
3653% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003654% (without a copy) if the image is in memory, or in a memory-mapped file. The
3655% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003656%
3657% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003658% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3659% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3660% access the meta-content (of type void) corresponding to the the
3661% region.
cristy3ed852e2009-09-05 21:47:34 +00003662%
3663% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3664%
3665% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3666% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3667% GetCacheViewAuthenticPixels() instead.
3668%
3669% The format of the GetVirtualPixels() method is:
3670%
cristy4c08aed2011-07-01 19:47:50 +00003671% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003672% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003673% ExceptionInfo *exception)
3674%
3675% A description of each parameter follows:
3676%
3677% o image: the image.
3678%
3679% o x,y,columns,rows: These values define the perimeter of a region of
3680% pixels.
3681%
3682% o exception: return any errors or warnings in this structure.
3683%
3684*/
cristy4c08aed2011-07-01 19:47:50 +00003685MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003686 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3687 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003688{
3689 CacheInfo
3690 *cache_info;
3691
cristy2036f5c2010-09-19 21:18:17 +00003692 const int
3693 id = GetOpenMPThreadId();
3694
cristy4c08aed2011-07-01 19:47:50 +00003695 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003696 *p;
cristy4c08aed2011-07-01 19:47:50 +00003697
cristy3ed852e2009-09-05 21:47:34 +00003698 assert(image != (const Image *) NULL);
3699 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003700 assert(image->cache != (Cache) NULL);
3701 cache_info=(CacheInfo *) image->cache;
3702 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003703 if (cache_info->methods.get_virtual_pixel_handler !=
3704 (GetVirtualPixelHandler) NULL)
3705 return(cache_info->methods.get_virtual_pixel_handler(image,
3706 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003707 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003708 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003709 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003710 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003711}
3712
3713/*
3714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3715% %
3716% %
3717% %
3718+ 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 %
3719% %
3720% %
3721% %
3722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3723%
cristy4c08aed2011-07-01 19:47:50 +00003724% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3725% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003726%
3727% The format of the GetVirtualPixelsCache() method is:
3728%
cristy4c08aed2011-07-01 19:47:50 +00003729% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003730%
3731% A description of each parameter follows:
3732%
3733% o image: the image.
3734%
3735*/
cristy4c08aed2011-07-01 19:47:50 +00003736static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003737{
3738 CacheInfo
3739 *cache_info;
3740
cristy5c9e6f22010-09-17 17:31:01 +00003741 const int
3742 id = GetOpenMPThreadId();
3743
cristye7cc7cf2010-09-21 13:26:47 +00003744 assert(image != (const Image *) NULL);
3745 assert(image->signature == MagickSignature);
3746 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003747 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003748 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003749 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003750 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003751}
3752
3753/*
3754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3755% %
3756% %
3757% %
3758+ G e t V i r t u a l P i x e l s N e x u s %
3759% %
3760% %
3761% %
3762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3763%
3764% GetVirtualPixelsNexus() returns the pixels associated with the specified
3765% cache nexus.
3766%
3767% The format of the GetVirtualPixelsNexus() method is:
3768%
cristy4c08aed2011-07-01 19:47:50 +00003769% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003770% NexusInfo *nexus_info)
3771%
3772% A description of each parameter follows:
3773%
3774% o cache: the pixel cache.
3775%
3776% o nexus_info: the cache nexus to return the colormap pixels.
3777%
3778*/
cristya6577ff2011-09-02 19:54:26 +00003779MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003780 NexusInfo *nexus_info)
3781{
3782 CacheInfo
3783 *cache_info;
3784
cristye7cc7cf2010-09-21 13:26:47 +00003785 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003786 cache_info=(CacheInfo *) cache;
3787 assert(cache_info->signature == MagickSignature);
3788 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003789 return((Quantum *) NULL);
3790 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003791}
3792
3793/*
3794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3795% %
3796% %
3797% %
3798+ M a s k P i x e l C a c h e N e x u s %
3799% %
3800% %
3801% %
3802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803%
3804% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3805% The method returns MagickTrue if the pixel region is masked, otherwise
3806% MagickFalse.
3807%
3808% The format of the MaskPixelCacheNexus() method is:
3809%
3810% MagickBooleanType MaskPixelCacheNexus(Image *image,
3811% NexusInfo *nexus_info,ExceptionInfo *exception)
3812%
3813% A description of each parameter follows:
3814%
3815% o image: the image.
3816%
3817% o nexus_info: the cache nexus to clip.
3818%
3819% o exception: return any errors or warnings in this structure.
3820%
3821*/
3822
cristy3aa93752011-12-18 15:54:24 +00003823static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3824 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003825{
3826 MagickRealType
3827 gamma;
3828
cristyaa83c2c2011-09-21 13:36:25 +00003829 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003830 {
3831 *composite=(*q);
3832 return;
3833 }
3834 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3835 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003836 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3837 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3838 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003839 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003840 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003841}
3842
3843static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3844 ExceptionInfo *exception)
3845{
3846 CacheInfo
3847 *cache_info;
3848
cristy4c08aed2011-07-01 19:47:50 +00003849 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003850 alpha,
3851 beta;
3852
3853 MagickSizeType
3854 number_pixels;
3855
3856 NexusInfo
3857 **clip_nexus,
3858 **image_nexus;
3859
cristy4c08aed2011-07-01 19:47:50 +00003860 register const Quantum
3861 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003862 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003863
cristy4c08aed2011-07-01 19:47:50 +00003864 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003865 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003866
cristye076a6e2010-08-15 19:59:43 +00003867 register ssize_t
3868 i;
3869
cristy3ed852e2009-09-05 21:47:34 +00003870 /*
3871 Apply clip mask.
3872 */
3873 if (image->debug != MagickFalse)
3874 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3875 if (image->mask == (Image *) NULL)
3876 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003877 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003878 if (cache_info == (Cache) NULL)
3879 return(MagickFalse);
3880 image_nexus=AcquirePixelCacheNexus(1);
3881 clip_nexus=AcquirePixelCacheNexus(1);
3882 if ((image_nexus == (NexusInfo **) NULL) ||
3883 (clip_nexus == (NexusInfo **) NULL))
3884 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003885 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3886 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3887 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003888 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003889 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3890 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003891 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003892 GetPixelInfo(image,&alpha);
3893 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003894 number_pixels=(MagickSizeType) nexus_info->region.width*
3895 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003896 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003897 {
cristy4c08aed2011-07-01 19:47:50 +00003898 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003899 break;
cristy803640d2011-11-17 02:11:32 +00003900 GetPixelInfoPixel(image,p,&alpha);
3901 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003902 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003903 &alpha,alpha.alpha,&beta);
3904 SetPixelRed(image,ClampToQuantum(beta.red),q);
3905 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3906 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3907 if (cache_info->colorspace == CMYKColorspace)
3908 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3909 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003910 p++;
3911 q++;
3912 r++;
3913 }
3914 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3915 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003916 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003917 return(MagickFalse);
3918 return(MagickTrue);
3919}
3920
3921/*
3922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3923% %
3924% %
3925% %
3926+ O p e n P i x e l C a c h e %
3927% %
3928% %
3929% %
3930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3931%
3932% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3933% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003934% metacontent, and memory mapping the cache if it is disk based. The cache
3935% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003936%
3937% The format of the OpenPixelCache() method is:
3938%
3939% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3940% ExceptionInfo *exception)
3941%
3942% A description of each parameter follows:
3943%
3944% o image: the image.
3945%
3946% o mode: ReadMode, WriteMode, or IOMode.
3947%
3948% o exception: return any errors or warnings in this structure.
3949%
3950*/
3951
cristyd43a46b2010-01-21 02:13:41 +00003952static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003953{
3954 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003955 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003956 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003957 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003958 {
3959 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003960 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003961 cache_info->length);
3962 }
3963}
3964
3965static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3966{
3967 CacheInfo
3968 *cache_info;
3969
3970 MagickOffsetType
3971 count,
3972 extent,
3973 offset;
3974
3975 cache_info=(CacheInfo *) image->cache;
3976 if (image->debug != MagickFalse)
3977 {
3978 char
3979 format[MaxTextExtent],
3980 message[MaxTextExtent];
3981
cristyb9080c92009-12-01 20:13:26 +00003982 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003983 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003984 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003985 cache_info->cache_filename,cache_info->file,format);
3986 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3987 }
3988 if (length != (MagickSizeType) ((MagickOffsetType) length))
3989 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003990 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003991 if (extent < 0)
3992 return(MagickFalse);
3993 if ((MagickSizeType) extent >= length)
3994 return(MagickTrue);
3995 offset=(MagickOffsetType) length-1;
3996 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3997 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3998}
3999
4000static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4001 ExceptionInfo *exception)
4002{
cristy3ed852e2009-09-05 21:47:34 +00004003 CacheInfo
4004 *cache_info,
4005 source_info;
4006
cristyf3a6a9d2010-11-07 21:02:56 +00004007 char
4008 format[MaxTextExtent],
4009 message[MaxTextExtent];
4010
cristy4c08aed2011-07-01 19:47:50 +00004011 MagickBooleanType
4012 status;
4013
cristy3ed852e2009-09-05 21:47:34 +00004014 MagickSizeType
4015 length,
4016 number_pixels;
4017
cristy3b8fe922011-12-29 18:56:23 +00004018 PixelChannelMap
4019 *p,
4020 *q;
4021
cristy3ed852e2009-09-05 21:47:34 +00004022 size_t
cristye076a6e2010-08-15 19:59:43 +00004023 columns,
cristy3ed852e2009-09-05 21:47:34 +00004024 packet_size;
4025
cristye7cc7cf2010-09-21 13:26:47 +00004026 assert(image != (const Image *) NULL);
4027 assert(image->signature == MagickSignature);
4028 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004029 if (image->debug != MagickFalse)
4030 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4031 if ((image->columns == 0) || (image->rows == 0))
4032 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4033 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004034 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004035 source_info=(*cache_info);
4036 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004037 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004038 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004039 cache_info->storage_class=image->storage_class;
4040 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004041 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004042 cache_info->rows=image->rows;
4043 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004044 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004045 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004046 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4047 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004048 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004049 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004050 if (image->ping != MagickFalse)
4051 {
cristy73724512010-04-12 14:43:14 +00004052 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004053 cache_info->pixels=(Quantum *) NULL;
4054 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004055 cache_info->length=0;
4056 return(MagickTrue);
4057 }
cristy3ed852e2009-09-05 21:47:34 +00004058 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004059 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004060 if (image->metacontent_extent != 0)
4061 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004062 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004063 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004064 if (cache_info->columns != columns)
4065 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4066 image->filename);
4067 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004068 p=cache_info->channel_map;
4069 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004070 if ((cache_info->type != UndefinedCache) &&
4071 (cache_info->columns <= source_info.columns) &&
4072 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004073 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004074 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004075 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4076 {
4077 /*
4078 Inline pixel cache clone optimization.
4079 */
4080 if ((cache_info->columns == source_info.columns) &&
4081 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004082 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004083 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004084 (cache_info->metacontent_extent == source_info.metacontent_extent))
4085 return(MagickTrue);
4086 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4087 }
cristy3ed852e2009-09-05 21:47:34 +00004088 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004089 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004090 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004091 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4092 {
4093 status=AcquireMagickResource(MemoryResource,cache_info->length);
4094 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4095 (cache_info->type == MemoryCache))
4096 {
cristyd43a46b2010-01-21 02:13:41 +00004097 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004098 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004099 cache_info->pixels=source_info.pixels;
4100 else
4101 {
4102 /*
4103 Create memory pixel cache.
4104 */
cristy4c08aed2011-07-01 19:47:50 +00004105 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004106 if (image->debug != MagickFalse)
4107 {
cristy32cacff2011-12-31 03:36:27 +00004108 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004109 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004110 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4111 cache_info->filename,cache_info->mapped != MagickFalse ?
4112 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004113 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004114 format);
cristy3ed852e2009-09-05 21:47:34 +00004115 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4116 message);
4117 }
cristy3ed852e2009-09-05 21:47:34 +00004118 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004119 cache_info->metacontent=(void *) NULL;
4120 if (cache_info->metacontent_extent != 0)
4121 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004122 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004123 if ((source_info.storage_class != UndefinedClass) &&
4124 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004125 {
cristy4c08aed2011-07-01 19:47:50 +00004126 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004127 exception);
4128 RelinquishPixelCachePixels(&source_info);
4129 }
cristy4c08aed2011-07-01 19:47:50 +00004130 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004131 }
4132 }
4133 RelinquishMagickResource(MemoryResource,cache_info->length);
4134 }
4135 /*
4136 Create pixel cache on disk.
4137 */
4138 status=AcquireMagickResource(DiskResource,cache_info->length);
4139 if (status == MagickFalse)
4140 {
4141 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4142 "CacheResourcesExhausted","`%s'",image->filename);
4143 return(MagickFalse);
4144 }
cristy413f1302012-01-01 17:48:27 +00004145 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4146 {
4147 (void) ClosePixelCacheOnDisk(cache_info);
4148 *cache_info->cache_filename='\0';
4149 }
cristy3ed852e2009-09-05 21:47:34 +00004150 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4151 {
4152 RelinquishMagickResource(DiskResource,cache_info->length);
4153 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4154 image->filename);
4155 return(MagickFalse);
4156 }
4157 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4158 cache_info->length);
4159 if (status == MagickFalse)
4160 {
4161 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4162 image->filename);
4163 return(MagickFalse);
4164 }
cristyed231572011-07-14 02:18:59 +00004165 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004166 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004167 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004168 cache_info->type=DiskCache;
4169 else
4170 {
4171 status=AcquireMagickResource(MapResource,cache_info->length);
4172 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4173 (cache_info->type != MemoryCache))
4174 cache_info->type=DiskCache;
4175 else
4176 {
cristy4c08aed2011-07-01 19:47:50 +00004177 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004178 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004179 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004180 {
cristy3ed852e2009-09-05 21:47:34 +00004181 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004182 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004183 }
4184 else
4185 {
4186 /*
4187 Create file-backed memory-mapped pixel cache.
4188 */
cristy4c08aed2011-07-01 19:47:50 +00004189 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004190 (void) ClosePixelCacheOnDisk(cache_info);
4191 cache_info->type=MapCache;
4192 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004193 cache_info->metacontent=(void *) NULL;
4194 if (cache_info->metacontent_extent != 0)
4195 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004196 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00004197 if ((source_info.storage_class != UndefinedClass) &&
4198 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004199 {
4200 status=ClonePixelCachePixels(cache_info,&source_info,
4201 exception);
4202 RelinquishPixelCachePixels(&source_info);
4203 }
4204 if (image->debug != MagickFalse)
4205 {
cristy413f1302012-01-01 17:48:27 +00004206 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004207 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004208 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004209 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004210 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004211 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004212 format);
cristy3ed852e2009-09-05 21:47:34 +00004213 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4214 message);
4215 }
cristy4c08aed2011-07-01 19:47:50 +00004216 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004217 }
4218 }
4219 RelinquishMagickResource(MapResource,cache_info->length);
4220 }
cristy4c08aed2011-07-01 19:47:50 +00004221 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00004222 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00004223 {
4224 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4225 RelinquishPixelCachePixels(&source_info);
4226 }
4227 if (image->debug != MagickFalse)
4228 {
cristyb9080c92009-12-01 20:13:26 +00004229 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004230 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004231 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004232 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004233 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004234 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004235 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4236 }
cristy4c08aed2011-07-01 19:47:50 +00004237 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004238}
4239
4240/*
4241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4242% %
4243% %
4244% %
4245+ P e r s i s t P i x e l C a c h e %
4246% %
4247% %
4248% %
4249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4250%
4251% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4252% persistent pixel cache is one that resides on disk and is not destroyed
4253% when the program exits.
4254%
4255% The format of the PersistPixelCache() method is:
4256%
4257% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4258% const MagickBooleanType attach,MagickOffsetType *offset,
4259% ExceptionInfo *exception)
4260%
4261% A description of each parameter follows:
4262%
4263% o image: the image.
4264%
4265% o filename: the persistent pixel cache filename.
4266%
cristyf3a6a9d2010-11-07 21:02:56 +00004267% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004268%
cristy3ed852e2009-09-05 21:47:34 +00004269% o initialize: A value other than zero initializes the persistent pixel
4270% cache.
4271%
4272% o offset: the offset in the persistent cache to store pixels.
4273%
4274% o exception: return any errors or warnings in this structure.
4275%
4276*/
4277MagickExport MagickBooleanType PersistPixelCache(Image *image,
4278 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4279 ExceptionInfo *exception)
4280{
4281 CacheInfo
4282 *cache_info,
4283 *clone_info;
4284
4285 Image
4286 clone_image;
4287
cristy3ed852e2009-09-05 21:47:34 +00004288 MagickBooleanType
4289 status;
4290
cristye076a6e2010-08-15 19:59:43 +00004291 ssize_t
4292 page_size;
4293
cristy3ed852e2009-09-05 21:47:34 +00004294 assert(image != (Image *) NULL);
4295 assert(image->signature == MagickSignature);
4296 if (image->debug != MagickFalse)
4297 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4298 assert(image->cache != (void *) NULL);
4299 assert(filename != (const char *) NULL);
4300 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004301 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004302 cache_info=(CacheInfo *) image->cache;
4303 assert(cache_info->signature == MagickSignature);
4304 if (attach != MagickFalse)
4305 {
4306 /*
cristy01b7eb02009-09-10 23:10:14 +00004307 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004308 */
4309 if (image->debug != MagickFalse)
4310 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004311 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004312 (void) CopyMagickString(cache_info->cache_filename,filename,
4313 MaxTextExtent);
4314 cache_info->type=DiskCache;
4315 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004316 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004317 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004318 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004319 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004320 }
cristy01b7eb02009-09-10 23:10:14 +00004321 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4322 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004323 {
cristyf84a1932010-01-03 18:00:18 +00004324 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004325 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004326 (cache_info->reference_count == 1))
4327 {
4328 int
4329 status;
4330
4331 /*
cristy01b7eb02009-09-10 23:10:14 +00004332 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004333 */
cristy320684d2011-09-23 14:55:47 +00004334 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004335 if (status == 0)
4336 {
4337 (void) CopyMagickString(cache_info->cache_filename,filename,
4338 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004339 *offset+=cache_info->length+page_size-(cache_info->length %
4340 page_size);
cristyf84a1932010-01-03 18:00:18 +00004341 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004342 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004343 if (image->debug != MagickFalse)
4344 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4345 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004346 return(MagickTrue);
4347 }
4348 }
cristyf84a1932010-01-03 18:00:18 +00004349 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004350 }
4351 /*
cristy01b7eb02009-09-10 23:10:14 +00004352 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004353 */
4354 clone_image=(*image);
4355 clone_info=(CacheInfo *) clone_image.cache;
4356 image->cache=ClonePixelCache(cache_info);
4357 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4358 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4359 cache_info->type=DiskCache;
4360 cache_info->offset=(*offset);
4361 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004362 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004363 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004364 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004365 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004366 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4367 return(status);
4368}
4369
4370/*
4371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4372% %
4373% %
4374% %
4375+ Q u e u e A u t h e n t i c N e x u s %
4376% %
4377% %
4378% %
4379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4380%
4381% QueueAuthenticNexus() allocates an region to store image pixels as defined
4382% by the region rectangle and returns a pointer to the region. This region is
4383% subsequently transferred from the pixel cache with
4384% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4385% pixels are transferred, otherwise a NULL is returned.
4386%
4387% The format of the QueueAuthenticNexus() method is:
4388%
cristy4c08aed2011-07-01 19:47:50 +00004389% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004390% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004391% const MagickBooleanType clone,NexusInfo *nexus_info,
4392% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004393%
4394% A description of each parameter follows:
4395%
4396% o image: the image.
4397%
4398% o x,y,columns,rows: These values define the perimeter of a region of
4399% pixels.
4400%
4401% o nexus_info: the cache nexus to set.
4402%
cristy65dbf172011-10-06 17:32:04 +00004403% o clone: clone the pixel cache.
4404%
cristy3ed852e2009-09-05 21:47:34 +00004405% o exception: return any errors or warnings in this structure.
4406%
4407*/
cristya6577ff2011-09-02 19:54:26 +00004408MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004409 const ssize_t y,const size_t columns,const size_t rows,
4410 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004411{
4412 CacheInfo
4413 *cache_info;
4414
4415 MagickOffsetType
4416 offset;
4417
4418 MagickSizeType
4419 number_pixels;
4420
4421 RectangleInfo
4422 region;
4423
4424 /*
4425 Validate pixel cache geometry.
4426 */
cristye7cc7cf2010-09-21 13:26:47 +00004427 assert(image != (const Image *) NULL);
4428 assert(image->signature == MagickSignature);
4429 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004430 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004431 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004432 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004433 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004434 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4435 {
4436 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4437 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004438 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004439 }
cristybb503372010-05-27 20:51:26 +00004440 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4441 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004442 {
4443 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4444 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004445 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004446 }
4447 offset=(MagickOffsetType) y*cache_info->columns+x;
4448 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004449 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004450 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4451 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4452 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004453 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004454 /*
4455 Return pixel cache.
4456 */
4457 region.x=x;
4458 region.y=y;
4459 region.width=columns;
4460 region.height=rows;
4461 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4462}
4463
4464/*
4465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4466% %
4467% %
4468% %
4469+ 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 %
4470% %
4471% %
4472% %
4473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474%
4475% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4476% defined by the region rectangle and returns a pointer to the region. This
4477% region is subsequently transferred from the pixel cache with
4478% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4479% pixels are transferred, otherwise a NULL is returned.
4480%
4481% The format of the QueueAuthenticPixelsCache() method is:
4482%
cristy4c08aed2011-07-01 19:47:50 +00004483% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004484% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004485% ExceptionInfo *exception)
4486%
4487% A description of each parameter follows:
4488%
4489% o image: the image.
4490%
4491% o x,y,columns,rows: These values define the perimeter of a region of
4492% pixels.
4493%
4494% o exception: return any errors or warnings in this structure.
4495%
4496*/
cristy4c08aed2011-07-01 19:47:50 +00004497static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004498 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004499 ExceptionInfo *exception)
4500{
4501 CacheInfo
4502 *cache_info;
4503
cristy5c9e6f22010-09-17 17:31:01 +00004504 const int
4505 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004506
cristy4c08aed2011-07-01 19:47:50 +00004507 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004508 *q;
cristy4c08aed2011-07-01 19:47:50 +00004509
cristye7cc7cf2010-09-21 13:26:47 +00004510 assert(image != (const Image *) NULL);
4511 assert(image->signature == MagickSignature);
4512 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004513 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004514 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004515 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004516 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4517 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004518 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004519}
4520
4521/*
4522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4523% %
4524% %
4525% %
4526% Q u e u e A u t h e n t i c P i x e l s %
4527% %
4528% %
4529% %
4530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4531%
4532% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004533% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004534% region is returned, otherwise NULL is returned. The returned pointer may
4535% point to a temporary working buffer for the pixels or it may point to the
4536% final location of the pixels in memory.
4537%
4538% Write-only access means that any existing pixel values corresponding to
4539% the region are ignored. This is useful if the initial image is being
4540% created from scratch, or if the existing pixel values are to be
4541% completely replaced without need to refer to their pre-existing values.
4542% The application is free to read and write the pixel buffer returned by
4543% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4544% initialize the pixel array values. Initializing pixel array values is the
4545% application's responsibility.
4546%
4547% Performance is maximized if the selected region is part of one row, or
4548% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004549% pixels in-place (without a copy) if the image is in memory, or in a
4550% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004551% by the user.
4552%
4553% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004554% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4555% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4556% obtain the meta-content (of type void) corresponding to the region.
4557% Once the Quantum (and/or Quantum) array has been updated, the
4558% changes must be saved back to the underlying image using
4559% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004560%
4561% The format of the QueueAuthenticPixels() method is:
4562%
cristy4c08aed2011-07-01 19:47:50 +00004563% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004564% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004565% ExceptionInfo *exception)
4566%
4567% A description of each parameter follows:
4568%
4569% o image: the image.
4570%
4571% o x,y,columns,rows: These values define the perimeter of a region of
4572% pixels.
4573%
4574% o exception: return any errors or warnings in this structure.
4575%
4576*/
cristy4c08aed2011-07-01 19:47:50 +00004577MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004578 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004579 ExceptionInfo *exception)
4580{
4581 CacheInfo
4582 *cache_info;
4583
cristy2036f5c2010-09-19 21:18:17 +00004584 const int
4585 id = GetOpenMPThreadId();
4586
cristy4c08aed2011-07-01 19:47:50 +00004587 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004588 *q;
cristy4c08aed2011-07-01 19:47:50 +00004589
cristy3ed852e2009-09-05 21:47:34 +00004590 assert(image != (Image *) NULL);
4591 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004592 assert(image->cache != (Cache) NULL);
4593 cache_info=(CacheInfo *) image->cache;
4594 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004595 if (cache_info->methods.queue_authentic_pixels_handler !=
4596 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004597 {
cristyacd2ed22011-08-30 01:44:23 +00004598 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004599 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004600 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004601 }
cristy2036f5c2010-09-19 21:18:17 +00004602 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004603 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4604 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004605 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004606}
4607
4608/*
4609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4610% %
4611% %
4612% %
cristy4c08aed2011-07-01 19:47:50 +00004613+ 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 +00004614% %
4615% %
4616% %
4617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4618%
cristy4c08aed2011-07-01 19:47:50 +00004619% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004620% the pixel cache.
4621%
cristy4c08aed2011-07-01 19:47:50 +00004622% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004623%
cristy4c08aed2011-07-01 19:47:50 +00004624% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004625% NexusInfo *nexus_info,ExceptionInfo *exception)
4626%
4627% A description of each parameter follows:
4628%
4629% o cache_info: the pixel cache.
4630%
cristy4c08aed2011-07-01 19:47:50 +00004631% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004632%
4633% o exception: return any errors or warnings in this structure.
4634%
4635*/
cristy4c08aed2011-07-01 19:47:50 +00004636static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004637 NexusInfo *nexus_info,ExceptionInfo *exception)
4638{
4639 MagickOffsetType
4640 count,
4641 offset;
4642
4643 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004644 extent,
4645 length;
cristy3ed852e2009-09-05 21:47:34 +00004646
cristybb503372010-05-27 20:51:26 +00004647 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004648 y;
4649
cristy4c08aed2011-07-01 19:47:50 +00004650 register unsigned char
4651 *restrict q;
4652
cristybb503372010-05-27 20:51:26 +00004653 size_t
cristy3ed852e2009-09-05 21:47:34 +00004654 rows;
4655
cristy4c08aed2011-07-01 19:47:50 +00004656 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004657 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004658 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004659 return(MagickTrue);
4660 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4661 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004662 length=(MagickSizeType) nexus_info->region.width*
4663 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004664 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004665 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004666 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004667 switch (cache_info->type)
4668 {
4669 case MemoryCache:
4670 case MapCache:
4671 {
cristy4c08aed2011-07-01 19:47:50 +00004672 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004673 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004674
4675 /*
cristy4c08aed2011-07-01 19:47:50 +00004676 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004677 */
cristydd341db2010-03-04 19:06:38 +00004678 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004679 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004680 {
cristy48078b12010-09-23 17:11:01 +00004681 length=extent;
cristydd341db2010-03-04 19:06:38 +00004682 rows=1UL;
4683 }
cristy4c08aed2011-07-01 19:47:50 +00004684 p=(unsigned char *) cache_info->metacontent+offset*
4685 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004686 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004687 {
cristy8f036fe2010-09-18 02:02:00 +00004688 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004689 p+=cache_info->metacontent_extent*cache_info->columns;
4690 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004691 }
4692 break;
4693 }
4694 case DiskCache:
4695 {
4696 /*
cristy4c08aed2011-07-01 19:47:50 +00004697 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004698 */
4699 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4700 {
4701 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4702 cache_info->cache_filename);
4703 return(MagickFalse);
4704 }
cristydd341db2010-03-04 19:06:38 +00004705 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004706 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004707 {
cristy48078b12010-09-23 17:11:01 +00004708 length=extent;
cristydd341db2010-03-04 19:06:38 +00004709 rows=1UL;
4710 }
cristy48078b12010-09-23 17:11:01 +00004711 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004712 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004713 {
cristy48078b12010-09-23 17:11:01 +00004714 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004715 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004716 cache_info->metacontent_extent,length,(unsigned char *) q);
4717 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004718 break;
4719 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004720 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004721 }
cristybb503372010-05-27 20:51:26 +00004722 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004723 {
4724 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4725 cache_info->cache_filename);
4726 return(MagickFalse);
4727 }
4728 break;
4729 }
4730 default:
4731 break;
4732 }
4733 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004734 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004735 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004736 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004737 nexus_info->region.width,(double) nexus_info->region.height,(double)
4738 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004739 return(MagickTrue);
4740}
4741
4742/*
4743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4744% %
4745% %
4746% %
4747+ R e a d P i x e l C a c h e P i x e l s %
4748% %
4749% %
4750% %
4751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4752%
4753% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4754% cache.
4755%
4756% The format of the ReadPixelCachePixels() method is:
4757%
4758% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4759% NexusInfo *nexus_info,ExceptionInfo *exception)
4760%
4761% A description of each parameter follows:
4762%
4763% o cache_info: the pixel cache.
4764%
4765% o nexus_info: the cache nexus to read the pixels.
4766%
4767% o exception: return any errors or warnings in this structure.
4768%
4769*/
4770static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4771 NexusInfo *nexus_info,ExceptionInfo *exception)
4772{
4773 MagickOffsetType
4774 count,
4775 offset;
4776
4777 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004778 extent,
4779 length;
cristy3ed852e2009-09-05 21:47:34 +00004780
cristy4c08aed2011-07-01 19:47:50 +00004781 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004782 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004783
cristye076a6e2010-08-15 19:59:43 +00004784 register ssize_t
4785 y;
4786
cristybb503372010-05-27 20:51:26 +00004787 size_t
cristy3ed852e2009-09-05 21:47:34 +00004788 rows;
4789
cristy4c08aed2011-07-01 19:47:50 +00004790 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004791 return(MagickTrue);
4792 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4793 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004794 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004795 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004796 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004797 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004798 q=nexus_info->pixels;
4799 switch (cache_info->type)
4800 {
4801 case MemoryCache:
4802 case MapCache:
4803 {
cristy4c08aed2011-07-01 19:47:50 +00004804 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004805 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004806
4807 /*
4808 Read pixels from memory.
4809 */
cristydd341db2010-03-04 19:06:38 +00004810 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004811 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004812 {
cristy48078b12010-09-23 17:11:01 +00004813 length=extent;
cristydd341db2010-03-04 19:06:38 +00004814 rows=1UL;
4815 }
cristyed231572011-07-14 02:18:59 +00004816 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004817 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004818 {
cristy8f036fe2010-09-18 02:02:00 +00004819 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004820 p+=cache_info->number_channels*cache_info->columns;
4821 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004822 }
4823 break;
4824 }
4825 case DiskCache:
4826 {
4827 /*
4828 Read pixels from disk.
4829 */
4830 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4831 {
4832 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4833 cache_info->cache_filename);
4834 return(MagickFalse);
4835 }
cristydd341db2010-03-04 19:06:38 +00004836 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004837 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004838 {
cristy48078b12010-09-23 17:11:01 +00004839 length=extent;
cristydd341db2010-03-04 19:06:38 +00004840 rows=1UL;
4841 }
cristybb503372010-05-27 20:51:26 +00004842 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004843 {
4844 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004845 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004846 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004847 break;
4848 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004849 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004850 }
cristybb503372010-05-27 20:51:26 +00004851 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004852 {
4853 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4854 cache_info->cache_filename);
4855 return(MagickFalse);
4856 }
4857 break;
4858 }
4859 default:
4860 break;
4861 }
4862 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004863 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004864 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004865 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004866 nexus_info->region.width,(double) nexus_info->region.height,(double)
4867 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004868 return(MagickTrue);
4869}
4870
4871/*
4872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4873% %
4874% %
4875% %
4876+ R e f e r e n c e P i x e l C a c h e %
4877% %
4878% %
4879% %
4880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4881%
4882% ReferencePixelCache() increments the reference count associated with the
4883% pixel cache returning a pointer to the cache.
4884%
4885% The format of the ReferencePixelCache method is:
4886%
4887% Cache ReferencePixelCache(Cache cache_info)
4888%
4889% A description of each parameter follows:
4890%
4891% o cache_info: the pixel cache.
4892%
4893*/
cristya6577ff2011-09-02 19:54:26 +00004894MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004895{
4896 CacheInfo
4897 *cache_info;
4898
4899 assert(cache != (Cache *) NULL);
4900 cache_info=(CacheInfo *) cache;
4901 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004902 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004903 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004904 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004905 return(cache_info);
4906}
4907
4908/*
4909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4910% %
4911% %
4912% %
4913+ S e t P i x e l C a c h e M e t h o d s %
4914% %
4915% %
4916% %
4917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4918%
4919% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4920%
4921% The format of the SetPixelCacheMethods() method is:
4922%
4923% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4924%
4925% A description of each parameter follows:
4926%
4927% o cache: the pixel cache.
4928%
4929% o cache_methods: Specifies a pointer to a CacheMethods structure.
4930%
4931*/
cristya6577ff2011-09-02 19:54:26 +00004932MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004933{
4934 CacheInfo
4935 *cache_info;
4936
4937 GetOneAuthenticPixelFromHandler
4938 get_one_authentic_pixel_from_handler;
4939
4940 GetOneVirtualPixelFromHandler
4941 get_one_virtual_pixel_from_handler;
4942
4943 /*
4944 Set cache pixel methods.
4945 */
4946 assert(cache != (Cache) NULL);
4947 assert(cache_methods != (CacheMethods *) NULL);
4948 cache_info=(CacheInfo *) cache;
4949 assert(cache_info->signature == MagickSignature);
4950 if (cache_info->debug != MagickFalse)
4951 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4952 cache_info->filename);
4953 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4954 cache_info->methods.get_virtual_pixel_handler=
4955 cache_methods->get_virtual_pixel_handler;
4956 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4957 cache_info->methods.destroy_pixel_handler=
4958 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004959 if (cache_methods->get_virtual_metacontent_from_handler !=
4960 (GetVirtualMetacontentFromHandler) NULL)
4961 cache_info->methods.get_virtual_metacontent_from_handler=
4962 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004963 if (cache_methods->get_authentic_pixels_handler !=
4964 (GetAuthenticPixelsHandler) NULL)
4965 cache_info->methods.get_authentic_pixels_handler=
4966 cache_methods->get_authentic_pixels_handler;
4967 if (cache_methods->queue_authentic_pixels_handler !=
4968 (QueueAuthenticPixelsHandler) NULL)
4969 cache_info->methods.queue_authentic_pixels_handler=
4970 cache_methods->queue_authentic_pixels_handler;
4971 if (cache_methods->sync_authentic_pixels_handler !=
4972 (SyncAuthenticPixelsHandler) NULL)
4973 cache_info->methods.sync_authentic_pixels_handler=
4974 cache_methods->sync_authentic_pixels_handler;
4975 if (cache_methods->get_authentic_pixels_from_handler !=
4976 (GetAuthenticPixelsFromHandler) NULL)
4977 cache_info->methods.get_authentic_pixels_from_handler=
4978 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004979 if (cache_methods->get_authentic_metacontent_from_handler !=
4980 (GetAuthenticMetacontentFromHandler) NULL)
4981 cache_info->methods.get_authentic_metacontent_from_handler=
4982 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004983 get_one_virtual_pixel_from_handler=
4984 cache_info->methods.get_one_virtual_pixel_from_handler;
4985 if (get_one_virtual_pixel_from_handler !=
4986 (GetOneVirtualPixelFromHandler) NULL)
4987 cache_info->methods.get_one_virtual_pixel_from_handler=
4988 cache_methods->get_one_virtual_pixel_from_handler;
4989 get_one_authentic_pixel_from_handler=
4990 cache_methods->get_one_authentic_pixel_from_handler;
4991 if (get_one_authentic_pixel_from_handler !=
4992 (GetOneAuthenticPixelFromHandler) NULL)
4993 cache_info->methods.get_one_authentic_pixel_from_handler=
4994 cache_methods->get_one_authentic_pixel_from_handler;
4995}
4996
4997/*
4998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4999% %
5000% %
5001% %
5002+ S e t P i x e l C a c h e N e x u s P i x e l s %
5003% %
5004% %
5005% %
5006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5007%
5008% SetPixelCacheNexusPixels() defines the region of the cache for the
5009% specified cache nexus.
5010%
5011% The format of the SetPixelCacheNexusPixels() method is:
5012%
cristy4c08aed2011-07-01 19:47:50 +00005013% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005014% const RectangleInfo *region,NexusInfo *nexus_info,
5015% ExceptionInfo *exception)
5016%
5017% A description of each parameter follows:
5018%
5019% o image: the image.
5020%
5021% o region: A pointer to the RectangleInfo structure that defines the
5022% region of this particular cache nexus.
5023%
5024% o nexus_info: the cache nexus to set.
5025%
5026% o exception: return any errors or warnings in this structure.
5027%
5028*/
cristyabd6e372010-09-15 19:11:26 +00005029
5030static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5031 NexusInfo *nexus_info,ExceptionInfo *exception)
5032{
5033 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5034 return(MagickFalse);
5035 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005036 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005037 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005038 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005039 {
5040 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005041 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005042 nexus_info->length);
5043 }
cristy4c08aed2011-07-01 19:47:50 +00005044 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005045 {
5046 (void) ThrowMagickException(exception,GetMagickModule(),
5047 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5048 cache_info->filename);
5049 return(MagickFalse);
5050 }
5051 return(MagickTrue);
5052}
5053
cristy4c08aed2011-07-01 19:47:50 +00005054static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005055 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5056{
5057 CacheInfo
5058 *cache_info;
5059
5060 MagickBooleanType
5061 status;
5062
cristy3ed852e2009-09-05 21:47:34 +00005063 MagickSizeType
5064 length,
5065 number_pixels;
5066
cristy3ed852e2009-09-05 21:47:34 +00005067 cache_info=(CacheInfo *) image->cache;
5068 assert(cache_info->signature == MagickSignature);
5069 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005070 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005071 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005072 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5073 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005074 {
cristybb503372010-05-27 20:51:26 +00005075 ssize_t
cristybad067a2010-02-15 17:20:55 +00005076 x,
5077 y;
cristy3ed852e2009-09-05 21:47:34 +00005078
cristyeaedf062010-05-29 22:36:02 +00005079 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5080 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005081 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5082 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005083 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005084 ((nexus_info->region.width == cache_info->columns) ||
5085 ((nexus_info->region.width % cache_info->columns) == 0)))))
5086 {
5087 MagickOffsetType
5088 offset;
5089
5090 /*
5091 Pixels are accessed directly from memory.
5092 */
5093 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5094 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005095 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005096 offset;
5097 nexus_info->metacontent=(void *) NULL;
5098 if (cache_info->metacontent_extent != 0)
5099 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5100 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005101 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005102 }
5103 }
5104 /*
5105 Pixels are stored in a cache region until they are synced to the cache.
5106 */
5107 number_pixels=(MagickSizeType) nexus_info->region.width*
5108 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005109 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005110 if (cache_info->metacontent_extent != 0)
5111 length+=number_pixels*cache_info->metacontent_extent;
5112 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005113 {
5114 nexus_info->length=length;
5115 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5116 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005117 {
5118 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005119 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005120 }
cristy3ed852e2009-09-05 21:47:34 +00005121 }
5122 else
5123 if (nexus_info->length != length)
5124 {
5125 RelinquishCacheNexusPixels(nexus_info);
5126 nexus_info->length=length;
5127 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5128 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005129 {
5130 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005131 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005132 }
cristy3ed852e2009-09-05 21:47:34 +00005133 }
5134 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005135 nexus_info->metacontent=(void *) NULL;
5136 if (cache_info->metacontent_extent != 0)
5137 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005138 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005139 return(nexus_info->pixels);
5140}
5141
5142/*
5143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5144% %
5145% %
5146% %
5147% 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 %
5148% %
5149% %
5150% %
5151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152%
5153% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5154% pixel cache and returns the previous setting. A virtual pixel is any pixel
5155% access that is outside the boundaries of the image cache.
5156%
5157% The format of the SetPixelCacheVirtualMethod() method is:
5158%
5159% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5160% const VirtualPixelMethod virtual_pixel_method)
5161%
5162% A description of each parameter follows:
5163%
5164% o image: the image.
5165%
5166% o virtual_pixel_method: choose the type of virtual pixel.
5167%
5168*/
cristyd1dd6e42011-09-04 01:46:08 +00005169MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005170 const VirtualPixelMethod virtual_pixel_method)
5171{
5172 CacheInfo
5173 *cache_info;
5174
5175 VirtualPixelMethod
5176 method;
5177
5178 assert(image != (Image *) NULL);
5179 assert(image->signature == MagickSignature);
5180 if (image->debug != MagickFalse)
5181 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5182 assert(image->cache != (Cache) NULL);
5183 cache_info=(CacheInfo *) image->cache;
5184 assert(cache_info->signature == MagickSignature);
5185 method=cache_info->virtual_pixel_method;
5186 cache_info->virtual_pixel_method=virtual_pixel_method;
5187 return(method);
5188}
5189
5190/*
5191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5192% %
5193% %
5194% %
5195+ 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 %
5196% %
5197% %
5198% %
5199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5200%
5201% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5202% in-memory or disk cache. The method returns MagickTrue if the pixel region
5203% is synced, otherwise MagickFalse.
5204%
5205% The format of the SyncAuthenticPixelCacheNexus() method is:
5206%
5207% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5208% NexusInfo *nexus_info,ExceptionInfo *exception)
5209%
5210% A description of each parameter follows:
5211%
5212% o image: the image.
5213%
5214% o nexus_info: the cache nexus to sync.
5215%
5216% o exception: return any errors or warnings in this structure.
5217%
5218*/
cristya6577ff2011-09-02 19:54:26 +00005219MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005220 NexusInfo *nexus_info,ExceptionInfo *exception)
5221{
5222 CacheInfo
5223 *cache_info;
5224
5225 MagickBooleanType
5226 status;
5227
5228 /*
5229 Transfer pixels to the cache.
5230 */
5231 assert(image != (Image *) NULL);
5232 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005233 if (image->cache == (Cache) NULL)
5234 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5235 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005236 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005237 if (cache_info->type == UndefinedCache)
5238 return(MagickFalse);
5239 if ((image->clip_mask != (Image *) NULL) &&
5240 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5241 return(MagickFalse);
5242 if ((image->mask != (Image *) NULL) &&
5243 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5244 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005245 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005246 return(MagickTrue);
5247 assert(cache_info->signature == MagickSignature);
5248 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005249 if ((cache_info->metacontent_extent != 0) &&
5250 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005251 return(MagickFalse);
5252 return(status);
5253}
5254
5255/*
5256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5257% %
5258% %
5259% %
5260+ S y n c A u t h e n t i c P i x e l C a c h e %
5261% %
5262% %
5263% %
5264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5265%
5266% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5267% or disk cache. The method returns MagickTrue if the pixel region is synced,
5268% otherwise MagickFalse.
5269%
5270% The format of the SyncAuthenticPixelsCache() method is:
5271%
5272% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5273% ExceptionInfo *exception)
5274%
5275% A description of each parameter follows:
5276%
5277% o image: the image.
5278%
5279% o exception: return any errors or warnings in this structure.
5280%
5281*/
5282static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5283 ExceptionInfo *exception)
5284{
5285 CacheInfo
5286 *cache_info;
5287
cristy5c9e6f22010-09-17 17:31:01 +00005288 const int
5289 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005290
cristy4c08aed2011-07-01 19:47:50 +00005291 MagickBooleanType
5292 status;
5293
cristye7cc7cf2010-09-21 13:26:47 +00005294 assert(image != (Image *) NULL);
5295 assert(image->signature == MagickSignature);
5296 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005297 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005298 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005299 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005300 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5301 exception);
5302 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005303}
5304
5305/*
5306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5307% %
5308% %
5309% %
5310% S y n c A u t h e n t i c P i x e l s %
5311% %
5312% %
5313% %
5314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315%
5316% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5317% The method returns MagickTrue if the pixel region is flushed, otherwise
5318% MagickFalse.
5319%
5320% The format of the SyncAuthenticPixels() method is:
5321%
5322% MagickBooleanType SyncAuthenticPixels(Image *image,
5323% ExceptionInfo *exception)
5324%
5325% A description of each parameter follows:
5326%
5327% o image: the image.
5328%
5329% o exception: return any errors or warnings in this structure.
5330%
5331*/
5332MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5333 ExceptionInfo *exception)
5334{
5335 CacheInfo
5336 *cache_info;
5337
cristy2036f5c2010-09-19 21:18:17 +00005338 const int
5339 id = GetOpenMPThreadId();
5340
cristy4c08aed2011-07-01 19:47:50 +00005341 MagickBooleanType
5342 status;
5343
cristy3ed852e2009-09-05 21:47:34 +00005344 assert(image != (Image *) NULL);
5345 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005346 assert(image->cache != (Cache) NULL);
5347 cache_info=(CacheInfo *) image->cache;
5348 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005349 if (cache_info->methods.sync_authentic_pixels_handler !=
5350 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005351 {
5352 status=cache_info->methods.sync_authentic_pixels_handler(image,
5353 exception);
5354 return(status);
5355 }
cristy2036f5c2010-09-19 21:18:17 +00005356 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005357 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5358 exception);
5359 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005360}
5361
5362/*
5363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5364% %
5365% %
5366% %
cristyd1dd6e42011-09-04 01:46:08 +00005367+ 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 +00005368% %
5369% %
5370% %
5371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5372%
5373% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5374% The method returns MagickTrue if the pixel region is flushed, otherwise
5375% MagickFalse.
5376%
5377% The format of the SyncImagePixelCache() method is:
5378%
5379% MagickBooleanType SyncImagePixelCache(Image *image,
5380% ExceptionInfo *exception)
5381%
5382% A description of each parameter follows:
5383%
5384% o image: the image.
5385%
5386% o exception: return any errors or warnings in this structure.
5387%
5388*/
cristyd1dd6e42011-09-04 01:46:08 +00005389MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005390 ExceptionInfo *exception)
5391{
5392 CacheInfo
5393 *cache_info;
5394
5395 assert(image != (Image *) NULL);
5396 assert(exception != (ExceptionInfo *) NULL);
5397 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5398 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5399}
5400
5401/*
5402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5403% %
5404% %
5405% %
cristy4c08aed2011-07-01 19:47:50 +00005406+ 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 +00005407% %
5408% %
5409% %
5410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5411%
cristy4c08aed2011-07-01 19:47:50 +00005412% WritePixelCacheMetacontent() writes the meta-content to the specified region
5413% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005414%
cristy4c08aed2011-07-01 19:47:50 +00005415% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005416%
cristy4c08aed2011-07-01 19:47:50 +00005417% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005418% NexusInfo *nexus_info,ExceptionInfo *exception)
5419%
5420% A description of each parameter follows:
5421%
5422% o cache_info: the pixel cache.
5423%
cristy4c08aed2011-07-01 19:47:50 +00005424% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005425%
5426% o exception: return any errors or warnings in this structure.
5427%
5428*/
cristy4c08aed2011-07-01 19:47:50 +00005429static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005430 NexusInfo *nexus_info,ExceptionInfo *exception)
5431{
5432 MagickOffsetType
5433 count,
5434 offset;
5435
5436 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005437 extent,
5438 length;
cristy3ed852e2009-09-05 21:47:34 +00005439
cristy4c08aed2011-07-01 19:47:50 +00005440 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005441 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005442
cristybb503372010-05-27 20:51:26 +00005443 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005444 y;
5445
cristybb503372010-05-27 20:51:26 +00005446 size_t
cristy3ed852e2009-09-05 21:47:34 +00005447 rows;
5448
cristy4c08aed2011-07-01 19:47:50 +00005449 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005450 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005451 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005452 return(MagickTrue);
5453 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5454 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005455 length=(MagickSizeType) nexus_info->region.width*
5456 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005457 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005458 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005459 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005460 switch (cache_info->type)
5461 {
5462 case MemoryCache:
5463 case MapCache:
5464 {
cristy4c08aed2011-07-01 19:47:50 +00005465 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005466 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005467
5468 /*
cristy4c08aed2011-07-01 19:47:50 +00005469 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005470 */
cristydd341db2010-03-04 19:06:38 +00005471 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005472 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005473 {
cristy48078b12010-09-23 17:11:01 +00005474 length=extent;
cristydd341db2010-03-04 19:06:38 +00005475 rows=1UL;
5476 }
cristy4c08aed2011-07-01 19:47:50 +00005477 q=(unsigned char *) cache_info->metacontent+offset*
5478 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005479 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005480 {
cristy8f036fe2010-09-18 02:02:00 +00005481 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005482 p+=nexus_info->region.width*cache_info->metacontent_extent;
5483 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005484 }
5485 break;
5486 }
5487 case DiskCache:
5488 {
5489 /*
cristy4c08aed2011-07-01 19:47:50 +00005490 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005491 */
5492 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5493 {
5494 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5495 cache_info->cache_filename);
5496 return(MagickFalse);
5497 }
cristydd341db2010-03-04 19:06:38 +00005498 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005499 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005500 {
cristy48078b12010-09-23 17:11:01 +00005501 length=extent;
cristydd341db2010-03-04 19:06:38 +00005502 rows=1UL;
5503 }
cristy48078b12010-09-23 17:11:01 +00005504 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005505 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005506 {
cristy48078b12010-09-23 17:11:01 +00005507 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005508 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005509 cache_info->metacontent_extent,length,(const unsigned char *) p);
5510 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005511 break;
cristy4c08aed2011-07-01 19:47:50 +00005512 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005513 offset+=cache_info->columns;
5514 }
cristybb503372010-05-27 20:51:26 +00005515 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005516 {
5517 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5518 cache_info->cache_filename);
5519 return(MagickFalse);
5520 }
5521 break;
5522 }
5523 default:
5524 break;
5525 }
5526 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005527 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005528 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005529 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005530 nexus_info->region.width,(double) nexus_info->region.height,(double)
5531 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005532 return(MagickTrue);
5533}
5534
5535/*
5536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5537% %
5538% %
5539% %
5540+ W r i t e C a c h e P i x e l s %
5541% %
5542% %
5543% %
5544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5545%
5546% WritePixelCachePixels() writes image pixels to the specified region of the
5547% pixel cache.
5548%
5549% The format of the WritePixelCachePixels() method is:
5550%
5551% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5552% NexusInfo *nexus_info,ExceptionInfo *exception)
5553%
5554% A description of each parameter follows:
5555%
5556% o cache_info: the pixel cache.
5557%
5558% o nexus_info: the cache nexus to write the pixels.
5559%
5560% o exception: return any errors or warnings in this structure.
5561%
5562*/
5563static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5564 NexusInfo *nexus_info,ExceptionInfo *exception)
5565{
5566 MagickOffsetType
5567 count,
5568 offset;
5569
5570 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005571 extent,
5572 length;
cristy3ed852e2009-09-05 21:47:34 +00005573
cristy4c08aed2011-07-01 19:47:50 +00005574 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005575 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005576
cristybb503372010-05-27 20:51:26 +00005577 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005578 y;
5579
cristybb503372010-05-27 20:51:26 +00005580 size_t
cristy3ed852e2009-09-05 21:47:34 +00005581 rows;
5582
cristy4c08aed2011-07-01 19:47:50 +00005583 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005584 return(MagickTrue);
5585 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5586 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005587 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005588 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005589 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005590 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005591 p=nexus_info->pixels;
5592 switch (cache_info->type)
5593 {
5594 case MemoryCache:
5595 case MapCache:
5596 {
cristy4c08aed2011-07-01 19:47:50 +00005597 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005598 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005599
5600 /*
5601 Write pixels to memory.
5602 */
cristydd341db2010-03-04 19:06:38 +00005603 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005604 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005605 {
cristy48078b12010-09-23 17:11:01 +00005606 length=extent;
cristydd341db2010-03-04 19:06:38 +00005607 rows=1UL;
5608 }
cristyed231572011-07-14 02:18:59 +00005609 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005610 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005611 {
cristy8f036fe2010-09-18 02:02:00 +00005612 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005613 p+=nexus_info->region.width*cache_info->number_channels;
5614 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005615 }
5616 break;
5617 }
5618 case DiskCache:
5619 {
5620 /*
5621 Write pixels to disk.
5622 */
5623 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5624 {
5625 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5626 cache_info->cache_filename);
5627 return(MagickFalse);
5628 }
cristydd341db2010-03-04 19:06:38 +00005629 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005630 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005631 {
cristy48078b12010-09-23 17:11:01 +00005632 length=extent;
cristydd341db2010-03-04 19:06:38 +00005633 rows=1UL;
5634 }
cristybb503372010-05-27 20:51:26 +00005635 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005636 {
5637 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005638 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005639 p);
5640 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005641 break;
cristyed231572011-07-14 02:18:59 +00005642 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005643 offset+=cache_info->columns;
5644 }
cristybb503372010-05-27 20:51:26 +00005645 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005646 {
5647 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5648 cache_info->cache_filename);
5649 return(MagickFalse);
5650 }
5651 break;
5652 }
5653 default:
5654 break;
5655 }
5656 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005657 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005658 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005659 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005660 nexus_info->region.width,(double) nexus_info->region.height,(double)
5661 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005662 return(MagickTrue);
5663}