blob: f591a1fde21c2bfeac54c462b816dcca44e9e5b5 [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
cristy4c08aed2011-07-01 19:47:50 +0000840static MagickBooleanType OptimizedPixelCacheClone(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
cristy4c08aed2011-07-01 19:47:50 +0000911static MagickBooleanType UnoptimizedPixelCacheClone(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
cristycacc77e2011-12-31 17:20:21 +0000922 Quantum
923 sans;
924
cristy4c08aed2011-07-01 19:47:50 +0000925 register ssize_t
926 x;
927
928 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 }
cristyd2cb5a92011-12-31 20:10:15 +0000978if (0)
cristy4d9c1922011-12-31 18:37:34 +0000979 if ((cache_info->type != MemoryCache) && (clone_info->type != MemoryCache) &&
980 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
981 {
982 /*
983 Inplace cloning not reliable.
984 */
985 (void) ClosePixelCacheOnDisk(clone_info);
986 if (cache_info->type == MapCache)
987 {
988 clone_info->pixels=(Quantum *) UnmapBlob(clone_info->pixels,(size_t)
989 clone_info->length);
990 RelinquishMagickResource(MapResource,clone_info->length);
991 }
992 *clone_info->cache_filename='\0';
993 clone_info->type=DiskCache;
994 }
cristy4c08aed2011-07-01 19:47:50 +0000995 if (clone_info->type == DiskCache)
996 {
cristy3dedf062011-07-02 14:07:40 +0000997 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
cristy4c08aed2011-07-01 19:47:50 +0000999 if (cache_info->type == DiskCache)
1000 (void) ClosePixelCacheOnDisk(cache_info);
1001 blob=(unsigned char *) RelinquishMagickMemory(blob);
1002 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1003 clone_info->cache_filename);
1004 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001005 }
cristy4c08aed2011-07-01 19:47:50 +00001006 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +00001007 }
1008 /*
cristy4c08aed2011-07-01 19:47:50 +00001009 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001010 */
cristycacc77e2011-12-31 17:20:21 +00001011 sans=0;
cristy4c08aed2011-07-01 19:47:50 +00001012 status=MagickTrue;
1013 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001014 {
cristy4c08aed2011-07-01 19:47:50 +00001015 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001016 {
cristy9e0719b2011-12-29 03:45:45 +00001017 register ssize_t
1018 i;
1019
cristy3ed852e2009-09-05 21:47:34 +00001020 /*
cristy4c08aed2011-07-01 19:47:50 +00001021 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001022 */
cristyed231572011-07-14 02:18:59 +00001023 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001024 if (cache_info->type != DiskCache)
1025 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1026 length);
cristy3ed852e2009-09-05 21:47:34 +00001027 else
1028 {
cristy4c08aed2011-07-01 19:47:50 +00001029 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1030 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001031 {
cristy4c08aed2011-07-01 19:47:50 +00001032 status=MagickFalse;
1033 break;
cristy3ed852e2009-09-05 21:47:34 +00001034 }
1035 }
cristy4c08aed2011-07-01 19:47:50 +00001036 cache_offset+=length;
1037 if ((y < (ssize_t) clone_info->rows) &&
1038 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +00001039 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001040 {
cristy9e0719b2011-12-29 03:45:45 +00001041 PixelChannel
1042 channel;
1043
1044 PixelTrait
1045 traits;
1046
1047 ssize_t
1048 offset;
1049
cristy4c08aed2011-07-01 19:47:50 +00001050 /*
cristy3b8fe922011-12-29 18:56:23 +00001051 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +00001052 */
cristy9e0719b2011-12-29 03:45:45 +00001053 channel=clone_info->channel_map[i].channel;
1054 traits=cache_info->channel_map[channel].traits;
1055 if (traits == UndefinedPixelTrait)
1056 {
cristycacc77e2011-12-31 17:20:21 +00001057 if (clone_info->type != DiskCache)
1058 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1059 (unsigned char *) &sans,sizeof(Quantum));
1060 else
1061 {
1062 count=WritePixelCacheRegion(clone_info,clone_offset,
1063 sizeof(Quantum),(unsigned char *) &sans);
1064 if ((MagickSizeType) count != sizeof(Quantum))
1065 {
1066 status=MagickFalse;
1067 break;
1068 }
1069 }
cristy9e0719b2011-12-29 03:45:45 +00001070 }
cristy4c08aed2011-07-01 19:47:50 +00001071 else
1072 {
cristycacc77e2011-12-31 17:20:21 +00001073 offset=cache_info->channel_map[channel].offset;
1074 if (clone_info->type != DiskCache)
1075 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1076 blob+offset*sizeof(Quantum),sizeof(Quantum));
1077 else
cristy4c08aed2011-07-01 19:47:50 +00001078 {
cristycacc77e2011-12-31 17:20:21 +00001079 count=WritePixelCacheRegion(clone_info,clone_offset,
1080 sizeof(Quantum),blob+offset*sizeof(Quantum));
1081 if ((MagickSizeType) count != sizeof(Quantum))
1082 {
1083 status=MagickFalse;
1084 break;
1085 }
cristy4c08aed2011-07-01 19:47:50 +00001086 }
1087 }
cristy9e0719b2011-12-29 03:45:45 +00001088 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00001089 }
1090 }
cristyed231572011-07-14 02:18:59 +00001091 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001092 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1093 for ( ; x < (ssize_t) clone_info->columns; x++)
1094 {
1095 /*
cristy9e0719b2011-12-29 03:45:45 +00001096 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001097 */
1098 if (clone_info->type != DiskCache)
1099 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1100 length);
1101 else
1102 {
1103 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1104 if ((MagickSizeType) count != length)
1105 {
1106 status=MagickFalse;
1107 break;
1108 }
1109 }
1110 clone_offset+=length;
1111 }
1112 }
cristyed231572011-07-14 02:18:59 +00001113 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001114 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1115 for ( ; y < (ssize_t) clone_info->rows; y++)
1116 {
1117 /*
cristy9e0719b2011-12-29 03:45:45 +00001118 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001119 */
1120 for (x=0; x < (ssize_t) clone_info->columns; x++)
1121 {
1122 if (clone_info->type != DiskCache)
1123 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1124 length);
1125 else
1126 {
1127 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1128 if ((MagickSizeType) count != length)
1129 {
1130 status=MagickFalse;
1131 break;
1132 }
1133 }
1134 clone_offset+=length;
1135 }
1136 }
cristy9e0719b2011-12-29 03:45:45 +00001137 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001138 (clone_info->metacontent_extent != 0))
1139 {
1140 /*
1141 Clone metacontent.
1142 */
1143 for (y=0; y < (ssize_t) cache_info->rows; y++)
1144 {
1145 for (x=0; x < (ssize_t) cache_info->columns; x++)
1146 {
1147 /*
1148 Read a set of metacontent.
1149 */
1150 length=cache_info->metacontent_extent;
1151 if (cache_info->type != DiskCache)
1152 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1153 cache_offset,length);
1154 else
1155 {
1156 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1157 if ((MagickSizeType) count != length)
1158 {
1159 status=MagickFalse;
1160 break;
1161 }
1162 }
1163 cache_offset+=length;
1164 if ((y < (ssize_t) clone_info->rows) &&
1165 (x < (ssize_t) clone_info->columns))
1166 {
1167 /*
1168 Write a set of metacontent.
1169 */
1170 length=clone_info->metacontent_extent;
1171 if (clone_info->type != DiskCache)
1172 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1173 blob,length);
1174 else
1175 {
1176 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1177 blob);
1178 if ((MagickSizeType) count != length)
1179 {
1180 status=MagickFalse;
1181 break;
1182 }
1183 }
1184 clone_offset+=length;
1185 }
1186 }
1187 length=clone_info->metacontent_extent;
1188 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1189 for ( ; x < (ssize_t) clone_info->columns; x++)
1190 {
1191 /*
cristy9e0719b2011-12-29 03:45:45 +00001192 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001193 */
1194 if (clone_info->type != DiskCache)
1195 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1196 blob,length);
1197 else
1198 {
cristy208b1002011-08-07 18:51:50 +00001199 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001200 if ((MagickSizeType) count != length)
1201 {
1202 status=MagickFalse;
1203 break;
1204 }
1205 }
1206 clone_offset+=length;
1207 }
1208 }
1209 length=clone_info->metacontent_extent;
1210 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1211 for ( ; y < (ssize_t) clone_info->rows; y++)
1212 {
1213 /*
cristy9e0719b2011-12-29 03:45:45 +00001214 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001215 */
1216 for (x=0; x < (ssize_t) clone_info->columns; x++)
1217 {
1218 if (clone_info->type != DiskCache)
1219 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1220 blob,length);
1221 else
1222 {
1223 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1224 if ((MagickSizeType) count != length)
1225 {
1226 status=MagickFalse;
1227 break;
1228 }
1229 }
1230 clone_offset+=length;
1231 }
1232 }
1233 }
1234 if (clone_info->type == DiskCache)
1235 (void) ClosePixelCacheOnDisk(clone_info);
1236 if (cache_info->type == DiskCache)
1237 (void) ClosePixelCacheOnDisk(cache_info);
1238 blob=(unsigned char *) RelinquishMagickMemory(blob);
1239 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001240}
1241
1242static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1243 CacheInfo *cache_info,ExceptionInfo *exception)
1244{
cristy3dfccb22011-12-28 21:47:20 +00001245 PixelChannelMap
1246 *p,
1247 *q;
1248
cristy5a7fbfb2010-11-06 16:10:59 +00001249 if (cache_info->type == PingCache)
1250 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001251 p=cache_info->channel_map;
1252 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001253 if ((cache_info->columns == clone_info->columns) &&
1254 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001255 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001256 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001257 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1258 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1259 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001260}
1261
1262/*
1263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264% %
1265% %
1266% %
1267+ C l o n e P i x e l C a c h e M e t h o d s %
1268% %
1269% %
1270% %
1271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1272%
1273% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1274% another.
1275%
1276% The format of the ClonePixelCacheMethods() method is:
1277%
1278% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1279%
1280% A description of each parameter follows:
1281%
1282% o clone: Specifies a pointer to a Cache structure.
1283%
1284% o cache: the pixel cache.
1285%
1286*/
cristya6577ff2011-09-02 19:54:26 +00001287MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001288{
1289 CacheInfo
1290 *cache_info,
1291 *source_info;
1292
1293 assert(clone != (Cache) NULL);
1294 source_info=(CacheInfo *) clone;
1295 assert(source_info->signature == MagickSignature);
1296 if (source_info->debug != MagickFalse)
1297 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1298 source_info->filename);
1299 assert(cache != (Cache) NULL);
1300 cache_info=(CacheInfo *) cache;
1301 assert(cache_info->signature == MagickSignature);
1302 source_info->methods=cache_info->methods;
1303}
1304
1305/*
1306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1307% %
1308% %
1309% %
1310+ D e s t r o y I m a g e P i x e l C a c h e %
1311% %
1312% %
1313% %
1314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315%
1316% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1317%
1318% The format of the DestroyImagePixelCache() method is:
1319%
1320% void DestroyImagePixelCache(Image *image)
1321%
1322% A description of each parameter follows:
1323%
1324% o image: the image.
1325%
1326*/
1327static void DestroyImagePixelCache(Image *image)
1328{
1329 assert(image != (Image *) NULL);
1330 assert(image->signature == MagickSignature);
1331 if (image->debug != MagickFalse)
1332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1333 if (image->cache == (void *) NULL)
1334 return;
1335 image->cache=DestroyPixelCache(image->cache);
1336}
1337
1338/*
1339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340% %
1341% %
1342% %
1343+ D e s t r o y I m a g e P i x e l s %
1344% %
1345% %
1346% %
1347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348%
1349% DestroyImagePixels() deallocates memory associated with the pixel cache.
1350%
1351% The format of the DestroyImagePixels() method is:
1352%
1353% void DestroyImagePixels(Image *image)
1354%
1355% A description of each parameter follows:
1356%
1357% o image: the image.
1358%
1359*/
1360MagickExport void DestroyImagePixels(Image *image)
1361{
1362 CacheInfo
1363 *cache_info;
1364
1365 assert(image != (const Image *) NULL);
1366 assert(image->signature == MagickSignature);
1367 if (image->debug != MagickFalse)
1368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1369 assert(image->cache != (Cache) NULL);
1370 cache_info=(CacheInfo *) image->cache;
1371 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001372 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1373 {
1374 cache_info->methods.destroy_pixel_handler(image);
1375 return;
1376 }
cristy2036f5c2010-09-19 21:18:17 +00001377 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001378}
1379
1380/*
1381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1382% %
1383% %
1384% %
1385+ D e s t r o y P i x e l C a c h e %
1386% %
1387% %
1388% %
1389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1390%
1391% DestroyPixelCache() deallocates memory associated with the pixel cache.
1392%
1393% The format of the DestroyPixelCache() method is:
1394%
1395% Cache DestroyPixelCache(Cache cache)
1396%
1397% A description of each parameter follows:
1398%
1399% o cache: the pixel cache.
1400%
1401*/
1402
1403static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1404{
1405 switch (cache_info->type)
1406 {
1407 case MemoryCache:
1408 {
1409 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001410 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001411 cache_info->pixels);
1412 else
cristy4c08aed2011-07-01 19:47:50 +00001413 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001414 (size_t) cache_info->length);
1415 RelinquishMagickResource(MemoryResource,cache_info->length);
1416 break;
1417 }
1418 case MapCache:
1419 {
cristy4c08aed2011-07-01 19:47:50 +00001420 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001421 cache_info->length);
1422 RelinquishMagickResource(MapResource,cache_info->length);
1423 }
1424 case DiskCache:
1425 {
1426 if (cache_info->file != -1)
1427 (void) ClosePixelCacheOnDisk(cache_info);
1428 RelinquishMagickResource(DiskResource,cache_info->length);
1429 break;
1430 }
1431 default:
1432 break;
1433 }
1434 cache_info->type=UndefinedCache;
1435 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001436 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001437}
1438
cristya6577ff2011-09-02 19:54:26 +00001439MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001440{
1441 CacheInfo
1442 *cache_info;
1443
cristy3ed852e2009-09-05 21:47:34 +00001444 assert(cache != (Cache) NULL);
1445 cache_info=(CacheInfo *) cache;
1446 assert(cache_info->signature == MagickSignature);
1447 if (cache_info->debug != MagickFalse)
1448 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1449 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001450 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001451 cache_info->reference_count--;
1452 if (cache_info->reference_count != 0)
1453 {
cristyf84a1932010-01-03 18:00:18 +00001454 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001455 return((Cache) NULL);
1456 }
cristyf84a1932010-01-03 18:00:18 +00001457 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001458 if (cache_resources != (SplayTreeInfo *) NULL)
1459 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001460 if (cache_info->debug != MagickFalse)
1461 {
1462 char
1463 message[MaxTextExtent];
1464
cristyb51dff52011-05-19 16:55:47 +00001465 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001466 cache_info->filename);
1467 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1468 }
cristyc2e1bdd2009-09-10 23:43:34 +00001469 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1470 (cache_info->type != DiskCache)))
1471 RelinquishPixelCachePixels(cache_info);
1472 else
1473 {
1474 RelinquishPixelCachePixels(cache_info);
1475 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1476 }
cristy3ed852e2009-09-05 21:47:34 +00001477 *cache_info->cache_filename='\0';
1478 if (cache_info->nexus_info != (NexusInfo **) NULL)
1479 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1480 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001481 if (cache_info->random_info != (RandomInfo *) NULL)
1482 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001483 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1484 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1485 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1486 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001487 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001488 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001489 cache=(Cache) NULL;
1490 return(cache);
1491}
1492
1493/*
1494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495% %
1496% %
1497% %
1498+ D e s t r o y P i x e l C a c h e N e x u s %
1499% %
1500% %
1501% %
1502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503%
1504% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1505%
1506% The format of the DestroyPixelCacheNexus() method is:
1507%
1508% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001509% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001510%
1511% A description of each parameter follows:
1512%
1513% o nexus_info: the nexus to destroy.
1514%
1515% o number_threads: the number of nexus threads.
1516%
1517*/
1518
1519static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1520{
1521 if (nexus_info->mapped == MagickFalse)
1522 (void) RelinquishMagickMemory(nexus_info->cache);
1523 else
1524 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001525 nexus_info->cache=(Quantum *) NULL;
1526 nexus_info->pixels=(Quantum *) NULL;
1527 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001528 nexus_info->length=0;
1529 nexus_info->mapped=MagickFalse;
1530}
1531
cristya6577ff2011-09-02 19:54:26 +00001532MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001533 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001534{
cristybb503372010-05-27 20:51:26 +00001535 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001536 i;
1537
1538 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001539 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001540 {
cristy4c08aed2011-07-01 19:47:50 +00001541 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001542 RelinquishCacheNexusPixels(nexus_info[i]);
1543 nexus_info[i]->signature=(~MagickSignature);
cristya64b85d2011-09-14 01:02:31 +00001544 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001545 }
cristyb41ee102010-10-04 16:46:15 +00001546 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001547 return(nexus_info);
1548}
1549
1550/*
1551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552% %
1553% %
1554% %
cristy4c08aed2011-07-01 19:47:50 +00001555% 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 +00001556% %
1557% %
1558% %
1559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560%
cristy4c08aed2011-07-01 19:47:50 +00001561% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1562% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1563% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001564%
cristy4c08aed2011-07-01 19:47:50 +00001565% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001566%
cristy4c08aed2011-07-01 19:47:50 +00001567% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001568%
1569% A description of each parameter follows:
1570%
1571% o image: the image.
1572%
1573*/
cristy4c08aed2011-07-01 19:47:50 +00001574MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001575{
1576 CacheInfo
1577 *cache_info;
1578
cristy5c9e6f22010-09-17 17:31:01 +00001579 const int
1580 id = GetOpenMPThreadId();
1581
cristy4c08aed2011-07-01 19:47:50 +00001582 void
1583 *metacontent;
1584
cristye7cc7cf2010-09-21 13:26:47 +00001585 assert(image != (const Image *) NULL);
1586 assert(image->signature == MagickSignature);
1587 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001588 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001589 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001590 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1591 (GetAuthenticMetacontentFromHandler) NULL)
1592 {
1593 metacontent=cache_info->methods.
1594 get_authentic_metacontent_from_handler(image);
1595 return(metacontent);
1596 }
cristy6ebe97c2010-07-03 01:17:28 +00001597 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001598 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1599 cache_info->nexus_info[id]);
1600 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001601}
1602
1603/*
1604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1605% %
1606% %
1607% %
cristy4c08aed2011-07-01 19:47:50 +00001608+ 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 +00001609% %
1610% %
1611% %
1612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1613%
cristy4c08aed2011-07-01 19:47:50 +00001614% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1615% with the last call to QueueAuthenticPixelsCache() or
1616% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001617%
cristy4c08aed2011-07-01 19:47:50 +00001618% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001619%
cristy4c08aed2011-07-01 19:47:50 +00001620% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001621%
1622% A description of each parameter follows:
1623%
1624% o image: the image.
1625%
1626*/
cristy4c08aed2011-07-01 19:47:50 +00001627static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001628{
1629 CacheInfo
1630 *cache_info;
1631
cristy2036f5c2010-09-19 21:18:17 +00001632 const int
1633 id = GetOpenMPThreadId();
1634
cristy4c08aed2011-07-01 19:47:50 +00001635 void
1636 *metacontent;
1637
cristy3ed852e2009-09-05 21:47:34 +00001638 assert(image != (const Image *) NULL);
1639 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001640 assert(image->cache != (Cache) NULL);
1641 cache_info=(CacheInfo *) image->cache;
1642 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001643 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001644 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1645 cache_info->nexus_info[id]);
1646 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001647}
1648
1649/*
1650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1651% %
1652% %
1653% %
1654+ 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 %
1655% %
1656% %
1657% %
1658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1659%
1660% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1661% disk pixel cache as defined by the geometry parameters. A pointer to the
1662% pixels is returned if the pixels are transferred, otherwise a NULL is
1663% returned.
1664%
1665% The format of the GetAuthenticPixelCacheNexus() method is:
1666%
cristy4c08aed2011-07-01 19:47:50 +00001667% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001668% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001669% NexusInfo *nexus_info,ExceptionInfo *exception)
1670%
1671% A description of each parameter follows:
1672%
1673% o image: the image.
1674%
1675% o x,y,columns,rows: These values define the perimeter of a region of
1676% pixels.
1677%
1678% o nexus_info: the cache nexus to return.
1679%
1680% o exception: return any errors or warnings in this structure.
1681%
1682*/
1683
cristy4c08aed2011-07-01 19:47:50 +00001684static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001685 NexusInfo *nexus_info)
1686{
cristy4c08aed2011-07-01 19:47:50 +00001687 MagickBooleanType
1688 status;
1689
cristy3ed852e2009-09-05 21:47:34 +00001690 MagickOffsetType
1691 offset;
1692
cristy73724512010-04-12 14:43:14 +00001693 if (cache_info->type == PingCache)
1694 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001695 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1696 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001697 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001698 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001699 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001700}
1701
cristya6577ff2011-09-02 19:54:26 +00001702MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001703 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001704 NexusInfo *nexus_info,ExceptionInfo *exception)
1705{
1706 CacheInfo
1707 *cache_info;
1708
cristy4c08aed2011-07-01 19:47:50 +00001709 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001710 *q;
cristy3ed852e2009-09-05 21:47:34 +00001711
1712 /*
1713 Transfer pixels from the cache.
1714 */
1715 assert(image != (Image *) NULL);
1716 assert(image->signature == MagickSignature);
cristy65dbf172011-10-06 17:32:04 +00001717 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
cristyacd2ed22011-08-30 01:44:23 +00001718 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001719 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001720 cache_info=(CacheInfo *) image->cache;
1721 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001722 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001723 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001724 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001725 return((Quantum *) NULL);
1726 if (cache_info->metacontent_extent != 0)
1727 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1728 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001729 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001730}
1731
1732/*
1733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734% %
1735% %
1736% %
1737+ 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 %
1738% %
1739% %
1740% %
1741%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1742%
1743% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1744% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1745%
1746% The format of the GetAuthenticPixelsFromCache() method is:
1747%
cristy4c08aed2011-07-01 19:47:50 +00001748% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001749%
1750% A description of each parameter follows:
1751%
1752% o image: the image.
1753%
1754*/
cristy4c08aed2011-07-01 19:47:50 +00001755static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001756{
1757 CacheInfo
1758 *cache_info;
1759
cristy5c9e6f22010-09-17 17:31:01 +00001760 const int
1761 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001762
cristye7cc7cf2010-09-21 13:26:47 +00001763 assert(image != (const Image *) NULL);
1764 assert(image->signature == MagickSignature);
1765 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001766 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001767 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001768 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001769 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001770}
1771
1772/*
1773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1774% %
1775% %
1776% %
1777% G e t A u t h e n t i c P i x e l Q u e u e %
1778% %
1779% %
1780% %
1781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1782%
cristy4c08aed2011-07-01 19:47:50 +00001783% GetAuthenticPixelQueue() returns the authentic pixels associated
1784% corresponding with the last call to QueueAuthenticPixels() or
1785% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001786%
1787% The format of the GetAuthenticPixelQueue() method is:
1788%
cristy4c08aed2011-07-01 19:47:50 +00001789% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001790%
1791% A description of each parameter follows:
1792%
1793% o image: the image.
1794%
1795*/
cristy4c08aed2011-07-01 19:47:50 +00001796MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001797{
1798 CacheInfo
1799 *cache_info;
1800
cristy2036f5c2010-09-19 21:18:17 +00001801 const int
1802 id = GetOpenMPThreadId();
1803
cristy3ed852e2009-09-05 21:47:34 +00001804 assert(image != (const Image *) NULL);
1805 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001806 assert(image->cache != (Cache) NULL);
1807 cache_info=(CacheInfo *) image->cache;
1808 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001809 if (cache_info->methods.get_authentic_pixels_from_handler !=
1810 (GetAuthenticPixelsFromHandler) NULL)
1811 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001812 assert(id < (int) cache_info->number_threads);
1813 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001814}
1815
1816/*
1817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1818% %
1819% %
1820% %
1821% G e t A u t h e n t i c P i x e l s %
1822% %
1823% %
cristy4c08aed2011-07-01 19:47:50 +00001824% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001825%
1826% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001827% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001828% representing the region is returned, otherwise NULL is returned.
1829%
1830% The returned pointer may point to a temporary working copy of the pixels
1831% or it may point to the original pixels in memory. Performance is maximized
1832% if the selected region is part of one row, or one or more full rows, since
1833% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001834% if the image is in memory, or in a memory-mapped file. The returned pointer
1835% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001836%
1837% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001838% Quantum. If the image has corresponding metacontent,call
1839% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1840% meta-content corresponding to the region. Once the Quantum array has
1841% been updated, the changes must be saved back to the underlying image using
1842% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001843%
1844% The format of the GetAuthenticPixels() method is:
1845%
cristy4c08aed2011-07-01 19:47:50 +00001846% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001847% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001848% ExceptionInfo *exception)
1849%
1850% A description of each parameter follows:
1851%
1852% o image: the image.
1853%
1854% o x,y,columns,rows: These values define the perimeter of a region of
1855% pixels.
1856%
1857% o exception: return any errors or warnings in this structure.
1858%
1859*/
cristy4c08aed2011-07-01 19:47:50 +00001860MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001861 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001862 ExceptionInfo *exception)
1863{
1864 CacheInfo
1865 *cache_info;
1866
cristy2036f5c2010-09-19 21:18:17 +00001867 const int
1868 id = GetOpenMPThreadId();
1869
cristy4c08aed2011-07-01 19:47:50 +00001870 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001871 *q;
cristy4c08aed2011-07-01 19:47:50 +00001872
cristy3ed852e2009-09-05 21:47:34 +00001873 assert(image != (Image *) NULL);
1874 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001875 assert(image->cache != (Cache) NULL);
1876 cache_info=(CacheInfo *) image->cache;
1877 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001878 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001879 (GetAuthenticPixelsHandler) NULL)
1880 {
cristyacd2ed22011-08-30 01:44:23 +00001881 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1882 exception);
1883 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001884 }
cristy2036f5c2010-09-19 21:18:17 +00001885 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001886 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001887 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001888 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001889}
1890
1891/*
1892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1893% %
1894% %
1895% %
1896+ G e t A u t h e n t i c P i x e l s C a c h e %
1897% %
1898% %
1899% %
1900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901%
1902% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1903% as defined by the geometry parameters. A pointer to the pixels is returned
1904% if the pixels are transferred, otherwise a NULL is returned.
1905%
1906% The format of the GetAuthenticPixelsCache() method is:
1907%
cristy4c08aed2011-07-01 19:47:50 +00001908% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001909% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001910% ExceptionInfo *exception)
1911%
1912% A description of each parameter follows:
1913%
1914% o image: the image.
1915%
1916% o x,y,columns,rows: These values define the perimeter of a region of
1917% pixels.
1918%
1919% o exception: return any errors or warnings in this structure.
1920%
1921*/
cristy4c08aed2011-07-01 19:47:50 +00001922static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001923 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001924 ExceptionInfo *exception)
1925{
1926 CacheInfo
1927 *cache_info;
1928
cristy5c9e6f22010-09-17 17:31:01 +00001929 const int
1930 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001931
cristy4c08aed2011-07-01 19:47:50 +00001932 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001933 *q;
cristy4c08aed2011-07-01 19:47:50 +00001934
cristye7cc7cf2010-09-21 13:26:47 +00001935 assert(image != (const Image *) NULL);
1936 assert(image->signature == MagickSignature);
1937 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001938 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001939 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001940 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001941 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001942 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001943 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001944 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001945 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001946}
1947
1948/*
1949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1950% %
1951% %
1952% %
1953+ G e t I m a g e E x t e n t %
1954% %
1955% %
1956% %
1957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958%
cristy4c08aed2011-07-01 19:47:50 +00001959% GetImageExtent() returns the extent of the pixels associated corresponding
1960% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001961%
1962% The format of the GetImageExtent() method is:
1963%
1964% MagickSizeType GetImageExtent(const Image *image)
1965%
1966% A description of each parameter follows:
1967%
1968% o image: the image.
1969%
1970*/
1971MagickExport MagickSizeType GetImageExtent(const Image *image)
1972{
1973 CacheInfo
1974 *cache_info;
1975
cristy5c9e6f22010-09-17 17:31:01 +00001976 const int
1977 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001978
cristy3ed852e2009-09-05 21:47:34 +00001979 assert(image != (Image *) NULL);
1980 assert(image->signature == MagickSignature);
1981 if (image->debug != MagickFalse)
1982 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1983 assert(image->cache != (Cache) NULL);
1984 cache_info=(CacheInfo *) image->cache;
1985 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001986 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001987 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001988}
1989
1990/*
1991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992% %
1993% %
1994% %
1995+ G e t I m a g e P i x e l C a c h e %
1996% %
1997% %
1998% %
1999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000%
2001% GetImagePixelCache() ensures that there is only a single reference to the
2002% pixel cache to be modified, updating the provided cache pointer to point to
2003% a clone of the original pixel cache if necessary.
2004%
2005% The format of the GetImagePixelCache method is:
2006%
2007% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2008% ExceptionInfo *exception)
2009%
2010% A description of each parameter follows:
2011%
2012% o image: the image.
2013%
2014% o clone: any value other than MagickFalse clones the cache pixels.
2015%
2016% o exception: return any errors or warnings in this structure.
2017%
2018*/
cristyaf894d72011-08-06 23:03:10 +00002019
cristy3ed852e2009-09-05 21:47:34 +00002020static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2021{
2022 CacheInfo
2023 *cache_info;
2024
cristy9e0719b2011-12-29 03:45:45 +00002025 PixelChannelMap
2026 *p,
2027 *q;
2028
cristy3ed852e2009-09-05 21:47:34 +00002029 /*
2030 Does the image match the pixel cache morphology?
2031 */
2032 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00002033 p=image->channel_map;
2034 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00002035 if ((image->storage_class != cache_info->storage_class) ||
2036 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00002037 (image->matte != cache_info->matte) ||
cristy3ed852e2009-09-05 21:47:34 +00002038 (image->columns != cache_info->columns) ||
2039 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00002040 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00002041 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00002042 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00002043 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2044 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2045 return(MagickFalse);
2046 return(MagickTrue);
2047}
2048
cristycd01fae2011-08-06 23:52:42 +00002049static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2050 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002051{
2052 CacheInfo
2053 *cache_info;
2054
cristy3ed852e2009-09-05 21:47:34 +00002055 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002056 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002057 status;
2058
cristy50a10922010-02-15 18:35:25 +00002059 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002060 cpu_throttle = 0,
2061 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002062 time_limit = 0;
2063
cristy1ea34962010-07-01 19:49:21 +00002064 static time_t
cristy208b1002011-08-07 18:51:50 +00002065 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00002066
cristyc4f9f132010-03-04 18:50:01 +00002067 status=MagickTrue;
2068 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002069 if (cpu_throttle == 0)
2070 {
2071 char
2072 *limit;
2073
2074 /*
2075 Set CPU throttle in milleseconds.
2076 */
2077 cpu_throttle=MagickResourceInfinity;
2078 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2079 if (limit == (char *) NULL)
2080 limit=GetPolicyValue("throttle");
2081 if (limit != (char *) NULL)
2082 {
2083 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2084 limit=DestroyString(limit);
2085 }
2086 }
2087 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2088 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002089 if (time_limit == 0)
2090 {
cristy6ebe97c2010-07-03 01:17:28 +00002091 /*
2092 Set the exire time in seconds.
2093 */
cristy1ea34962010-07-01 19:49:21 +00002094 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00002095 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002096 }
2097 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00002098 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002099 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002100 assert(image->cache != (Cache) NULL);
2101 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002102 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002103 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002104 {
cristyceb55ee2010-11-06 16:05:49 +00002105 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002106 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002107 {
cristyceb55ee2010-11-06 16:05:49 +00002108 Image
2109 clone_image;
2110
2111 CacheInfo
2112 *clone_info;
2113
2114 /*
2115 Clone pixel cache.
2116 */
2117 clone_image=(*image);
2118 clone_image.semaphore=AllocateSemaphoreInfo();
2119 clone_image.reference_count=1;
2120 clone_image.cache=ClonePixelCache(cache_info);
2121 clone_info=(CacheInfo *) clone_image.cache;
2122 status=OpenPixelCache(&clone_image,IOMode,exception);
2123 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002124 {
cristy5a7fbfb2010-11-06 16:10:59 +00002125 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002126 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002127 if (status != MagickFalse)
2128 {
cristy979bf772011-08-08 00:04:15 +00002129 if (cache_info->mode == ReadMode)
2130 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00002131 destroy=MagickTrue;
2132 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002133 }
2134 }
cristyceb55ee2010-11-06 16:05:49 +00002135 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002136 }
cristyceb55ee2010-11-06 16:05:49 +00002137 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002138 }
cristy4320e0e2009-09-10 15:00:08 +00002139 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002140 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002141 if (status != MagickFalse)
2142 {
2143 /*
2144 Ensure the image matches the pixel cache morphology.
2145 */
2146 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002147 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00002148 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2149 status=OpenPixelCache(image,IOMode,exception);
2150 }
cristyf84a1932010-01-03 18:00:18 +00002151 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002152 if (status == MagickFalse)
2153 return((Cache) NULL);
2154 return(image->cache);
2155}
2156
2157/*
2158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2159% %
2160% %
2161% %
2162% G e t O n e A u t h e n t i c P i x e l %
2163% %
2164% %
2165% %
2166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167%
2168% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2169% location. The image background color is returned if an error occurs.
2170%
2171% The format of the GetOneAuthenticPixel() method is:
2172%
cristybb503372010-05-27 20:51:26 +00002173% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002174% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002175%
2176% A description of each parameter follows:
2177%
2178% o image: the image.
2179%
2180% o x,y: These values define the location of the pixel to return.
2181%
2182% o pixel: return a pixel at the specified (x,y) location.
2183%
2184% o exception: return any errors or warnings in this structure.
2185%
2186*/
cristyacbbb7c2010-06-30 18:56:48 +00002187MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002188 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002189{
2190 CacheInfo
2191 *cache_info;
2192
cristy4c08aed2011-07-01 19:47:50 +00002193 register Quantum
2194 *q;
cristy2036f5c2010-09-19 21:18:17 +00002195
cristy2ed42f62011-10-02 19:49:57 +00002196 register ssize_t
2197 i;
2198
cristy3ed852e2009-09-05 21:47:34 +00002199 assert(image != (Image *) NULL);
2200 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002201 assert(image->cache != (Cache) NULL);
2202 cache_info=(CacheInfo *) image->cache;
2203 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002204 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002205 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2206 (GetOneAuthenticPixelFromHandler) NULL)
2207 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2208 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002209 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2210 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002211 {
cristy9e0719b2011-12-29 03:45:45 +00002212 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2213 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2214 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2215 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2216 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002217 return(MagickFalse);
2218 }
2219 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2220 {
2221 PixelChannel
2222 channel;
2223
cristye2a912b2011-12-05 20:02:07 +00002224 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002225 pixel[channel]=q[i];
2226 }
cristy2036f5c2010-09-19 21:18:17 +00002227 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002228}
2229
2230/*
2231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2232% %
2233% %
2234% %
2235+ 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 %
2236% %
2237% %
2238% %
2239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240%
2241% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2242% location. The image background color is returned if an error occurs.
2243%
2244% The format of the GetOneAuthenticPixelFromCache() method is:
2245%
2246% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002247% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002248% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002249%
2250% A description of each parameter follows:
2251%
2252% o image: the image.
2253%
2254% o x,y: These values define the location of the pixel to return.
2255%
2256% o pixel: return a pixel at the specified (x,y) location.
2257%
2258% o exception: return any errors or warnings in this structure.
2259%
2260*/
2261static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002262 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002263{
cristy098f78c2010-09-23 17:28:44 +00002264 CacheInfo
2265 *cache_info;
2266
2267 const int
2268 id = GetOpenMPThreadId();
2269
cristy4c08aed2011-07-01 19:47:50 +00002270 register Quantum
2271 *q;
cristy3ed852e2009-09-05 21:47:34 +00002272
cristy2ed42f62011-10-02 19:49:57 +00002273 register ssize_t
2274 i;
2275
cristy0158a4b2010-09-20 13:59:45 +00002276 assert(image != (const Image *) NULL);
2277 assert(image->signature == MagickSignature);
2278 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002279 cache_info=(CacheInfo *) image->cache;
2280 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002281 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002282 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002283 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2284 exception);
2285 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002286 {
cristy9e0719b2011-12-29 03:45:45 +00002287 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2288 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2289 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2290 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2291 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002292 return(MagickFalse);
2293 }
2294 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2295 {
2296 PixelChannel
2297 channel;
2298
cristye2a912b2011-12-05 20:02:07 +00002299 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002300 pixel[channel]=q[i];
2301 }
cristy3ed852e2009-09-05 21:47:34 +00002302 return(MagickTrue);
2303}
2304
2305/*
2306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2307% %
2308% %
2309% %
cristy3ed852e2009-09-05 21:47:34 +00002310% G e t O n e V i r t u a l P i x e l %
2311% %
2312% %
2313% %
2314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315%
2316% GetOneVirtualPixel() returns a single virtual pixel at the specified
2317% (x,y) location. The image background color is returned if an error occurs.
2318% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2319%
2320% The format of the GetOneVirtualPixel() method is:
2321%
cristybb503372010-05-27 20:51:26 +00002322% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002323% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002324%
2325% A description of each parameter follows:
2326%
2327% o image: the image.
2328%
2329% o x,y: These values define the location of the pixel to return.
2330%
2331% o pixel: return a pixel at the specified (x,y) location.
2332%
2333% o exception: return any errors or warnings in this structure.
2334%
2335*/
2336MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002337 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002338{
cristy3ed852e2009-09-05 21:47:34 +00002339 CacheInfo
2340 *cache_info;
2341
cristy0158a4b2010-09-20 13:59:45 +00002342 const int
2343 id = GetOpenMPThreadId();
2344
cristy4c08aed2011-07-01 19:47:50 +00002345 const Quantum
2346 *p;
cristy2036f5c2010-09-19 21:18:17 +00002347
cristy2ed42f62011-10-02 19:49:57 +00002348 register ssize_t
2349 i;
2350
cristy3ed852e2009-09-05 21:47:34 +00002351 assert(image != (const Image *) NULL);
2352 assert(image->signature == MagickSignature);
2353 assert(image->cache != (Cache) NULL);
2354 cache_info=(CacheInfo *) image->cache;
2355 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002356 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002357 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2358 (GetOneVirtualPixelFromHandler) NULL)
2359 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2360 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002361 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002362 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002363 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002364 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002365 {
cristy9e0719b2011-12-29 03:45:45 +00002366 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2367 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2368 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2369 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2370 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002371 return(MagickFalse);
2372 }
2373 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2374 {
2375 PixelChannel
2376 channel;
2377
cristye2a912b2011-12-05 20:02:07 +00002378 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002379 pixel[channel]=p[i];
2380 }
cristy2036f5c2010-09-19 21:18:17 +00002381 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002382}
2383
2384/*
2385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2386% %
2387% %
2388% %
2389+ 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 %
2390% %
2391% %
2392% %
2393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2394%
2395% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2396% specified (x,y) location. The image background color is returned if an
2397% error occurs.
2398%
2399% The format of the GetOneVirtualPixelFromCache() method is:
2400%
2401% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002402% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002403% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002404%
2405% A description of each parameter follows:
2406%
2407% o image: the image.
2408%
2409% o virtual_pixel_method: the virtual pixel method.
2410%
2411% o x,y: These values define the location of the pixel to return.
2412%
2413% o pixel: return a pixel at the specified (x,y) location.
2414%
2415% o exception: return any errors or warnings in this structure.
2416%
2417*/
2418static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002419 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002420 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002421{
cristy0158a4b2010-09-20 13:59:45 +00002422 CacheInfo
2423 *cache_info;
2424
2425 const int
2426 id = GetOpenMPThreadId();
2427
cristy4c08aed2011-07-01 19:47:50 +00002428 const Quantum
2429 *p;
cristy3ed852e2009-09-05 21:47:34 +00002430
cristy2ed42f62011-10-02 19:49:57 +00002431 register ssize_t
2432 i;
2433
cristye7cc7cf2010-09-21 13:26:47 +00002434 assert(image != (const Image *) NULL);
2435 assert(image->signature == MagickSignature);
2436 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002437 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002438 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002439 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002440 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002441 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002442 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002443 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002444 {
cristy9e0719b2011-12-29 03:45:45 +00002445 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2446 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2447 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2448 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2449 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002450 return(MagickFalse);
2451 }
2452 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2453 {
2454 PixelChannel
2455 channel;
2456
cristye2a912b2011-12-05 20:02:07 +00002457 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002458 pixel[channel]=p[i];
2459 }
cristy3ed852e2009-09-05 21:47:34 +00002460 return(MagickTrue);
2461}
2462
2463/*
2464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465% %
2466% %
2467% %
cristy3aa93752011-12-18 15:54:24 +00002468% G e t O n e V i r t u a l P i x e l I n f o %
2469% %
2470% %
2471% %
2472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473%
2474% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2475% location. The image background color is returned if an error occurs. If
2476% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2477%
2478% The format of the GetOneVirtualPixelInfo() method is:
2479%
2480% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2481% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2482% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2483%
2484% A description of each parameter follows:
2485%
2486% o image: the image.
2487%
2488% o virtual_pixel_method: the virtual pixel method.
2489%
2490% o x,y: these values define the location of the pixel to return.
2491%
2492% o pixel: return a pixel at the specified (x,y) location.
2493%
2494% o exception: return any errors or warnings in this structure.
2495%
2496*/
2497MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2498 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2499 PixelInfo *pixel,ExceptionInfo *exception)
2500{
2501 CacheInfo
2502 *cache_info;
2503
2504 const int
2505 id = GetOpenMPThreadId();
2506
2507 register const Quantum
2508 *p;
2509
2510 assert(image != (const Image *) NULL);
2511 assert(image->signature == MagickSignature);
2512 assert(image->cache != (Cache) NULL);
2513 cache_info=(CacheInfo *) image->cache;
2514 assert(cache_info->signature == MagickSignature);
2515 assert(id < (int) cache_info->number_threads);
2516 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2517 cache_info->nexus_info[id],exception);
2518 GetPixelInfo(image,pixel);
2519 if (p == (const Quantum *) NULL)
2520 return(MagickFalse);
2521 GetPixelInfoPixel(image,p,pixel);
2522 return(MagickTrue);
2523}
2524
2525/*
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527% %
2528% %
2529% %
cristy3ed852e2009-09-05 21:47:34 +00002530+ G e t P i x e l C a c h e C o l o r s p a c e %
2531% %
2532% %
2533% %
2534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535%
2536% GetPixelCacheColorspace() returns the class type of the pixel cache.
2537%
2538% The format of the GetPixelCacheColorspace() method is:
2539%
2540% Colorspace GetPixelCacheColorspace(Cache cache)
2541%
2542% A description of each parameter follows:
2543%
2544% o cache: the pixel cache.
2545%
2546*/
cristya6577ff2011-09-02 19:54:26 +00002547MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002548{
2549 CacheInfo
2550 *cache_info;
2551
2552 assert(cache != (Cache) NULL);
2553 cache_info=(CacheInfo *) cache;
2554 assert(cache_info->signature == MagickSignature);
2555 if (cache_info->debug != MagickFalse)
2556 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2557 cache_info->filename);
2558 return(cache_info->colorspace);
2559}
2560
2561/*
2562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2563% %
2564% %
2565% %
2566+ G e t P i x e l C a c h e M e t h o d s %
2567% %
2568% %
2569% %
2570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2571%
2572% GetPixelCacheMethods() initializes the CacheMethods structure.
2573%
2574% The format of the GetPixelCacheMethods() method is:
2575%
2576% void GetPixelCacheMethods(CacheMethods *cache_methods)
2577%
2578% A description of each parameter follows:
2579%
2580% o cache_methods: Specifies a pointer to a CacheMethods structure.
2581%
2582*/
cristya6577ff2011-09-02 19:54:26 +00002583MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002584{
2585 assert(cache_methods != (CacheMethods *) NULL);
2586 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2587 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2588 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002589 cache_methods->get_virtual_metacontent_from_handler=
2590 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002591 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2592 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002593 cache_methods->get_authentic_metacontent_from_handler=
2594 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002595 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2596 cache_methods->get_one_authentic_pixel_from_handler=
2597 GetOneAuthenticPixelFromCache;
2598 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2599 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2600 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2601}
2602
2603/*
2604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605% %
2606% %
2607% %
2608+ G e t P i x e l C a c h e N e x u s E x t e n t %
2609% %
2610% %
2611% %
2612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2613%
cristy4c08aed2011-07-01 19:47:50 +00002614% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2615% corresponding with the last call to SetPixelCacheNexusPixels() or
2616% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002617%
2618% The format of the GetPixelCacheNexusExtent() method is:
2619%
2620% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2621% NexusInfo *nexus_info)
2622%
2623% A description of each parameter follows:
2624%
2625% o nexus_info: the nexus info.
2626%
2627*/
cristya6577ff2011-09-02 19:54:26 +00002628MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002629 NexusInfo *nexus_info)
2630{
2631 CacheInfo
2632 *cache_info;
2633
2634 MagickSizeType
2635 extent;
2636
cristy9f027d12011-09-21 01:17:17 +00002637 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002638 cache_info=(CacheInfo *) cache;
2639 assert(cache_info->signature == MagickSignature);
2640 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2641 if (extent == 0)
2642 return((MagickSizeType) cache_info->columns*cache_info->rows);
2643 return(extent);
2644}
2645
2646/*
2647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2648% %
2649% %
2650% %
cristy4c08aed2011-07-01 19:47:50 +00002651+ 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 +00002652% %
2653% %
2654% %
2655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2656%
cristy4c08aed2011-07-01 19:47:50 +00002657% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2658% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002659%
cristy4c08aed2011-07-01 19:47:50 +00002660% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002661%
cristy4c08aed2011-07-01 19:47:50 +00002662% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002663% NexusInfo *nexus_info)
2664%
2665% A description of each parameter follows:
2666%
2667% o cache: the pixel cache.
2668%
cristy4c08aed2011-07-01 19:47:50 +00002669% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002670%
2671*/
cristya6577ff2011-09-02 19:54:26 +00002672MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002673 NexusInfo *nexus_info)
2674{
2675 CacheInfo
2676 *cache_info;
2677
cristy9f027d12011-09-21 01:17:17 +00002678 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002679 cache_info=(CacheInfo *) cache;
2680 assert(cache_info->signature == MagickSignature);
2681 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002682 return((void *) NULL);
2683 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002684}
2685
2686/*
2687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2688% %
2689% %
2690% %
2691+ G e t P i x e l C a c h e N e x u s P i x e l s %
2692% %
2693% %
2694% %
2695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2696%
2697% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2698% cache nexus.
2699%
2700% The format of the GetPixelCacheNexusPixels() method is:
2701%
cristy4c08aed2011-07-01 19:47:50 +00002702% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002703% NexusInfo *nexus_info)
2704%
2705% A description of each parameter follows:
2706%
2707% o cache: the pixel cache.
2708%
2709% o nexus_info: the cache nexus to return the pixels.
2710%
2711*/
cristya6577ff2011-09-02 19:54:26 +00002712MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002713 NexusInfo *nexus_info)
2714{
2715 CacheInfo
2716 *cache_info;
2717
cristy9f027d12011-09-21 01:17:17 +00002718 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002719 cache_info=(CacheInfo *) cache;
2720 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002721 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002722 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002723 return(nexus_info->pixels);
2724}
2725
2726/*
2727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2728% %
2729% %
2730% %
cristy056ba772010-01-02 23:33:54 +00002731+ G e t P i x e l C a c h e P i x e l s %
2732% %
2733% %
2734% %
2735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736%
2737% GetPixelCachePixels() returns the pixels associated with the specified image.
2738%
2739% The format of the GetPixelCachePixels() method is:
2740%
cristyf84a1932010-01-03 18:00:18 +00002741% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2742% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002743%
2744% A description of each parameter follows:
2745%
2746% o image: the image.
2747%
2748% o length: the pixel cache length.
2749%
cristyf84a1932010-01-03 18:00:18 +00002750% o exception: return any errors or warnings in this structure.
2751%
cristy056ba772010-01-02 23:33:54 +00002752*/
cristyd1dd6e42011-09-04 01:46:08 +00002753MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002754 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002755{
2756 CacheInfo
2757 *cache_info;
2758
2759 assert(image != (const Image *) NULL);
2760 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002761 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002762 assert(length != (MagickSizeType *) NULL);
2763 assert(exception != (ExceptionInfo *) NULL);
2764 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002765 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002766 assert(cache_info->signature == MagickSignature);
2767 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002768 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002769 return((void *) NULL);
2770 *length=cache_info->length;
2771 return((void *) cache_info->pixels);
2772}
2773
2774/*
2775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776% %
2777% %
2778% %
cristyb32b90a2009-09-07 21:45:48 +00002779+ 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 +00002780% %
2781% %
2782% %
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784%
2785% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2786%
2787% The format of the GetPixelCacheStorageClass() method is:
2788%
2789% ClassType GetPixelCacheStorageClass(Cache cache)
2790%
2791% A description of each parameter follows:
2792%
2793% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2794%
2795% o cache: the pixel cache.
2796%
2797*/
cristya6577ff2011-09-02 19:54:26 +00002798MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002799{
2800 CacheInfo
2801 *cache_info;
2802
2803 assert(cache != (Cache) NULL);
2804 cache_info=(CacheInfo *) cache;
2805 assert(cache_info->signature == MagickSignature);
2806 if (cache_info->debug != MagickFalse)
2807 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2808 cache_info->filename);
2809 return(cache_info->storage_class);
2810}
2811
2812/*
2813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2814% %
2815% %
2816% %
cristyb32b90a2009-09-07 21:45:48 +00002817+ G e t P i x e l C a c h e T i l e S i z e %
2818% %
2819% %
2820% %
2821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2822%
2823% GetPixelCacheTileSize() returns the pixel cache tile size.
2824%
2825% The format of the GetPixelCacheTileSize() method is:
2826%
cristybb503372010-05-27 20:51:26 +00002827% void GetPixelCacheTileSize(const Image *image,size_t *width,
2828% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002829%
2830% A description of each parameter follows:
2831%
2832% o image: the image.
2833%
2834% o width: the optimize cache tile width in pixels.
2835%
2836% o height: the optimize cache tile height in pixels.
2837%
2838*/
cristya6577ff2011-09-02 19:54:26 +00002839MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002840 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002841{
cristy4c08aed2011-07-01 19:47:50 +00002842 CacheInfo
2843 *cache_info;
2844
cristyb32b90a2009-09-07 21:45:48 +00002845 assert(image != (Image *) NULL);
2846 assert(image->signature == MagickSignature);
2847 if (image->debug != MagickFalse)
2848 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002849 cache_info=(CacheInfo *) image->cache;
2850 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002851 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002852 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002853 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002854 *height=(*width);
2855}
2856
2857/*
2858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2859% %
2860% %
2861% %
2862+ G e t P i x e l C a c h e T y p e %
2863% %
2864% %
2865% %
2866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2867%
2868% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2869%
2870% The format of the GetPixelCacheType() method is:
2871%
2872% CacheType GetPixelCacheType(const Image *image)
2873%
2874% A description of each parameter follows:
2875%
2876% o image: the image.
2877%
2878*/
cristya6577ff2011-09-02 19:54:26 +00002879MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002880{
2881 CacheInfo
2882 *cache_info;
2883
2884 assert(image != (Image *) NULL);
2885 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002886 assert(image->cache != (Cache) NULL);
2887 cache_info=(CacheInfo *) image->cache;
2888 assert(cache_info->signature == MagickSignature);
2889 return(cache_info->type);
2890}
2891
2892/*
2893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2894% %
2895% %
2896% %
cristy3ed852e2009-09-05 21:47:34 +00002897+ 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 %
2898% %
2899% %
2900% %
2901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2902%
2903% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2904% pixel cache. A virtual pixel is any pixel access that is outside the
2905% boundaries of the image cache.
2906%
2907% The format of the GetPixelCacheVirtualMethod() method is:
2908%
2909% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2910%
2911% A description of each parameter follows:
2912%
2913% o image: the image.
2914%
2915*/
cristyd1dd6e42011-09-04 01:46:08 +00002916MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002917{
2918 CacheInfo
2919 *cache_info;
2920
2921 assert(image != (Image *) NULL);
2922 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002923 assert(image->cache != (Cache) NULL);
2924 cache_info=(CacheInfo *) image->cache;
2925 assert(cache_info->signature == MagickSignature);
2926 return(cache_info->virtual_pixel_method);
2927}
2928
2929/*
2930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2931% %
2932% %
2933% %
cristy4c08aed2011-07-01 19:47:50 +00002934+ 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 +00002935% %
2936% %
2937% %
2938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2939%
cristy4c08aed2011-07-01 19:47:50 +00002940% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2941% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002942%
cristy4c08aed2011-07-01 19:47:50 +00002943% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002944%
cristy4c08aed2011-07-01 19:47:50 +00002945% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002946%
2947% A description of each parameter follows:
2948%
2949% o image: the image.
2950%
2951*/
cristy4c08aed2011-07-01 19:47:50 +00002952static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002953{
2954 CacheInfo
2955 *cache_info;
2956
cristy5c9e6f22010-09-17 17:31:01 +00002957 const int
2958 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002959
cristy4c08aed2011-07-01 19:47:50 +00002960 const void
2961 *metacontent;
2962
cristye7cc7cf2010-09-21 13:26:47 +00002963 assert(image != (const Image *) NULL);
2964 assert(image->signature == MagickSignature);
2965 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002966 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002967 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002968 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002969 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2970 cache_info->nexus_info[id]);
2971 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002972}
2973
2974/*
2975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2976% %
2977% %
2978% %
cristy4c08aed2011-07-01 19:47:50 +00002979+ 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 +00002980% %
2981% %
2982% %
2983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2984%
cristy4c08aed2011-07-01 19:47:50 +00002985% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2986% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002987%
cristy4c08aed2011-07-01 19:47:50 +00002988% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002989%
cristy4c08aed2011-07-01 19:47:50 +00002990% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002991% NexusInfo *nexus_info)
2992%
2993% A description of each parameter follows:
2994%
2995% o cache: the pixel cache.
2996%
cristy4c08aed2011-07-01 19:47:50 +00002997% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002998%
2999*/
cristya6577ff2011-09-02 19:54:26 +00003000MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00003001 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00003002{
3003 CacheInfo
3004 *cache_info;
3005
cristye7cc7cf2010-09-21 13:26:47 +00003006 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003007 cache_info=(CacheInfo *) cache;
3008 assert(cache_info->signature == MagickSignature);
3009 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003010 return((void *) NULL);
3011 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003012}
3013
3014/*
3015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3016% %
3017% %
3018% %
cristy4c08aed2011-07-01 19:47:50 +00003019% 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 +00003020% %
3021% %
3022% %
3023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3024%
cristy4c08aed2011-07-01 19:47:50 +00003025% GetVirtualMetacontent() returns the virtual metacontent corresponding with
3026% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3027% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00003028%
cristy4c08aed2011-07-01 19:47:50 +00003029% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00003030%
cristy4c08aed2011-07-01 19:47:50 +00003031% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003032%
3033% A description of each parameter follows:
3034%
3035% o image: the image.
3036%
3037*/
cristy4c08aed2011-07-01 19:47:50 +00003038MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003039{
3040 CacheInfo
3041 *cache_info;
3042
cristy2036f5c2010-09-19 21:18:17 +00003043 const int
3044 id = GetOpenMPThreadId();
3045
cristy4c08aed2011-07-01 19:47:50 +00003046 const void
3047 *metacontent;
3048
cristy3ed852e2009-09-05 21:47:34 +00003049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003051 assert(image->cache != (Cache) NULL);
3052 cache_info=(CacheInfo *) image->cache;
3053 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00003054 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3055 (GetVirtualMetacontentFromHandler) NULL)
3056 {
3057 metacontent=cache_info->methods.
3058 get_virtual_metacontent_from_handler(image);
3059 return(metacontent);
3060 }
cristy2036f5c2010-09-19 21:18:17 +00003061 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003062 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3063 cache_info->nexus_info[id]);
3064 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003065}
3066
3067/*
3068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3069% %
3070% %
3071% %
3072+ 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 %
3073% %
3074% %
3075% %
3076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3077%
3078% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3079% pixel cache as defined by the geometry parameters. A pointer to the pixels
3080% is returned if the pixels are transferred, otherwise a NULL is returned.
3081%
3082% The format of the GetVirtualPixelsFromNexus() method is:
3083%
cristy4c08aed2011-07-01 19:47:50 +00003084% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003085% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003086% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3087% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003088%
3089% A description of each parameter follows:
3090%
3091% o image: the image.
3092%
3093% o virtual_pixel_method: the virtual pixel method.
3094%
3095% o x,y,columns,rows: These values define the perimeter of a region of
3096% pixels.
3097%
3098% o nexus_info: the cache nexus to acquire.
3099%
3100% o exception: return any errors or warnings in this structure.
3101%
3102*/
3103
cristybb503372010-05-27 20:51:26 +00003104static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003105 DitherMatrix[64] =
3106 {
3107 0, 48, 12, 60, 3, 51, 15, 63,
3108 32, 16, 44, 28, 35, 19, 47, 31,
3109 8, 56, 4, 52, 11, 59, 7, 55,
3110 40, 24, 36, 20, 43, 27, 39, 23,
3111 2, 50, 14, 62, 1, 49, 13, 61,
3112 34, 18, 46, 30, 33, 17, 45, 29,
3113 10, 58, 6, 54, 9, 57, 5, 53,
3114 42, 26, 38, 22, 41, 25, 37, 21
3115 };
3116
cristybb503372010-05-27 20:51:26 +00003117static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003118{
cristybb503372010-05-27 20:51:26 +00003119 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003120 index;
3121
3122 index=x+DitherMatrix[x & 0x07]-32L;
3123 if (index < 0L)
3124 return(0L);
cristybb503372010-05-27 20:51:26 +00003125 if (index >= (ssize_t) columns)
3126 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003127 return(index);
3128}
3129
cristybb503372010-05-27 20:51:26 +00003130static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003131{
cristybb503372010-05-27 20:51:26 +00003132 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003133 index;
3134
3135 index=y+DitherMatrix[y & 0x07]-32L;
3136 if (index < 0L)
3137 return(0L);
cristybb503372010-05-27 20:51:26 +00003138 if (index >= (ssize_t) rows)
3139 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003140 return(index);
3141}
3142
cristybb503372010-05-27 20:51:26 +00003143static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003144{
3145 if (x < 0L)
3146 return(0L);
cristybb503372010-05-27 20:51:26 +00003147 if (x >= (ssize_t) columns)
3148 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003149 return(x);
3150}
3151
cristybb503372010-05-27 20:51:26 +00003152static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003153{
3154 if (y < 0L)
3155 return(0L);
cristybb503372010-05-27 20:51:26 +00003156 if (y >= (ssize_t) rows)
3157 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003158 return(y);
3159}
3160
cristybb503372010-05-27 20:51:26 +00003161static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003162{
cristybb503372010-05-27 20:51:26 +00003163 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003164}
3165
cristybb503372010-05-27 20:51:26 +00003166static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003167{
cristybb503372010-05-27 20:51:26 +00003168 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003169}
3170
cristybb503372010-05-27 20:51:26 +00003171static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3172 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003173{
3174 MagickModulo
3175 modulo;
3176
cristy6162bb42011-07-18 11:34:09 +00003177 /*
3178 Compute the remainder of dividing offset by extent. It returns not only
3179 the quotient (tile the offset falls in) but also the positive remainer
3180 within that tile such that 0 <= remainder < extent. This method is
3181 essentially a ldiv() using a floored modulo division rather than the
3182 normal default truncated modulo division.
3183 */
cristybb503372010-05-27 20:51:26 +00003184 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003185 if (offset < 0L)
3186 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003187 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003188 return(modulo);
3189}
3190
cristya6577ff2011-09-02 19:54:26 +00003191MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003192 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3193 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003194 ExceptionInfo *exception)
3195{
3196 CacheInfo
3197 *cache_info;
3198
3199 MagickOffsetType
3200 offset;
3201
3202 MagickSizeType
3203 length,
3204 number_pixels;
3205
3206 NexusInfo
3207 **virtual_nexus;
3208
cristy4c08aed2011-07-01 19:47:50 +00003209 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003210 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003211 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003212
3213 RectangleInfo
3214 region;
3215
cristy4c08aed2011-07-01 19:47:50 +00003216 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003217 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003218
cristy4c08aed2011-07-01 19:47:50 +00003219 register const void
3220 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003221
cristy4c08aed2011-07-01 19:47:50 +00003222 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003223 *restrict q;
3224
cristybb503372010-05-27 20:51:26 +00003225 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003226 i,
3227 u;
cristy3ed852e2009-09-05 21:47:34 +00003228
cristy4c08aed2011-07-01 19:47:50 +00003229 register unsigned char
3230 *restrict s;
3231
cristy105ba3c2011-07-18 02:28:38 +00003232 ssize_t
3233 v;
3234
cristy4c08aed2011-07-01 19:47:50 +00003235 void
cristy105ba3c2011-07-18 02:28:38 +00003236 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003237
cristy3ed852e2009-09-05 21:47:34 +00003238 /*
3239 Acquire pixels.
3240 */
cristye7cc7cf2010-09-21 13:26:47 +00003241 assert(image != (const Image *) NULL);
3242 assert(image->signature == MagickSignature);
3243 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003244 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003245 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003246 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003247 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003248 region.x=x;
3249 region.y=y;
3250 region.width=columns;
3251 region.height=rows;
3252 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003253 if (pixels == (Quantum *) NULL)
3254 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003255 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003256 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3257 nexus_info->region.x;
3258 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3259 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003260 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3261 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003262 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3263 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003264 {
3265 MagickBooleanType
3266 status;
3267
3268 /*
3269 Pixel request is inside cache extents.
3270 */
cristy4c08aed2011-07-01 19:47:50 +00003271 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003272 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003273 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3274 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003275 return((const Quantum *) NULL);
3276 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003277 {
cristy4c08aed2011-07-01 19:47:50 +00003278 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003279 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003280 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003281 }
cristyacd2ed22011-08-30 01:44:23 +00003282 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003283 }
3284 /*
3285 Pixel request is outside cache extents.
3286 */
cristy4c08aed2011-07-01 19:47:50 +00003287 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003288 virtual_nexus=AcquirePixelCacheNexus(1);
3289 if (virtual_nexus == (NexusInfo **) NULL)
3290 {
cristy4c08aed2011-07-01 19:47:50 +00003291 if (virtual_nexus != (NexusInfo **) NULL)
3292 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003293 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3294 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003295 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003296 }
cristy105ba3c2011-07-18 02:28:38 +00003297 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3298 sizeof(*virtual_pixel));
3299 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003300 switch (virtual_pixel_method)
3301 {
cristy4c08aed2011-07-01 19:47:50 +00003302 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003303 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003304 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003305 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003306 case MaskVirtualPixelMethod:
3307 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003308 case EdgeVirtualPixelMethod:
3309 case CheckerTileVirtualPixelMethod:
3310 case HorizontalTileVirtualPixelMethod:
3311 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003312 {
cristy4c08aed2011-07-01 19:47:50 +00003313 if (cache_info->metacontent_extent != 0)
3314 {
cristy6162bb42011-07-18 11:34:09 +00003315 /*
3316 Acquire a metacontent buffer.
3317 */
cristya64b85d2011-09-14 01:02:31 +00003318 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003319 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003320 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003321 {
cristy4c08aed2011-07-01 19:47:50 +00003322 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3323 (void) ThrowMagickException(exception,GetMagickModule(),
3324 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3325 return((const Quantum *) NULL);
3326 }
cristy105ba3c2011-07-18 02:28:38 +00003327 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003328 cache_info->metacontent_extent);
3329 }
3330 switch (virtual_pixel_method)
3331 {
3332 case BlackVirtualPixelMethod:
3333 {
cristy30301712011-07-18 15:06:51 +00003334 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3335 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003336 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3337 break;
3338 }
3339 case GrayVirtualPixelMethod:
3340 {
cristy30301712011-07-18 15:06:51 +00003341 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003342 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3343 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003344 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3345 break;
3346 }
3347 case TransparentVirtualPixelMethod:
3348 {
cristy30301712011-07-18 15:06:51 +00003349 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3350 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003351 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3352 break;
3353 }
3354 case MaskVirtualPixelMethod:
3355 case WhiteVirtualPixelMethod:
3356 {
cristy30301712011-07-18 15:06:51 +00003357 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3358 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003359 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3360 break;
3361 }
3362 default:
3363 {
cristy9e0719b2011-12-29 03:45:45 +00003364 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3365 virtual_pixel);
3366 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3367 virtual_pixel);
3368 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3369 virtual_pixel);
cristy6162bb42011-07-18 11:34:09 +00003370 if (image->colorspace == CMYKColorspace)
cristy9e0719b2011-12-29 03:45:45 +00003371 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3372 virtual_pixel);
3373 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3374 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003375 break;
3376 }
3377 }
cristy3ed852e2009-09-05 21:47:34 +00003378 break;
3379 }
3380 default:
cristy3ed852e2009-09-05 21:47:34 +00003381 break;
cristy3ed852e2009-09-05 21:47:34 +00003382 }
cristybb503372010-05-27 20:51:26 +00003383 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003384 {
cristybb503372010-05-27 20:51:26 +00003385 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003386 {
3387 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003388 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003389 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3390 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003391 {
3392 MagickModulo
3393 x_modulo,
3394 y_modulo;
3395
3396 /*
3397 Transfer a single pixel.
3398 */
3399 length=(MagickSizeType) 1;
3400 switch (virtual_pixel_method)
3401 {
cristy3ed852e2009-09-05 21:47:34 +00003402 default:
3403 {
3404 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003405 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003406 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003407 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003408 break;
3409 }
3410 case RandomVirtualPixelMethod:
3411 {
3412 if (cache_info->random_info == (RandomInfo *) NULL)
3413 cache_info->random_info=AcquireRandomInfo();
3414 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003415 RandomX(cache_info->random_info,cache_info->columns),
3416 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003417 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003418 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003419 break;
3420 }
3421 case DitherVirtualPixelMethod:
3422 {
3423 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003424 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003425 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003426 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003427 break;
3428 }
3429 case TileVirtualPixelMethod:
3430 {
3431 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3432 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3433 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003434 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003435 exception);
cristy4c08aed2011-07-01 19:47:50 +00003436 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003437 break;
3438 }
3439 case MirrorVirtualPixelMethod:
3440 {
3441 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3442 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003443 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003444 x_modulo.remainder-1L;
3445 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3446 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003447 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003448 y_modulo.remainder-1L;
3449 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003450 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003451 exception);
cristy4c08aed2011-07-01 19:47:50 +00003452 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003453 break;
3454 }
3455 case HorizontalTileEdgeVirtualPixelMethod:
3456 {
3457 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3458 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003459 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003460 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003461 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003462 break;
3463 }
3464 case VerticalTileEdgeVirtualPixelMethod:
3465 {
3466 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003468 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003469 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003470 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3471 break;
3472 }
3473 case BackgroundVirtualPixelMethod:
3474 case BlackVirtualPixelMethod:
3475 case GrayVirtualPixelMethod:
3476 case TransparentVirtualPixelMethod:
3477 case MaskVirtualPixelMethod:
3478 case WhiteVirtualPixelMethod:
3479 {
3480 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003481 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003482 break;
3483 }
3484 case EdgeVirtualPixelMethod:
3485 case CheckerTileVirtualPixelMethod:
3486 {
3487 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3488 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3489 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3490 {
3491 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003492 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003493 break;
3494 }
3495 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3496 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3497 exception);
3498 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3499 break;
3500 }
3501 case HorizontalTileVirtualPixelMethod:
3502 {
3503 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3504 {
3505 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003506 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003507 break;
3508 }
3509 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3510 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3511 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3512 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3513 exception);
3514 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3515 break;
3516 }
3517 case VerticalTileVirtualPixelMethod:
3518 {
3519 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3520 {
3521 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003522 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003523 break;
3524 }
3525 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3526 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3527 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3528 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3529 exception);
3530 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003531 break;
3532 }
3533 }
cristy4c08aed2011-07-01 19:47:50 +00003534 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003535 break;
cristyed231572011-07-14 02:18:59 +00003536 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003537 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003538 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003539 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003540 {
3541 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3542 s+=cache_info->metacontent_extent;
3543 }
cristy3ed852e2009-09-05 21:47:34 +00003544 continue;
3545 }
3546 /*
3547 Transfer a run of pixels.
3548 */
cristy4c08aed2011-07-01 19:47:50 +00003549 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3550 length,1UL,*virtual_nexus,exception);
3551 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003552 break;
cristy4c08aed2011-07-01 19:47:50 +00003553 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003554 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3555 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003556 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003557 {
cristy4c08aed2011-07-01 19:47:50 +00003558 (void) memcpy(s,r,(size_t) length);
3559 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003560 }
3561 }
3562 }
cristy4c08aed2011-07-01 19:47:50 +00003563 /*
3564 Free resources.
3565 */
cristy105ba3c2011-07-18 02:28:38 +00003566 if (virtual_metacontent != (void *) NULL)
3567 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003568 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3569 return(pixels);
3570}
3571
3572/*
3573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3574% %
3575% %
3576% %
3577+ G e t V i r t u a l P i x e l C a c h e %
3578% %
3579% %
3580% %
3581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582%
3583% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3584% cache as defined by the geometry parameters. A pointer to the pixels
3585% is returned if the pixels are transferred, otherwise a NULL is returned.
3586%
3587% The format of the GetVirtualPixelCache() method is:
3588%
cristy4c08aed2011-07-01 19:47:50 +00003589% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003590% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3591% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003592% ExceptionInfo *exception)
3593%
3594% A description of each parameter follows:
3595%
3596% o image: the image.
3597%
3598% o virtual_pixel_method: the virtual pixel method.
3599%
3600% o x,y,columns,rows: These values define the perimeter of a region of
3601% pixels.
3602%
3603% o exception: return any errors or warnings in this structure.
3604%
3605*/
cristy4c08aed2011-07-01 19:47:50 +00003606static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003607 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3608 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003609{
3610 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003611 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003612
cristy5c9e6f22010-09-17 17:31:01 +00003613 const int
3614 id = GetOpenMPThreadId();
3615
cristy4c08aed2011-07-01 19:47:50 +00003616 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003617 *p;
cristy4c08aed2011-07-01 19:47:50 +00003618
cristye7cc7cf2010-09-21 13:26:47 +00003619 assert(image != (const Image *) NULL);
3620 assert(image->signature == MagickSignature);
3621 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003622 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003623 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003624 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003625 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003626 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003627 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003628}
3629
3630/*
3631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3632% %
3633% %
3634% %
3635% G e t V i r t u a l P i x e l Q u e u e %
3636% %
3637% %
3638% %
3639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3640%
cristy4c08aed2011-07-01 19:47:50 +00003641% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3642% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003643%
3644% The format of the GetVirtualPixelQueue() method is:
3645%
cristy4c08aed2011-07-01 19:47:50 +00003646% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003647%
3648% A description of each parameter follows:
3649%
3650% o image: the image.
3651%
3652*/
cristy4c08aed2011-07-01 19:47:50 +00003653MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003654{
3655 CacheInfo
3656 *cache_info;
3657
cristy2036f5c2010-09-19 21:18:17 +00003658 const int
3659 id = GetOpenMPThreadId();
3660
cristy3ed852e2009-09-05 21:47:34 +00003661 assert(image != (const Image *) NULL);
3662 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003663 assert(image->cache != (Cache) NULL);
3664 cache_info=(CacheInfo *) image->cache;
3665 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003666 if (cache_info->methods.get_virtual_pixels_handler !=
3667 (GetVirtualPixelsHandler) NULL)
3668 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003669 assert(id < (int) cache_info->number_threads);
3670 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003671}
3672
3673/*
3674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3675% %
3676% %
3677% %
3678% G e t V i r t u a l P i x e l s %
3679% %
3680% %
3681% %
3682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3683%
3684% GetVirtualPixels() returns an immutable pixel region. If the
3685% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003686% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003687% copy of the pixels or it may point to the original pixels in memory.
3688% Performance is maximized if the selected region is part of one row, or one
3689% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003690% (without a copy) if the image is in memory, or in a memory-mapped file. The
3691% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003692%
3693% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003694% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3695% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3696% access the meta-content (of type void) corresponding to the the
3697% region.
cristy3ed852e2009-09-05 21:47:34 +00003698%
3699% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3700%
3701% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3702% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3703% GetCacheViewAuthenticPixels() instead.
3704%
3705% The format of the GetVirtualPixels() method is:
3706%
cristy4c08aed2011-07-01 19:47:50 +00003707% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003708% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003709% ExceptionInfo *exception)
3710%
3711% A description of each parameter follows:
3712%
3713% o image: the image.
3714%
3715% o x,y,columns,rows: These values define the perimeter of a region of
3716% pixels.
3717%
3718% o exception: return any errors or warnings in this structure.
3719%
3720*/
cristy4c08aed2011-07-01 19:47:50 +00003721MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003722 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3723 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003724{
3725 CacheInfo
3726 *cache_info;
3727
cristy2036f5c2010-09-19 21:18:17 +00003728 const int
3729 id = GetOpenMPThreadId();
3730
cristy4c08aed2011-07-01 19:47:50 +00003731 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003732 *p;
cristy4c08aed2011-07-01 19:47:50 +00003733
cristy3ed852e2009-09-05 21:47:34 +00003734 assert(image != (const Image *) NULL);
3735 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003736 assert(image->cache != (Cache) NULL);
3737 cache_info=(CacheInfo *) image->cache;
3738 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003739 if (cache_info->methods.get_virtual_pixel_handler !=
3740 (GetVirtualPixelHandler) NULL)
3741 return(cache_info->methods.get_virtual_pixel_handler(image,
3742 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003743 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003744 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003745 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003746 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003747}
3748
3749/*
3750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3751% %
3752% %
3753% %
3754+ 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 %
3755% %
3756% %
3757% %
3758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3759%
cristy4c08aed2011-07-01 19:47:50 +00003760% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3761% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003762%
3763% The format of the GetVirtualPixelsCache() method is:
3764%
cristy4c08aed2011-07-01 19:47:50 +00003765% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003766%
3767% A description of each parameter follows:
3768%
3769% o image: the image.
3770%
3771*/
cristy4c08aed2011-07-01 19:47:50 +00003772static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003773{
3774 CacheInfo
3775 *cache_info;
3776
cristy5c9e6f22010-09-17 17:31:01 +00003777 const int
3778 id = GetOpenMPThreadId();
3779
cristye7cc7cf2010-09-21 13:26:47 +00003780 assert(image != (const Image *) NULL);
3781 assert(image->signature == MagickSignature);
3782 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003783 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003784 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003785 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003786 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003787}
3788
3789/*
3790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3791% %
3792% %
3793% %
3794+ G e t V i r t u a l P i x e l s N e x u s %
3795% %
3796% %
3797% %
3798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3799%
3800% GetVirtualPixelsNexus() returns the pixels associated with the specified
3801% cache nexus.
3802%
3803% The format of the GetVirtualPixelsNexus() method is:
3804%
cristy4c08aed2011-07-01 19:47:50 +00003805% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003806% NexusInfo *nexus_info)
3807%
3808% A description of each parameter follows:
3809%
3810% o cache: the pixel cache.
3811%
3812% o nexus_info: the cache nexus to return the colormap pixels.
3813%
3814*/
cristya6577ff2011-09-02 19:54:26 +00003815MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003816 NexusInfo *nexus_info)
3817{
3818 CacheInfo
3819 *cache_info;
3820
cristye7cc7cf2010-09-21 13:26:47 +00003821 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003822 cache_info=(CacheInfo *) cache;
3823 assert(cache_info->signature == MagickSignature);
3824 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003825 return((Quantum *) NULL);
3826 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003827}
3828
3829/*
3830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3831% %
3832% %
3833% %
3834+ M a s k P i x e l C a c h e N e x u s %
3835% %
3836% %
3837% %
3838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3839%
3840% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3841% The method returns MagickTrue if the pixel region is masked, otherwise
3842% MagickFalse.
3843%
3844% The format of the MaskPixelCacheNexus() method is:
3845%
3846% MagickBooleanType MaskPixelCacheNexus(Image *image,
3847% NexusInfo *nexus_info,ExceptionInfo *exception)
3848%
3849% A description of each parameter follows:
3850%
3851% o image: the image.
3852%
3853% o nexus_info: the cache nexus to clip.
3854%
3855% o exception: return any errors or warnings in this structure.
3856%
3857*/
3858
cristy3aa93752011-12-18 15:54:24 +00003859static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3860 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003861{
3862 MagickRealType
3863 gamma;
3864
cristyaa83c2c2011-09-21 13:36:25 +00003865 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
cristy3ed852e2009-09-05 21:47:34 +00003866 {
3867 *composite=(*q);
3868 return;
3869 }
3870 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3871 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003872 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3873 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3874 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003875 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003876 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003877}
3878
3879static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3880 ExceptionInfo *exception)
3881{
3882 CacheInfo
3883 *cache_info;
3884
cristy4c08aed2011-07-01 19:47:50 +00003885 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003886 alpha,
3887 beta;
3888
3889 MagickSizeType
3890 number_pixels;
3891
3892 NexusInfo
3893 **clip_nexus,
3894 **image_nexus;
3895
cristy4c08aed2011-07-01 19:47:50 +00003896 register const Quantum
3897 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003898 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003899
cristy4c08aed2011-07-01 19:47:50 +00003900 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003901 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003902
cristye076a6e2010-08-15 19:59:43 +00003903 register ssize_t
3904 i;
3905
cristy3ed852e2009-09-05 21:47:34 +00003906 /*
3907 Apply clip mask.
3908 */
3909 if (image->debug != MagickFalse)
3910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3911 if (image->mask == (Image *) NULL)
3912 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003913 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003914 if (cache_info == (Cache) NULL)
3915 return(MagickFalse);
3916 image_nexus=AcquirePixelCacheNexus(1);
3917 clip_nexus=AcquirePixelCacheNexus(1);
3918 if ((image_nexus == (NexusInfo **) NULL) ||
3919 (clip_nexus == (NexusInfo **) NULL))
3920 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003921 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3922 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3923 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003924 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003925 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3926 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
cristyc82a27b2011-10-21 01:07:16 +00003927 nexus_info->region.height,clip_nexus[0],exception);
cristy4c08aed2011-07-01 19:47:50 +00003928 GetPixelInfo(image,&alpha);
3929 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003930 number_pixels=(MagickSizeType) nexus_info->region.width*
3931 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003932 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003933 {
cristy4c08aed2011-07-01 19:47:50 +00003934 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003935 break;
cristy803640d2011-11-17 02:11:32 +00003936 GetPixelInfoPixel(image,p,&alpha);
3937 GetPixelInfoPixel(image,q,&beta);
cristy3aa93752011-12-18 15:54:24 +00003938 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
cristy4c08aed2011-07-01 19:47:50 +00003939 &alpha,alpha.alpha,&beta);
3940 SetPixelRed(image,ClampToQuantum(beta.red),q);
3941 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3942 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3943 if (cache_info->colorspace == CMYKColorspace)
3944 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3945 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003946 p++;
3947 q++;
3948 r++;
3949 }
3950 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3951 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003952 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003953 return(MagickFalse);
3954 return(MagickTrue);
3955}
3956
3957/*
3958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3959% %
3960% %
3961% %
3962+ O p e n P i x e l C a c h e %
3963% %
3964% %
3965% %
3966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967%
3968% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3969% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003970% metacontent, and memory mapping the cache if it is disk based. The cache
3971% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003972%
3973% The format of the OpenPixelCache() method is:
3974%
3975% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3976% ExceptionInfo *exception)
3977%
3978% A description of each parameter follows:
3979%
3980% o image: the image.
3981%
3982% o mode: ReadMode, WriteMode, or IOMode.
3983%
3984% o exception: return any errors or warnings in this structure.
3985%
3986*/
3987
cristyd43a46b2010-01-21 02:13:41 +00003988static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003989{
3990 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003991 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003992 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003993 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003994 {
3995 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003996 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003997 cache_info->length);
3998 }
3999}
4000
4001static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4002{
4003 CacheInfo
4004 *cache_info;
4005
4006 MagickOffsetType
4007 count,
4008 extent,
4009 offset;
4010
4011 cache_info=(CacheInfo *) image->cache;
4012 if (image->debug != MagickFalse)
4013 {
4014 char
4015 format[MaxTextExtent],
4016 message[MaxTextExtent];
4017
cristyb9080c92009-12-01 20:13:26 +00004018 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004019 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00004020 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004021 cache_info->cache_filename,cache_info->file,format);
4022 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4023 }
4024 if (length != (MagickSizeType) ((MagickOffsetType) length))
4025 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00004026 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00004027 if (extent < 0)
4028 return(MagickFalse);
4029 if ((MagickSizeType) extent >= length)
4030 return(MagickTrue);
4031 offset=(MagickOffsetType) length-1;
4032 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4033 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4034}
4035
4036static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4037 ExceptionInfo *exception)
4038{
cristy3ed852e2009-09-05 21:47:34 +00004039 CacheInfo
4040 *cache_info,
4041 source_info;
4042
cristyf3a6a9d2010-11-07 21:02:56 +00004043 char
4044 format[MaxTextExtent],
4045 message[MaxTextExtent];
4046
cristy4c08aed2011-07-01 19:47:50 +00004047 MagickBooleanType
4048 status;
4049
cristy3ed852e2009-09-05 21:47:34 +00004050 MagickSizeType
4051 length,
4052 number_pixels;
4053
cristy3b8fe922011-12-29 18:56:23 +00004054 PixelChannelMap
4055 *p,
4056 *q;
4057
cristy3ed852e2009-09-05 21:47:34 +00004058 size_t
cristye076a6e2010-08-15 19:59:43 +00004059 columns,
cristy3ed852e2009-09-05 21:47:34 +00004060 packet_size;
4061
cristye7cc7cf2010-09-21 13:26:47 +00004062 assert(image != (const Image *) NULL);
4063 assert(image->signature == MagickSignature);
4064 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004065 if (image->debug != MagickFalse)
4066 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4067 if ((image->columns == 0) || (image->rows == 0))
4068 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4069 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004070 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004071 source_info=(*cache_info);
4072 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004073 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004074 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004075 cache_info->storage_class=image->storage_class;
4076 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00004077 cache_info->matte=image->matte;
cristy3ed852e2009-09-05 21:47:34 +00004078 cache_info->rows=image->rows;
4079 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00004080 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00004081 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00004082 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4083 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00004084 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00004085 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00004086 if (image->ping != MagickFalse)
4087 {
cristy73724512010-04-12 14:43:14 +00004088 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004089 cache_info->pixels=(Quantum *) NULL;
4090 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004091 cache_info->length=0;
4092 return(MagickTrue);
4093 }
cristy3ed852e2009-09-05 21:47:34 +00004094 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004095 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004096 if (image->metacontent_extent != 0)
4097 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004098 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004099 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004100 if (cache_info->columns != columns)
4101 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4102 image->filename);
4103 cache_info->length=length;
cristy3b8fe922011-12-29 18:56:23 +00004104 p=cache_info->channel_map;
4105 q=source_info.channel_map;
cristy4c08aed2011-07-01 19:47:50 +00004106 if ((cache_info->type != UndefinedCache) &&
4107 (cache_info->columns <= source_info.columns) &&
4108 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004109 (cache_info->number_channels <= source_info.number_channels) &&
cristy3b8fe922011-12-29 18:56:23 +00004110 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004111 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4112 {
4113 /*
4114 Inline pixel cache clone optimization.
4115 */
4116 if ((cache_info->columns == source_info.columns) &&
4117 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004118 (cache_info->number_channels == source_info.number_channels) &&
cristy32cacff2011-12-31 03:36:27 +00004119 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00004120 (cache_info->metacontent_extent == source_info.metacontent_extent))
4121 return(MagickTrue);
4122 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4123 }
cristy3ed852e2009-09-05 21:47:34 +00004124 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004125 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004126 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004127 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4128 {
4129 status=AcquireMagickResource(MemoryResource,cache_info->length);
4130 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4131 (cache_info->type == MemoryCache))
4132 {
cristyd43a46b2010-01-21 02:13:41 +00004133 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004134 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004135 cache_info->pixels=source_info.pixels;
4136 else
4137 {
4138 /*
4139 Create memory pixel cache.
4140 */
cristy4c08aed2011-07-01 19:47:50 +00004141 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004142 if (image->debug != MagickFalse)
4143 {
cristy32cacff2011-12-31 03:36:27 +00004144 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00004145 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004146 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4147 cache_info->filename,cache_info->mapped != MagickFalse ?
4148 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004149 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004150 format);
cristy3ed852e2009-09-05 21:47:34 +00004151 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4152 message);
4153 }
cristy3ed852e2009-09-05 21:47:34 +00004154 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004155 cache_info->metacontent=(void *) NULL;
4156 if (cache_info->metacontent_extent != 0)
4157 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004158 number_pixels*cache_info->number_channels);
cristyd2cb5a92011-12-31 20:10:15 +00004159 if (source_info.type != UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00004160 {
cristy4c08aed2011-07-01 19:47:50 +00004161 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004162 exception);
4163 RelinquishPixelCachePixels(&source_info);
4164 }
cristy4c08aed2011-07-01 19:47:50 +00004165 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004166 }
4167 }
4168 RelinquishMagickResource(MemoryResource,cache_info->length);
4169 }
4170 /*
4171 Create pixel cache on disk.
4172 */
4173 status=AcquireMagickResource(DiskResource,cache_info->length);
4174 if (status == MagickFalse)
4175 {
4176 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4177 "CacheResourcesExhausted","`%s'",image->filename);
4178 return(MagickFalse);
4179 }
cristyd2cb5a92011-12-31 20:10:15 +00004180 if (source_info.type != UndefinedCache)
4181 {
4182 (void) ClosePixelCacheOnDisk(cache_info);
4183 *cache_info->cache_filename='\0';
4184 }
cristy3ed852e2009-09-05 21:47:34 +00004185 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4186 {
4187 RelinquishMagickResource(DiskResource,cache_info->length);
4188 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4189 image->filename);
4190 return(MagickFalse);
4191 }
4192 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4193 cache_info->length);
4194 if (status == MagickFalse)
4195 {
4196 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4197 image->filename);
4198 return(MagickFalse);
4199 }
cristyed231572011-07-14 02:18:59 +00004200 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004201 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00004202 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00004203 cache_info->type=DiskCache;
4204 else
4205 {
4206 status=AcquireMagickResource(MapResource,cache_info->length);
4207 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4208 (cache_info->type != MemoryCache))
4209 cache_info->type=DiskCache;
4210 else
4211 {
cristy4c08aed2011-07-01 19:47:50 +00004212 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004213 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004214 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004215 {
cristy3ed852e2009-09-05 21:47:34 +00004216 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004217 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004218 }
4219 else
4220 {
4221 /*
4222 Create file-backed memory-mapped pixel cache.
4223 */
cristy4c08aed2011-07-01 19:47:50 +00004224 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004225 (void) ClosePixelCacheOnDisk(cache_info);
4226 cache_info->type=MapCache;
4227 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004228 cache_info->metacontent=(void *) NULL;
4229 if (cache_info->metacontent_extent != 0)
4230 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004231 number_pixels*cache_info->number_channels);
cristyd2cb5a92011-12-31 20:10:15 +00004232 if (source_info.type != UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00004233 {
4234 status=ClonePixelCachePixels(cache_info,&source_info,
4235 exception);
4236 RelinquishPixelCachePixels(&source_info);
4237 }
4238 if (image->debug != MagickFalse)
4239 {
cristy97e7a572009-12-05 15:07:53 +00004240 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004241 format);
cristyb51dff52011-05-19 16:55:47 +00004242 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004243 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004244 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004245 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004246 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004247 format);
cristy3ed852e2009-09-05 21:47:34 +00004248 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4249 message);
4250 }
cristy4c08aed2011-07-01 19:47:50 +00004251 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004252 }
4253 }
4254 RelinquishMagickResource(MapResource,cache_info->length);
4255 }
cristy4c08aed2011-07-01 19:47:50 +00004256 status=MagickTrue;
cristyd2cb5a92011-12-31 20:10:15 +00004257 if (source_info.type != UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00004258 {
4259 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4260 RelinquishPixelCachePixels(&source_info);
4261 }
4262 if (image->debug != MagickFalse)
4263 {
cristyb9080c92009-12-01 20:13:26 +00004264 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004265 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004266 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004267 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004268 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004269 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004270 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4271 }
cristy4c08aed2011-07-01 19:47:50 +00004272 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004273}
4274
4275/*
4276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4277% %
4278% %
4279% %
4280+ P e r s i s t P i x e l C a c h e %
4281% %
4282% %
4283% %
4284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4285%
4286% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4287% persistent pixel cache is one that resides on disk and is not destroyed
4288% when the program exits.
4289%
4290% The format of the PersistPixelCache() method is:
4291%
4292% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4293% const MagickBooleanType attach,MagickOffsetType *offset,
4294% ExceptionInfo *exception)
4295%
4296% A description of each parameter follows:
4297%
4298% o image: the image.
4299%
4300% o filename: the persistent pixel cache filename.
4301%
cristyf3a6a9d2010-11-07 21:02:56 +00004302% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004303%
cristy3ed852e2009-09-05 21:47:34 +00004304% o initialize: A value other than zero initializes the persistent pixel
4305% cache.
4306%
4307% o offset: the offset in the persistent cache to store pixels.
4308%
4309% o exception: return any errors or warnings in this structure.
4310%
4311*/
4312MagickExport MagickBooleanType PersistPixelCache(Image *image,
4313 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4314 ExceptionInfo *exception)
4315{
4316 CacheInfo
4317 *cache_info,
4318 *clone_info;
4319
4320 Image
4321 clone_image;
4322
cristy3ed852e2009-09-05 21:47:34 +00004323 MagickBooleanType
4324 status;
4325
cristye076a6e2010-08-15 19:59:43 +00004326 ssize_t
4327 page_size;
4328
cristy3ed852e2009-09-05 21:47:34 +00004329 assert(image != (Image *) NULL);
4330 assert(image->signature == MagickSignature);
4331 if (image->debug != MagickFalse)
4332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4333 assert(image->cache != (void *) NULL);
4334 assert(filename != (const char *) NULL);
4335 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004336 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004337 cache_info=(CacheInfo *) image->cache;
4338 assert(cache_info->signature == MagickSignature);
4339 if (attach != MagickFalse)
4340 {
4341 /*
cristy01b7eb02009-09-10 23:10:14 +00004342 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004343 */
4344 if (image->debug != MagickFalse)
4345 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004346 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004347 (void) CopyMagickString(cache_info->cache_filename,filename,
4348 MaxTextExtent);
4349 cache_info->type=DiskCache;
4350 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004351 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004352 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004353 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004354 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004355 }
cristy01b7eb02009-09-10 23:10:14 +00004356 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4357 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004358 {
cristyf84a1932010-01-03 18:00:18 +00004359 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004360 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004361 (cache_info->reference_count == 1))
4362 {
4363 int
4364 status;
4365
4366 /*
cristy01b7eb02009-09-10 23:10:14 +00004367 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004368 */
cristy320684d2011-09-23 14:55:47 +00004369 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004370 if (status == 0)
4371 {
4372 (void) CopyMagickString(cache_info->cache_filename,filename,
4373 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004374 *offset+=cache_info->length+page_size-(cache_info->length %
4375 page_size);
cristyf84a1932010-01-03 18:00:18 +00004376 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004377 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004378 if (image->debug != MagickFalse)
4379 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4380 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004381 return(MagickTrue);
4382 }
4383 }
cristyf84a1932010-01-03 18:00:18 +00004384 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004385 }
4386 /*
cristy01b7eb02009-09-10 23:10:14 +00004387 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004388 */
4389 clone_image=(*image);
4390 clone_info=(CacheInfo *) clone_image.cache;
4391 image->cache=ClonePixelCache(cache_info);
4392 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4393 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4394 cache_info->type=DiskCache;
4395 cache_info->offset=(*offset);
4396 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004397 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004398 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004399 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004400 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004401 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4402 return(status);
4403}
4404
4405/*
4406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4407% %
4408% %
4409% %
4410+ Q u e u e A u t h e n t i c N e x u s %
4411% %
4412% %
4413% %
4414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4415%
4416% QueueAuthenticNexus() allocates an region to store image pixels as defined
4417% by the region rectangle and returns a pointer to the region. This region is
4418% subsequently transferred from the pixel cache with
4419% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4420% pixels are transferred, otherwise a NULL is returned.
4421%
4422% The format of the QueueAuthenticNexus() method is:
4423%
cristy4c08aed2011-07-01 19:47:50 +00004424% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004425% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004426% const MagickBooleanType clone,NexusInfo *nexus_info,
4427% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004428%
4429% A description of each parameter follows:
4430%
4431% o image: the image.
4432%
4433% o x,y,columns,rows: These values define the perimeter of a region of
4434% pixels.
4435%
4436% o nexus_info: the cache nexus to set.
4437%
cristy65dbf172011-10-06 17:32:04 +00004438% o clone: clone the pixel cache.
4439%
cristy3ed852e2009-09-05 21:47:34 +00004440% o exception: return any errors or warnings in this structure.
4441%
4442*/
cristya6577ff2011-09-02 19:54:26 +00004443MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy65dbf172011-10-06 17:32:04 +00004444 const ssize_t y,const size_t columns,const size_t rows,
4445 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004446{
4447 CacheInfo
4448 *cache_info;
4449
4450 MagickOffsetType
4451 offset;
4452
4453 MagickSizeType
4454 number_pixels;
4455
4456 RectangleInfo
4457 region;
4458
4459 /*
4460 Validate pixel cache geometry.
4461 */
cristye7cc7cf2010-09-21 13:26:47 +00004462 assert(image != (const Image *) NULL);
4463 assert(image->signature == MagickSignature);
4464 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004465 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004466 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004467 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004468 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004469 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4470 {
4471 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4472 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004473 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004474 }
cristybb503372010-05-27 20:51:26 +00004475 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4476 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004477 {
4478 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4479 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004480 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004481 }
4482 offset=(MagickOffsetType) y*cache_info->columns+x;
4483 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004484 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004485 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4486 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4487 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004488 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004489 /*
4490 Return pixel cache.
4491 */
4492 region.x=x;
4493 region.y=y;
4494 region.width=columns;
4495 region.height=rows;
4496 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4497}
4498
4499/*
4500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4501% %
4502% %
4503% %
4504+ 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 %
4505% %
4506% %
4507% %
4508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4509%
4510% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4511% defined by the region rectangle and returns a pointer to the region. This
4512% region is subsequently transferred from the pixel cache with
4513% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4514% pixels are transferred, otherwise a NULL is returned.
4515%
4516% The format of the QueueAuthenticPixelsCache() method is:
4517%
cristy4c08aed2011-07-01 19:47:50 +00004518% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004519% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004520% ExceptionInfo *exception)
4521%
4522% A description of each parameter follows:
4523%
4524% o image: the image.
4525%
4526% o x,y,columns,rows: These values define the perimeter of a region of
4527% pixels.
4528%
4529% o exception: return any errors or warnings in this structure.
4530%
4531*/
cristy4c08aed2011-07-01 19:47:50 +00004532static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004533 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004534 ExceptionInfo *exception)
4535{
4536 CacheInfo
4537 *cache_info;
4538
cristy5c9e6f22010-09-17 17:31:01 +00004539 const int
4540 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004541
cristy4c08aed2011-07-01 19:47:50 +00004542 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004543 *q;
cristy4c08aed2011-07-01 19:47:50 +00004544
cristye7cc7cf2010-09-21 13:26:47 +00004545 assert(image != (const Image *) NULL);
4546 assert(image->signature == MagickSignature);
4547 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004548 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004549 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004550 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004551 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4552 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004553 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004554}
4555
4556/*
4557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4558% %
4559% %
4560% %
4561% Q u e u e A u t h e n t i c P i x e l s %
4562% %
4563% %
4564% %
4565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4566%
4567% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004568% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004569% region is returned, otherwise NULL is returned. The returned pointer may
4570% point to a temporary working buffer for the pixels or it may point to the
4571% final location of the pixels in memory.
4572%
4573% Write-only access means that any existing pixel values corresponding to
4574% the region are ignored. This is useful if the initial image is being
4575% created from scratch, or if the existing pixel values are to be
4576% completely replaced without need to refer to their pre-existing values.
4577% The application is free to read and write the pixel buffer returned by
4578% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4579% initialize the pixel array values. Initializing pixel array values is the
4580% application's responsibility.
4581%
4582% Performance is maximized if the selected region is part of one row, or
4583% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004584% pixels in-place (without a copy) if the image is in memory, or in a
4585% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004586% by the user.
4587%
4588% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004589% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4590% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4591% obtain the meta-content (of type void) corresponding to the region.
4592% Once the Quantum (and/or Quantum) array has been updated, the
4593% changes must be saved back to the underlying image using
4594% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004595%
4596% The format of the QueueAuthenticPixels() method is:
4597%
cristy4c08aed2011-07-01 19:47:50 +00004598% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004599% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004600% ExceptionInfo *exception)
4601%
4602% A description of each parameter follows:
4603%
4604% o image: the image.
4605%
4606% o x,y,columns,rows: These values define the perimeter of a region of
4607% pixels.
4608%
4609% o exception: return any errors or warnings in this structure.
4610%
4611*/
cristy4c08aed2011-07-01 19:47:50 +00004612MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004613 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004614 ExceptionInfo *exception)
4615{
4616 CacheInfo
4617 *cache_info;
4618
cristy2036f5c2010-09-19 21:18:17 +00004619 const int
4620 id = GetOpenMPThreadId();
4621
cristy4c08aed2011-07-01 19:47:50 +00004622 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004623 *q;
cristy4c08aed2011-07-01 19:47:50 +00004624
cristy3ed852e2009-09-05 21:47:34 +00004625 assert(image != (Image *) NULL);
4626 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004627 assert(image->cache != (Cache) NULL);
4628 cache_info=(CacheInfo *) image->cache;
4629 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004630 if (cache_info->methods.queue_authentic_pixels_handler !=
4631 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004632 {
cristyacd2ed22011-08-30 01:44:23 +00004633 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
cristy4c08aed2011-07-01 19:47:50 +00004634 columns,rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004635 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004636 }
cristy2036f5c2010-09-19 21:18:17 +00004637 assert(id < (int) cache_info->number_threads);
cristy65dbf172011-10-06 17:32:04 +00004638 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4639 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004640 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004641}
4642
4643/*
4644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4645% %
4646% %
4647% %
cristy4c08aed2011-07-01 19:47:50 +00004648+ 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 +00004649% %
4650% %
4651% %
4652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4653%
cristy4c08aed2011-07-01 19:47:50 +00004654% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004655% the pixel cache.
4656%
cristy4c08aed2011-07-01 19:47:50 +00004657% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004658%
cristy4c08aed2011-07-01 19:47:50 +00004659% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004660% NexusInfo *nexus_info,ExceptionInfo *exception)
4661%
4662% A description of each parameter follows:
4663%
4664% o cache_info: the pixel cache.
4665%
cristy4c08aed2011-07-01 19:47:50 +00004666% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004667%
4668% o exception: return any errors or warnings in this structure.
4669%
4670*/
cristy4c08aed2011-07-01 19:47:50 +00004671static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004672 NexusInfo *nexus_info,ExceptionInfo *exception)
4673{
4674 MagickOffsetType
4675 count,
4676 offset;
4677
4678 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004679 extent,
4680 length;
cristy3ed852e2009-09-05 21:47:34 +00004681
cristybb503372010-05-27 20:51:26 +00004682 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004683 y;
4684
cristy4c08aed2011-07-01 19:47:50 +00004685 register unsigned char
4686 *restrict q;
4687
cristybb503372010-05-27 20:51:26 +00004688 size_t
cristy3ed852e2009-09-05 21:47:34 +00004689 rows;
4690
cristy4c08aed2011-07-01 19:47:50 +00004691 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004692 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004693 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004694 return(MagickTrue);
4695 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4696 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004697 length=(MagickSizeType) nexus_info->region.width*
4698 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004699 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004700 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004701 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004702 switch (cache_info->type)
4703 {
4704 case MemoryCache:
4705 case MapCache:
4706 {
cristy4c08aed2011-07-01 19:47:50 +00004707 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004708 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004709
4710 /*
cristy4c08aed2011-07-01 19:47:50 +00004711 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004712 */
cristydd341db2010-03-04 19:06:38 +00004713 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004714 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004715 {
cristy48078b12010-09-23 17:11:01 +00004716 length=extent;
cristydd341db2010-03-04 19:06:38 +00004717 rows=1UL;
4718 }
cristy4c08aed2011-07-01 19:47:50 +00004719 p=(unsigned char *) cache_info->metacontent+offset*
4720 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004721 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004722 {
cristy8f036fe2010-09-18 02:02:00 +00004723 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004724 p+=cache_info->metacontent_extent*cache_info->columns;
4725 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004726 }
4727 break;
4728 }
4729 case DiskCache:
4730 {
4731 /*
cristy4c08aed2011-07-01 19:47:50 +00004732 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004733 */
4734 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4735 {
4736 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4737 cache_info->cache_filename);
4738 return(MagickFalse);
4739 }
cristydd341db2010-03-04 19:06:38 +00004740 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004741 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004742 {
cristy48078b12010-09-23 17:11:01 +00004743 length=extent;
cristydd341db2010-03-04 19:06:38 +00004744 rows=1UL;
4745 }
cristy48078b12010-09-23 17:11:01 +00004746 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004747 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004748 {
cristy48078b12010-09-23 17:11:01 +00004749 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004750 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004751 cache_info->metacontent_extent,length,(unsigned char *) q);
4752 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004753 break;
4754 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004755 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004756 }
cristybb503372010-05-27 20:51:26 +00004757 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004758 {
4759 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4760 cache_info->cache_filename);
4761 return(MagickFalse);
4762 }
4763 break;
4764 }
4765 default:
4766 break;
4767 }
4768 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004769 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004770 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004771 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004772 nexus_info->region.width,(double) nexus_info->region.height,(double)
4773 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004774 return(MagickTrue);
4775}
4776
4777/*
4778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4779% %
4780% %
4781% %
4782+ R e a d P i x e l C a c h e P i x e l s %
4783% %
4784% %
4785% %
4786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4787%
4788% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4789% cache.
4790%
4791% The format of the ReadPixelCachePixels() method is:
4792%
4793% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4794% NexusInfo *nexus_info,ExceptionInfo *exception)
4795%
4796% A description of each parameter follows:
4797%
4798% o cache_info: the pixel cache.
4799%
4800% o nexus_info: the cache nexus to read the pixels.
4801%
4802% o exception: return any errors or warnings in this structure.
4803%
4804*/
4805static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4806 NexusInfo *nexus_info,ExceptionInfo *exception)
4807{
4808 MagickOffsetType
4809 count,
4810 offset;
4811
4812 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004813 extent,
4814 length;
cristy3ed852e2009-09-05 21:47:34 +00004815
cristy4c08aed2011-07-01 19:47:50 +00004816 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004817 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004818
cristye076a6e2010-08-15 19:59:43 +00004819 register ssize_t
4820 y;
4821
cristybb503372010-05-27 20:51:26 +00004822 size_t
cristy3ed852e2009-09-05 21:47:34 +00004823 rows;
4824
cristy4c08aed2011-07-01 19:47:50 +00004825 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004826 return(MagickTrue);
4827 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4828 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004829 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004830 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004831 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004832 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004833 q=nexus_info->pixels;
4834 switch (cache_info->type)
4835 {
4836 case MemoryCache:
4837 case MapCache:
4838 {
cristy4c08aed2011-07-01 19:47:50 +00004839 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004840 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004841
4842 /*
4843 Read pixels from memory.
4844 */
cristydd341db2010-03-04 19:06:38 +00004845 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004846 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004847 {
cristy48078b12010-09-23 17:11:01 +00004848 length=extent;
cristydd341db2010-03-04 19:06:38 +00004849 rows=1UL;
4850 }
cristyed231572011-07-14 02:18:59 +00004851 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004852 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004853 {
cristy8f036fe2010-09-18 02:02:00 +00004854 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004855 p+=cache_info->number_channels*cache_info->columns;
4856 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004857 }
4858 break;
4859 }
4860 case DiskCache:
4861 {
4862 /*
4863 Read pixels from disk.
4864 */
4865 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4866 {
4867 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4868 cache_info->cache_filename);
4869 return(MagickFalse);
4870 }
cristydd341db2010-03-04 19:06:38 +00004871 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004872 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004873 {
cristy48078b12010-09-23 17:11:01 +00004874 length=extent;
cristydd341db2010-03-04 19:06:38 +00004875 rows=1UL;
4876 }
cristybb503372010-05-27 20:51:26 +00004877 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004878 {
4879 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004880 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004881 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004882 break;
4883 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004884 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004885 }
cristybb503372010-05-27 20:51:26 +00004886 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004887 {
4888 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4889 cache_info->cache_filename);
4890 return(MagickFalse);
4891 }
4892 break;
4893 }
4894 default:
4895 break;
4896 }
4897 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004898 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004899 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004900 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004901 nexus_info->region.width,(double) nexus_info->region.height,(double)
4902 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004903 return(MagickTrue);
4904}
4905
4906/*
4907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4908% %
4909% %
4910% %
4911+ R e f e r e n c e P i x e l C a c h e %
4912% %
4913% %
4914% %
4915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4916%
4917% ReferencePixelCache() increments the reference count associated with the
4918% pixel cache returning a pointer to the cache.
4919%
4920% The format of the ReferencePixelCache method is:
4921%
4922% Cache ReferencePixelCache(Cache cache_info)
4923%
4924% A description of each parameter follows:
4925%
4926% o cache_info: the pixel cache.
4927%
4928*/
cristya6577ff2011-09-02 19:54:26 +00004929MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004930{
4931 CacheInfo
4932 *cache_info;
4933
4934 assert(cache != (Cache *) NULL);
4935 cache_info=(CacheInfo *) cache;
4936 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004937 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004938 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004939 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004940 return(cache_info);
4941}
4942
4943/*
4944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4945% %
4946% %
4947% %
4948+ S e t P i x e l C a c h e M e t h o d s %
4949% %
4950% %
4951% %
4952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4953%
4954% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4955%
4956% The format of the SetPixelCacheMethods() method is:
4957%
4958% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4959%
4960% A description of each parameter follows:
4961%
4962% o cache: the pixel cache.
4963%
4964% o cache_methods: Specifies a pointer to a CacheMethods structure.
4965%
4966*/
cristya6577ff2011-09-02 19:54:26 +00004967MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004968{
4969 CacheInfo
4970 *cache_info;
4971
4972 GetOneAuthenticPixelFromHandler
4973 get_one_authentic_pixel_from_handler;
4974
4975 GetOneVirtualPixelFromHandler
4976 get_one_virtual_pixel_from_handler;
4977
4978 /*
4979 Set cache pixel methods.
4980 */
4981 assert(cache != (Cache) NULL);
4982 assert(cache_methods != (CacheMethods *) NULL);
4983 cache_info=(CacheInfo *) cache;
4984 assert(cache_info->signature == MagickSignature);
4985 if (cache_info->debug != MagickFalse)
4986 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4987 cache_info->filename);
4988 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4989 cache_info->methods.get_virtual_pixel_handler=
4990 cache_methods->get_virtual_pixel_handler;
4991 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4992 cache_info->methods.destroy_pixel_handler=
4993 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004994 if (cache_methods->get_virtual_metacontent_from_handler !=
4995 (GetVirtualMetacontentFromHandler) NULL)
4996 cache_info->methods.get_virtual_metacontent_from_handler=
4997 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004998 if (cache_methods->get_authentic_pixels_handler !=
4999 (GetAuthenticPixelsHandler) NULL)
5000 cache_info->methods.get_authentic_pixels_handler=
5001 cache_methods->get_authentic_pixels_handler;
5002 if (cache_methods->queue_authentic_pixels_handler !=
5003 (QueueAuthenticPixelsHandler) NULL)
5004 cache_info->methods.queue_authentic_pixels_handler=
5005 cache_methods->queue_authentic_pixels_handler;
5006 if (cache_methods->sync_authentic_pixels_handler !=
5007 (SyncAuthenticPixelsHandler) NULL)
5008 cache_info->methods.sync_authentic_pixels_handler=
5009 cache_methods->sync_authentic_pixels_handler;
5010 if (cache_methods->get_authentic_pixels_from_handler !=
5011 (GetAuthenticPixelsFromHandler) NULL)
5012 cache_info->methods.get_authentic_pixels_from_handler=
5013 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00005014 if (cache_methods->get_authentic_metacontent_from_handler !=
5015 (GetAuthenticMetacontentFromHandler) NULL)
5016 cache_info->methods.get_authentic_metacontent_from_handler=
5017 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00005018 get_one_virtual_pixel_from_handler=
5019 cache_info->methods.get_one_virtual_pixel_from_handler;
5020 if (get_one_virtual_pixel_from_handler !=
5021 (GetOneVirtualPixelFromHandler) NULL)
5022 cache_info->methods.get_one_virtual_pixel_from_handler=
5023 cache_methods->get_one_virtual_pixel_from_handler;
5024 get_one_authentic_pixel_from_handler=
5025 cache_methods->get_one_authentic_pixel_from_handler;
5026 if (get_one_authentic_pixel_from_handler !=
5027 (GetOneAuthenticPixelFromHandler) NULL)
5028 cache_info->methods.get_one_authentic_pixel_from_handler=
5029 cache_methods->get_one_authentic_pixel_from_handler;
5030}
5031
5032/*
5033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5034% %
5035% %
5036% %
5037+ S e t P i x e l C a c h e N e x u s P i x e l s %
5038% %
5039% %
5040% %
5041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5042%
5043% SetPixelCacheNexusPixels() defines the region of the cache for the
5044% specified cache nexus.
5045%
5046% The format of the SetPixelCacheNexusPixels() method is:
5047%
cristy4c08aed2011-07-01 19:47:50 +00005048% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005049% const RectangleInfo *region,NexusInfo *nexus_info,
5050% ExceptionInfo *exception)
5051%
5052% A description of each parameter follows:
5053%
5054% o image: the image.
5055%
5056% o region: A pointer to the RectangleInfo structure that defines the
5057% region of this particular cache nexus.
5058%
5059% o nexus_info: the cache nexus to set.
5060%
5061% o exception: return any errors or warnings in this structure.
5062%
5063*/
cristyabd6e372010-09-15 19:11:26 +00005064
5065static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5066 NexusInfo *nexus_info,ExceptionInfo *exception)
5067{
5068 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5069 return(MagickFalse);
5070 nexus_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00005071 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005072 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005073 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005074 {
5075 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005076 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005077 nexus_info->length);
5078 }
cristy4c08aed2011-07-01 19:47:50 +00005079 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005080 {
5081 (void) ThrowMagickException(exception,GetMagickModule(),
5082 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5083 cache_info->filename);
5084 return(MagickFalse);
5085 }
5086 return(MagickTrue);
5087}
5088
cristy4c08aed2011-07-01 19:47:50 +00005089static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005090 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5091{
5092 CacheInfo
5093 *cache_info;
5094
5095 MagickBooleanType
5096 status;
5097
cristy3ed852e2009-09-05 21:47:34 +00005098 MagickSizeType
5099 length,
5100 number_pixels;
5101
cristy3ed852e2009-09-05 21:47:34 +00005102 cache_info=(CacheInfo *) image->cache;
5103 assert(cache_info->signature == MagickSignature);
5104 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005105 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005106 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005107 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5108 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005109 {
cristybb503372010-05-27 20:51:26 +00005110 ssize_t
cristybad067a2010-02-15 17:20:55 +00005111 x,
5112 y;
cristy3ed852e2009-09-05 21:47:34 +00005113
cristyeaedf062010-05-29 22:36:02 +00005114 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5115 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005116 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5117 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005118 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005119 ((nexus_info->region.width == cache_info->columns) ||
5120 ((nexus_info->region.width % cache_info->columns) == 0)))))
5121 {
5122 MagickOffsetType
5123 offset;
5124
5125 /*
5126 Pixels are accessed directly from memory.
5127 */
5128 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5129 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005130 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005131 offset;
5132 nexus_info->metacontent=(void *) NULL;
5133 if (cache_info->metacontent_extent != 0)
5134 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5135 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005136 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005137 }
5138 }
5139 /*
5140 Pixels are stored in a cache region until they are synced to the cache.
5141 */
5142 number_pixels=(MagickSizeType) nexus_info->region.width*
5143 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005144 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005145 if (cache_info->metacontent_extent != 0)
5146 length+=number_pixels*cache_info->metacontent_extent;
5147 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005148 {
5149 nexus_info->length=length;
5150 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5151 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005152 {
5153 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005154 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005155 }
cristy3ed852e2009-09-05 21:47:34 +00005156 }
5157 else
5158 if (nexus_info->length != length)
5159 {
5160 RelinquishCacheNexusPixels(nexus_info);
5161 nexus_info->length=length;
5162 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5163 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005164 {
5165 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005166 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005167 }
cristy3ed852e2009-09-05 21:47:34 +00005168 }
5169 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005170 nexus_info->metacontent=(void *) NULL;
5171 if (cache_info->metacontent_extent != 0)
5172 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005173 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005174 return(nexus_info->pixels);
5175}
5176
5177/*
5178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179% %
5180% %
5181% %
5182% 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 %
5183% %
5184% %
5185% %
5186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5187%
5188% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5189% pixel cache and returns the previous setting. A virtual pixel is any pixel
5190% access that is outside the boundaries of the image cache.
5191%
5192% The format of the SetPixelCacheVirtualMethod() method is:
5193%
5194% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5195% const VirtualPixelMethod virtual_pixel_method)
5196%
5197% A description of each parameter follows:
5198%
5199% o image: the image.
5200%
5201% o virtual_pixel_method: choose the type of virtual pixel.
5202%
5203*/
cristyd1dd6e42011-09-04 01:46:08 +00005204MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005205 const VirtualPixelMethod virtual_pixel_method)
5206{
5207 CacheInfo
5208 *cache_info;
5209
5210 VirtualPixelMethod
5211 method;
5212
5213 assert(image != (Image *) NULL);
5214 assert(image->signature == MagickSignature);
5215 if (image->debug != MagickFalse)
5216 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5217 assert(image->cache != (Cache) NULL);
5218 cache_info=(CacheInfo *) image->cache;
5219 assert(cache_info->signature == MagickSignature);
5220 method=cache_info->virtual_pixel_method;
5221 cache_info->virtual_pixel_method=virtual_pixel_method;
5222 return(method);
5223}
5224
5225/*
5226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5227% %
5228% %
5229% %
5230+ 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 %
5231% %
5232% %
5233% %
5234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5235%
5236% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5237% in-memory or disk cache. The method returns MagickTrue if the pixel region
5238% is synced, otherwise MagickFalse.
5239%
5240% The format of the SyncAuthenticPixelCacheNexus() method is:
5241%
5242% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5243% NexusInfo *nexus_info,ExceptionInfo *exception)
5244%
5245% A description of each parameter follows:
5246%
5247% o image: the image.
5248%
5249% o nexus_info: the cache nexus to sync.
5250%
5251% o exception: return any errors or warnings in this structure.
5252%
5253*/
cristya6577ff2011-09-02 19:54:26 +00005254MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005255 NexusInfo *nexus_info,ExceptionInfo *exception)
5256{
5257 CacheInfo
5258 *cache_info;
5259
5260 MagickBooleanType
5261 status;
5262
5263 /*
5264 Transfer pixels to the cache.
5265 */
5266 assert(image != (Image *) NULL);
5267 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005268 if (image->cache == (Cache) NULL)
5269 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5270 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005271 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005272 if (cache_info->type == UndefinedCache)
5273 return(MagickFalse);
5274 if ((image->clip_mask != (Image *) NULL) &&
5275 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5276 return(MagickFalse);
5277 if ((image->mask != (Image *) NULL) &&
5278 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5279 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005280 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005281 return(MagickTrue);
5282 assert(cache_info->signature == MagickSignature);
5283 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005284 if ((cache_info->metacontent_extent != 0) &&
5285 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005286 return(MagickFalse);
5287 return(status);
5288}
5289
5290/*
5291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5292% %
5293% %
5294% %
5295+ S y n c A u t h e n t i c P i x e l C a c h e %
5296% %
5297% %
5298% %
5299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5300%
5301% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5302% or disk cache. The method returns MagickTrue if the pixel region is synced,
5303% otherwise MagickFalse.
5304%
5305% The format of the SyncAuthenticPixelsCache() method is:
5306%
5307% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5308% ExceptionInfo *exception)
5309%
5310% A description of each parameter follows:
5311%
5312% o image: the image.
5313%
5314% o exception: return any errors or warnings in this structure.
5315%
5316*/
5317static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5318 ExceptionInfo *exception)
5319{
5320 CacheInfo
5321 *cache_info;
5322
cristy5c9e6f22010-09-17 17:31:01 +00005323 const int
5324 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005325
cristy4c08aed2011-07-01 19:47:50 +00005326 MagickBooleanType
5327 status;
5328
cristye7cc7cf2010-09-21 13:26:47 +00005329 assert(image != (Image *) NULL);
5330 assert(image->signature == MagickSignature);
5331 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005332 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005333 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005334 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005335 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5336 exception);
5337 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005338}
5339
5340/*
5341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5342% %
5343% %
5344% %
5345% S y n c A u t h e n t i c P i x e l s %
5346% %
5347% %
5348% %
5349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5350%
5351% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5352% The method returns MagickTrue if the pixel region is flushed, otherwise
5353% MagickFalse.
5354%
5355% The format of the SyncAuthenticPixels() method is:
5356%
5357% MagickBooleanType SyncAuthenticPixels(Image *image,
5358% ExceptionInfo *exception)
5359%
5360% A description of each parameter follows:
5361%
5362% o image: the image.
5363%
5364% o exception: return any errors or warnings in this structure.
5365%
5366*/
5367MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5368 ExceptionInfo *exception)
5369{
5370 CacheInfo
5371 *cache_info;
5372
cristy2036f5c2010-09-19 21:18:17 +00005373 const int
5374 id = GetOpenMPThreadId();
5375
cristy4c08aed2011-07-01 19:47:50 +00005376 MagickBooleanType
5377 status;
5378
cristy3ed852e2009-09-05 21:47:34 +00005379 assert(image != (Image *) NULL);
5380 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005381 assert(image->cache != (Cache) NULL);
5382 cache_info=(CacheInfo *) image->cache;
5383 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005384 if (cache_info->methods.sync_authentic_pixels_handler !=
5385 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005386 {
5387 status=cache_info->methods.sync_authentic_pixels_handler(image,
5388 exception);
5389 return(status);
5390 }
cristy2036f5c2010-09-19 21:18:17 +00005391 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005392 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5393 exception);
5394 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005395}
5396
5397/*
5398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5399% %
5400% %
5401% %
cristyd1dd6e42011-09-04 01:46:08 +00005402+ 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 +00005403% %
5404% %
5405% %
5406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5407%
5408% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5409% The method returns MagickTrue if the pixel region is flushed, otherwise
5410% MagickFalse.
5411%
5412% The format of the SyncImagePixelCache() method is:
5413%
5414% MagickBooleanType SyncImagePixelCache(Image *image,
5415% ExceptionInfo *exception)
5416%
5417% A description of each parameter follows:
5418%
5419% o image: the image.
5420%
5421% o exception: return any errors or warnings in this structure.
5422%
5423*/
cristyd1dd6e42011-09-04 01:46:08 +00005424MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005425 ExceptionInfo *exception)
5426{
5427 CacheInfo
5428 *cache_info;
5429
5430 assert(image != (Image *) NULL);
5431 assert(exception != (ExceptionInfo *) NULL);
5432 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5433 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5434}
5435
5436/*
5437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5438% %
5439% %
5440% %
cristy4c08aed2011-07-01 19:47:50 +00005441+ 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 +00005442% %
5443% %
5444% %
5445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5446%
cristy4c08aed2011-07-01 19:47:50 +00005447% WritePixelCacheMetacontent() writes the meta-content to the specified region
5448% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005449%
cristy4c08aed2011-07-01 19:47:50 +00005450% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005451%
cristy4c08aed2011-07-01 19:47:50 +00005452% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005453% NexusInfo *nexus_info,ExceptionInfo *exception)
5454%
5455% A description of each parameter follows:
5456%
5457% o cache_info: the pixel cache.
5458%
cristy4c08aed2011-07-01 19:47:50 +00005459% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005460%
5461% o exception: return any errors or warnings in this structure.
5462%
5463*/
cristy4c08aed2011-07-01 19:47:50 +00005464static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005465 NexusInfo *nexus_info,ExceptionInfo *exception)
5466{
5467 MagickOffsetType
5468 count,
5469 offset;
5470
5471 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005472 extent,
5473 length;
cristy3ed852e2009-09-05 21:47:34 +00005474
cristy4c08aed2011-07-01 19:47:50 +00005475 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005476 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005477
cristybb503372010-05-27 20:51:26 +00005478 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005479 y;
5480
cristybb503372010-05-27 20:51:26 +00005481 size_t
cristy3ed852e2009-09-05 21:47:34 +00005482 rows;
5483
cristy4c08aed2011-07-01 19:47:50 +00005484 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005485 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005486 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005487 return(MagickTrue);
5488 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5489 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005490 length=(MagickSizeType) nexus_info->region.width*
5491 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005492 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005493 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005494 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005495 switch (cache_info->type)
5496 {
5497 case MemoryCache:
5498 case MapCache:
5499 {
cristy4c08aed2011-07-01 19:47:50 +00005500 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005501 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005502
5503 /*
cristy4c08aed2011-07-01 19:47:50 +00005504 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005505 */
cristydd341db2010-03-04 19:06:38 +00005506 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005507 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005508 {
cristy48078b12010-09-23 17:11:01 +00005509 length=extent;
cristydd341db2010-03-04 19:06:38 +00005510 rows=1UL;
5511 }
cristy4c08aed2011-07-01 19:47:50 +00005512 q=(unsigned char *) cache_info->metacontent+offset*
5513 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005514 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005515 {
cristy8f036fe2010-09-18 02:02:00 +00005516 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005517 p+=nexus_info->region.width*cache_info->metacontent_extent;
5518 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005519 }
5520 break;
5521 }
5522 case DiskCache:
5523 {
5524 /*
cristy4c08aed2011-07-01 19:47:50 +00005525 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005526 */
5527 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5528 {
5529 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5530 cache_info->cache_filename);
5531 return(MagickFalse);
5532 }
cristydd341db2010-03-04 19:06:38 +00005533 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005534 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005535 {
cristy48078b12010-09-23 17:11:01 +00005536 length=extent;
cristydd341db2010-03-04 19:06:38 +00005537 rows=1UL;
5538 }
cristy48078b12010-09-23 17:11:01 +00005539 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005540 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005541 {
cristy48078b12010-09-23 17:11:01 +00005542 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005543 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005544 cache_info->metacontent_extent,length,(const unsigned char *) p);
5545 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005546 break;
cristy4c08aed2011-07-01 19:47:50 +00005547 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005548 offset+=cache_info->columns;
5549 }
cristybb503372010-05-27 20:51:26 +00005550 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005551 {
5552 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5553 cache_info->cache_filename);
5554 return(MagickFalse);
5555 }
5556 break;
5557 }
5558 default:
5559 break;
5560 }
5561 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005562 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005563 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005564 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005565 nexus_info->region.width,(double) nexus_info->region.height,(double)
5566 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005567 return(MagickTrue);
5568}
5569
5570/*
5571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5572% %
5573% %
5574% %
5575+ W r i t e C a c h e P i x e l s %
5576% %
5577% %
5578% %
5579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5580%
5581% WritePixelCachePixels() writes image pixels to the specified region of the
5582% pixel cache.
5583%
5584% The format of the WritePixelCachePixels() method is:
5585%
5586% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5587% NexusInfo *nexus_info,ExceptionInfo *exception)
5588%
5589% A description of each parameter follows:
5590%
5591% o cache_info: the pixel cache.
5592%
5593% o nexus_info: the cache nexus to write the pixels.
5594%
5595% o exception: return any errors or warnings in this structure.
5596%
5597*/
5598static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5599 NexusInfo *nexus_info,ExceptionInfo *exception)
5600{
5601 MagickOffsetType
5602 count,
5603 offset;
5604
5605 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005606 extent,
5607 length;
cristy3ed852e2009-09-05 21:47:34 +00005608
cristy4c08aed2011-07-01 19:47:50 +00005609 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005610 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005611
cristybb503372010-05-27 20:51:26 +00005612 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005613 y;
5614
cristybb503372010-05-27 20:51:26 +00005615 size_t
cristy3ed852e2009-09-05 21:47:34 +00005616 rows;
5617
cristy4c08aed2011-07-01 19:47:50 +00005618 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005619 return(MagickTrue);
5620 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5621 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005622 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005623 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005624 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005625 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005626 p=nexus_info->pixels;
5627 switch (cache_info->type)
5628 {
5629 case MemoryCache:
5630 case MapCache:
5631 {
cristy4c08aed2011-07-01 19:47:50 +00005632 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005633 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005634
5635 /*
5636 Write pixels to memory.
5637 */
cristydd341db2010-03-04 19:06:38 +00005638 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005639 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005640 {
cristy48078b12010-09-23 17:11:01 +00005641 length=extent;
cristydd341db2010-03-04 19:06:38 +00005642 rows=1UL;
5643 }
cristyed231572011-07-14 02:18:59 +00005644 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005645 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005646 {
cristy8f036fe2010-09-18 02:02:00 +00005647 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005648 p+=nexus_info->region.width*cache_info->number_channels;
5649 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005650 }
5651 break;
5652 }
5653 case DiskCache:
5654 {
5655 /*
5656 Write pixels to disk.
5657 */
5658 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5659 {
5660 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5661 cache_info->cache_filename);
5662 return(MagickFalse);
5663 }
cristydd341db2010-03-04 19:06:38 +00005664 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005665 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005666 {
cristy48078b12010-09-23 17:11:01 +00005667 length=extent;
cristydd341db2010-03-04 19:06:38 +00005668 rows=1UL;
5669 }
cristybb503372010-05-27 20:51:26 +00005670 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005671 {
5672 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005673 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005674 p);
5675 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005676 break;
cristyed231572011-07-14 02:18:59 +00005677 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005678 offset+=cache_info->columns;
5679 }
cristybb503372010-05-27 20:51:26 +00005680 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005681 {
5682 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5683 cache_info->cache_filename);
5684 return(MagickFalse);
5685 }
5686 break;
5687 }
5688 default:
5689 break;
5690 }
5691 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005692 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005693 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005694 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005695 nexus_info->region.width,(double) nexus_info->region.height,(double)
5696 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005697 return(MagickTrue);
5698}