blob: fa4600dc94cff3aeb78eb2bf07198ca7bc487c27 [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"
cristyd2d11ec2012-03-28 13:53:49 +000057#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000058#include "MagickCore/pixel.h"
59#include "MagickCore/pixel-accessor.h"
60#include "MagickCore/policy.h"
61#include "MagickCore/quantum.h"
62#include "MagickCore/random_.h"
63#include "MagickCore/resource_.h"
64#include "MagickCore/semaphore.h"
65#include "MagickCore/splay-tree.h"
66#include "MagickCore/string_.h"
67#include "MagickCore/string-private.h"
68#include "MagickCore/thread-private.h"
69#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000070#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000071#if defined(MAGICKCORE_ZLIB_DELEGATE)
72#include "zlib.h"
73#endif
74
75/*
cristy30097232010-07-01 02:16:30 +000076 Define declarations.
77*/
78#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
cristyc11dace2012-01-24 16:39:46 +000079#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
80 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
cristy30097232010-07-01 02:16:30 +000081
82/*
cristy3ed852e2009-09-05 21:47:34 +000083 Typedef declarations.
84*/
85typedef struct _MagickModulo
86{
cristybb503372010-05-27 20:51:26 +000087 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000088 quotient,
89 remainder;
90} MagickModulo;
91
92struct _NexusInfo
93{
94 MagickBooleanType
95 mapped;
96
97 RectangleInfo
98 region;
99
100 MagickSizeType
101 length;
102
cristy4c08aed2011-07-01 19:47:50 +0000103 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000104 *cache,
105 *pixels;
106
cristy4c08aed2011-07-01 19:47:50 +0000107 void
108 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000109
cristybb503372010-05-27 20:51:26 +0000110 size_t
cristy3ed852e2009-09-05 21:47:34 +0000111 signature;
112};
113
114/*
115 Forward declarations.
116*/
117#if defined(__cplusplus) || defined(c_plusplus)
118extern "C" {
119#endif
120
cristy19596d62012-02-19 00:24:59 +0000121static Cache
122 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
123 magick_hot_spot;
124
cristy4c08aed2011-07-01 19:47:50 +0000125static const Quantum
cristybb503372010-05-27 20:51:26 +0000126 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000127 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 *GetVirtualPixelsCache(const Image *);
129
cristy4c08aed2011-07-01 19:47:50 +0000130static const void
131 *GetVirtualMetacontentFromCache(const Image *);
132
cristy3ed852e2009-09-05 21:47:34 +0000133static MagickBooleanType
cristy74ce05d2012-05-06 18:41:18 +0000134 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
135 ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000136 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000137 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000138 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000139 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000140 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
141 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000142 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
144
cristy4c08aed2011-07-01 19:47:50 +0000145static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000146 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
147 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000148 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
149 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000150 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristy19596d62012-02-19 00:24:59 +0000151 ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000152
153#if defined(__cplusplus) || defined(c_plusplus)
154}
155#endif
156
157/*
158 Global declarations.
159*/
160static volatile MagickBooleanType
161 instantiate_cache = MagickFalse;
162
163static SemaphoreInfo
164 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000165
166/*
167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168% %
169% %
170% %
171+ A c q u i r e P i x e l C a c h e %
172% %
173% %
174% %
175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176%
177% AcquirePixelCache() acquires a pixel cache.
178%
179% The format of the AcquirePixelCache() method is:
180%
cristybb503372010-05-27 20:51:26 +0000181% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000182%
183% A description of each parameter follows:
184%
185% o number_threads: the number of nexus threads.
186%
187*/
cristya6577ff2011-09-02 19:54:26 +0000188MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000189{
190 CacheInfo
191 *cache_info;
192
cristya64b85d2011-09-14 01:02:31 +0000193 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000194 if (cache_info == (CacheInfo *) NULL)
195 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
196 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
197 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000198 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000199 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000200 cache_info->file=(-1);
201 cache_info->id=GetMagickThreadId();
202 cache_info->number_threads=number_threads;
203 if (number_threads == 0)
cristyac245f82012-05-05 17:13:57 +0000204 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
206 if (cache_info->nexus_info == (NexusInfo **) NULL)
207 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000208 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000209 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000210 cache_info->disk_semaphore=AllocateSemaphoreInfo();
211 cache_info->debug=IsEventLogging();
212 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000213 return((Cache ) cache_info);
214}
215
216/*
217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218% %
219% %
220% %
221% A c q u i r e P i x e l C a c h e N e x u s %
222% %
223% %
224% %
225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226%
227% AcquirePixelCacheNexus() allocates the NexusInfo structure.
228%
229% The format of the AcquirePixelCacheNexus method is:
230%
cristybb503372010-05-27 20:51:26 +0000231% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000232%
233% A description of each parameter follows:
234%
235% o number_threads: the number of nexus threads.
236%
237*/
cristya6577ff2011-09-02 19:54:26 +0000238MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000239{
cristy3ed852e2009-09-05 21:47:34 +0000240 NexusInfo
241 **nexus_info;
242
cristye076a6e2010-08-15 19:59:43 +0000243 register ssize_t
244 i;
245
cristy64c3edf2012-04-13 18:50:13 +0000246 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000247 sizeof(*nexus_info));
248 if (nexus_info == (NexusInfo **) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000250 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
251 sizeof(**nexus_info));
252 if (nexus_info[0] == (NexusInfo *) NULL)
253 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
254 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000255 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000256 {
cristye5f87c82012-02-14 12:44:17 +0000257 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000258 nexus_info[i]->signature=MagickSignature;
259 }
260 return(nexus_info);
261}
262
263/*
264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265% %
266% %
267% %
cristyd43a46b2010-01-21 02:13:41 +0000268+ A c q u i r e P i x e l C a c h e P i x e l s %
269% %
270% %
271% %
272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273%
274% AcquirePixelCachePixels() returns the pixels associated with the specified
275% image.
276%
277% The format of the AcquirePixelCachePixels() method is:
278%
279% const void *AcquirePixelCachePixels(const Image *image,
280% MagickSizeType *length,ExceptionInfo *exception)
281%
282% A description of each parameter follows:
283%
284% o image: the image.
285%
286% o length: the pixel cache length.
287%
288% o exception: return any errors or warnings in this structure.
289%
290*/
cristyd1dd6e42011-09-04 01:46:08 +0000291MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000292 MagickSizeType *length,ExceptionInfo *exception)
293{
294 CacheInfo
295 *cache_info;
296
297 assert(image != (const Image *) NULL);
298 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000299 assert(exception != (ExceptionInfo *) NULL);
300 assert(exception->signature == MagickSignature);
301 assert(image->cache != (Cache) NULL);
302 cache_info=(CacheInfo *) image->cache;
303 assert(cache_info->signature == MagickSignature);
304 *length=0;
305 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
306 return((const void *) NULL);
307 *length=cache_info->length;
308 return((const void *) cache_info->pixels);
309}
310
311/*
312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313% %
314% %
315% %
cristyf34a1452009-10-24 22:29:27 +0000316+ C a c h e C o m p o n e n t G e n e s i s %
317% %
318% %
319% %
320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321%
322% CacheComponentGenesis() instantiates the cache component.
323%
324% The format of the CacheComponentGenesis method is:
325%
326% MagickBooleanType CacheComponentGenesis(void)
327%
328*/
cristy5ff4eaf2011-09-03 01:38:02 +0000329MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000330{
cristy165b6092009-10-26 13:52:10 +0000331 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000332 return(MagickTrue);
333}
334
335/*
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337% %
338% %
339% %
340+ C a c h e C o m p o n e n t T e r m i n u s %
341% %
342% %
343% %
344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345%
346% CacheComponentTerminus() destroys the cache component.
347%
348% The format of the CacheComponentTerminus() method is:
349%
350% CacheComponentTerminus(void)
351%
352*/
cristy5ff4eaf2011-09-03 01:38:02 +0000353MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000354{
cristy18b17442009-10-25 18:36:48 +0000355 if (cache_semaphore == (SemaphoreInfo *) NULL)
356 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000357 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000358 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000359 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000360 DestroySemaphoreInfo(&cache_semaphore);
361}
362
363/*
364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365% %
366% %
367% %
cristy3ed852e2009-09-05 21:47:34 +0000368+ C l o n e P i x e l C a c h e %
369% %
370% %
371% %
372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373%
374% ClonePixelCache() clones a pixel cache.
375%
376% The format of the ClonePixelCache() method is:
377%
378% Cache ClonePixelCache(const Cache cache)
379%
380% A description of each parameter follows:
381%
382% o cache: the pixel cache.
383%
384*/
cristya6577ff2011-09-02 19:54:26 +0000385MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000386{
387 CacheInfo
388 *clone_info;
389
390 const CacheInfo
391 *cache_info;
392
cristy9f027d12011-09-21 01:17:17 +0000393 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000394 cache_info=(const CacheInfo *) cache;
395 assert(cache_info->signature == MagickSignature);
396 if (cache_info->debug != MagickFalse)
397 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
398 cache_info->filename);
399 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
400 if (clone_info == (Cache) NULL)
401 return((Cache) NULL);
402 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
403 return((Cache ) clone_info);
404}
405
406/*
407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408% %
409% %
410% %
cristy60c44a82009-10-07 00:58:49 +0000411+ 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 +0000412% %
413% %
414% %
415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
416% ClonePixelCachePixels() clones the source pixel cache to the destination
417% cache.
418%
419% The format of the ClonePixelCachePixels() method is:
420%
421% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
422% CacheInfo *source_info,ExceptionInfo *exception)
423%
424% A description of each parameter follows:
425%
426% o cache_info: the pixel cache.
427%
428% o source_info: the source pixel cache.
429%
430% o exception: return any errors or warnings in this structure.
431%
432*/
433
434static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
435{
436 int
437 status;
438
cristy5ee247a2010-02-12 15:42:34 +0000439 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000440 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000441 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000442 {
443 status=close(cache_info->file);
444 cache_info->file=(-1);
445 RelinquishMagickResource(FileResource,1);
446 }
cristyf84a1932010-01-03 18:00:18 +0000447 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000448 return(status == -1 ? MagickFalse : MagickTrue);
449}
450
cristy3ed852e2009-09-05 21:47:34 +0000451static inline MagickSizeType MagickMax(const MagickSizeType x,
452 const MagickSizeType y)
453{
454 if (x > y)
455 return(x);
456 return(y);
457}
458
459static inline MagickSizeType MagickMin(const MagickSizeType x,
460 const MagickSizeType y)
461{
462 if (x < y)
463 return(x);
464 return(y);
465}
466
467static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
468 const MapMode mode)
469{
470 int
471 file;
472
473 /*
474 Open pixel cache on disk.
475 */
cristyf84a1932010-01-03 18:00:18 +0000476 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000477 if (cache_info->file != -1)
478 {
cristyf84a1932010-01-03 18:00:18 +0000479 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000480 return(MagickTrue); /* cache already open */
481 }
cristy3ed852e2009-09-05 21:47:34 +0000482 if (*cache_info->cache_filename == '\0')
483 file=AcquireUniqueFileResource(cache_info->cache_filename);
484 else
485 switch (mode)
486 {
487 case ReadMode:
488 {
cristy18c6c272011-09-23 14:40:37 +0000489 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000490 break;
491 }
492 case WriteMode:
493 {
cristy18c6c272011-09-23 14:40:37 +0000494 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
495 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000496 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000497 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000498 break;
499 }
500 case IOMode:
501 default:
502 {
cristy18c6c272011-09-23 14:40:37 +0000503 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000504 O_EXCL,S_MODE);
505 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000506 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000507 break;
508 }
509 }
510 if (file == -1)
511 {
cristyf84a1932010-01-03 18:00:18 +0000512 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000513 return(MagickFalse);
514 }
515 (void) AcquireMagickResource(FileResource,1);
516 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000517 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000518 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000519 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000520 return(MagickTrue);
521}
522
523static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
524 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000525 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000526{
527 register MagickOffsetType
528 i;
529
530 ssize_t
531 count;
532
cristy08a88202010-03-04 19:18:05 +0000533 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000534#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000535 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000536 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000537 {
cristyf84a1932010-01-03 18:00:18 +0000538 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000539 return((MagickOffsetType) -1);
540 }
541#endif
542 count=0;
543 for (i=0; i < (MagickOffsetType) length; i+=count)
544 {
545#if !defined(MAGICKCORE_HAVE_PREAD)
546 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
547 (MagickSizeType) SSIZE_MAX));
548#else
549 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000550 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000551#endif
552 if (count > 0)
553 continue;
554 count=0;
555 if (errno != EINTR)
556 {
557 i=(-1);
558 break;
559 }
560 }
561#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563#endif
564 return(i);
565}
566
567static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
568 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000569 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000570{
571 register MagickOffsetType
572 i;
573
574 ssize_t
575 count;
576
cristy08a88202010-03-04 19:18:05 +0000577 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000578#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000579 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000580 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000581 {
cristyf84a1932010-01-03 18:00:18 +0000582 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000583 return((MagickOffsetType) -1);
584 }
585#endif
586 count=0;
587 for (i=0; i < (MagickOffsetType) length; i+=count)
588 {
589#if !defined(MAGICKCORE_HAVE_PWRITE)
590 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
591 (MagickSizeType) SSIZE_MAX));
592#else
593 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000594 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000595#endif
596 if (count > 0)
597 continue;
598 count=0;
599 if (errno != EINTR)
600 {
601 i=(-1);
602 break;
603 }
604 }
605#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607#endif
608 return(i);
609}
610
cristy4c08aed2011-07-01 19:47:50 +0000611static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000612 CacheInfo *cache_info,ExceptionInfo *exception)
613{
614 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000615 count;
cristy3ed852e2009-09-05 21:47:34 +0000616
cristy4c08aed2011-07-01 19:47:50 +0000617 register MagickOffsetType
618 i;
cristye076a6e2010-08-15 19:59:43 +0000619
cristybb503372010-05-27 20:51:26 +0000620 size_t
cristy4c08aed2011-07-01 19:47:50 +0000621 length;
cristy3ed852e2009-09-05 21:47:34 +0000622
cristy4c08aed2011-07-01 19:47:50 +0000623 unsigned char
624 *blob;
625
626 /*
627 Clone pixel cache (both caches on disk).
628 */
cristy3ed852e2009-09-05 21:47:34 +0000629 if (cache_info->debug != MagickFalse)
630 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000631 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000632 sizeof(*blob));
633 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000634 {
cristy4c08aed2011-07-01 19:47:50 +0000635 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000636 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000637 cache_info->filename);
638 return(MagickFalse);
639 }
cristy3dedf062011-07-02 14:07:40 +0000640 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000641 {
642 blob=(unsigned char *) RelinquishMagickMemory(blob);
643 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
644 cache_info->cache_filename);
645 return(MagickFalse);
646 }
cristy3dedf062011-07-02 14:07:40 +0000647 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000648 {
649 (void) ClosePixelCacheOnDisk(cache_info);
650 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000651 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
652 clone_info->cache_filename);
653 return(MagickFalse);
654 }
cristy4c08aed2011-07-01 19:47:50 +0000655 count=0;
656 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000657 {
cristy4c08aed2011-07-01 19:47:50 +0000658 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
659 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
660 blob);
661 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000662 {
cristy4c08aed2011-07-01 19:47:50 +0000663 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
664 cache_info->cache_filename);
665 break;
cristy3ed852e2009-09-05 21:47:34 +0000666 }
cristy4c08aed2011-07-01 19:47:50 +0000667 length=(size_t) count;
668 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
669 if ((MagickSizeType) count != length)
670 {
671 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
672 clone_info->cache_filename);
673 break;
674 }
675 }
676 (void) ClosePixelCacheOnDisk(clone_info);
677 (void) ClosePixelCacheOnDisk(cache_info);
678 blob=(unsigned char *) RelinquishMagickMemory(blob);
679 if (i < (MagickOffsetType) cache_info->length)
680 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000681 return(MagickTrue);
682}
683
cristyfd24a062012-01-02 14:46:34 +0000684static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000685 CacheInfo *cache_info,ExceptionInfo *exception)
686{
687 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000688 count;
cristy3ed852e2009-09-05 21:47:34 +0000689
cristy4c08aed2011-07-01 19:47:50 +0000690 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000691 {
cristy3ed852e2009-09-05 21:47:34 +0000692 /*
cristy4c08aed2011-07-01 19:47:50 +0000693 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000694 */
cristy4c08aed2011-07-01 19:47:50 +0000695 if (cache_info->debug != MagickFalse)
696 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
697 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
698 cache_info->length);
699 return(MagickTrue);
700 }
701 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
702 {
703 /*
704 Clone pixel cache (one cache on disk, one in memory).
705 */
706 if (cache_info->debug != MagickFalse)
707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
708 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000709 {
cristy4c08aed2011-07-01 19:47:50 +0000710 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000711 cache_info->cache_filename);
712 return(MagickFalse);
713 }
cristy4c08aed2011-07-01 19:47:50 +0000714 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
715 cache_info->length,(unsigned char *) clone_info->pixels);
716 (void) ClosePixelCacheOnDisk(cache_info);
717 if ((MagickSizeType) count != cache_info->length)
718 {
719 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
720 cache_info->cache_filename);
721 return(MagickFalse);
722 }
723 return(MagickTrue);
724 }
725 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
726 {
727 /*
728 Clone pixel cache (one cache on disk, one in memory).
729 */
730 if (clone_info->debug != MagickFalse)
731 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
732 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
733 {
734 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
735 clone_info->cache_filename);
736 return(MagickFalse);
737 }
738 count=WritePixelCacheRegion(clone_info,clone_info->offset,
739 clone_info->length,(unsigned char *) cache_info->pixels);
740 (void) ClosePixelCacheOnDisk(clone_info);
741 if ((MagickSizeType) count != clone_info->length)
742 {
743 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
744 clone_info->cache_filename);
745 return(MagickFalse);
746 }
747 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000748 }
749 /*
cristy4c08aed2011-07-01 19:47:50 +0000750 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000751 */
cristy4c08aed2011-07-01 19:47:50 +0000752 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000753}
754
cristyfd24a062012-01-02 14:46:34 +0000755static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000756 CacheInfo *cache_info,ExceptionInfo *exception)
757{
cristy4c08aed2011-07-01 19:47:50 +0000758 MagickBooleanType
759 status;
cristy3ed852e2009-09-05 21:47:34 +0000760
cristy4c08aed2011-07-01 19:47:50 +0000761 MagickOffsetType
762 cache_offset,
763 clone_offset,
764 count;
765
766 register ssize_t
767 x;
768
cristyfd24a062012-01-02 14:46:34 +0000769 register unsigned char
770 *p;
771
cristy4c08aed2011-07-01 19:47:50 +0000772 size_t
cristy3ed852e2009-09-05 21:47:34 +0000773 length;
774
cristy4c08aed2011-07-01 19:47:50 +0000775 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000776 y;
777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000780
cristy4c08aed2011-07-01 19:47:50 +0000781 /*
782 Clone pixel cache (unoptimized).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000785 {
cristy4c08aed2011-07-01 19:47:50 +0000786 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
787 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
788 else
789 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
791 else
792 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
794 else
795 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
796 }
cristyed231572011-07-14 02:18:59 +0000797 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
798 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000799 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000800 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000801 if (blob == (unsigned char *) NULL)
802 {
803 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000804 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000805 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000806 return(MagickFalse);
807 }
cristy4c08aed2011-07-01 19:47:50 +0000808 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
809 cache_offset=0;
810 clone_offset=0;
811 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000814 {
cristy4c08aed2011-07-01 19:47:50 +0000815 blob=(unsigned char *) RelinquishMagickMemory(blob);
816 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000817 cache_info->cache_filename);
818 return(MagickFalse);
819 }
cristy4c08aed2011-07-01 19:47:50 +0000820 cache_offset=cache_info->offset;
821 }
822 if (clone_info->type == DiskCache)
823 {
cristy3dedf062011-07-02 14:07:40 +0000824 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000825 {
cristy4c08aed2011-07-01 19:47:50 +0000826 blob=(unsigned char *) RelinquishMagickMemory(blob);
827 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
828 clone_info->cache_filename);
829 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000830 }
cristy4c08aed2011-07-01 19:47:50 +0000831 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000832 }
833 /*
cristy4c08aed2011-07-01 19:47:50 +0000834 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000835 */
cristy4c08aed2011-07-01 19:47:50 +0000836 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000837 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000838 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000839 {
cristy4c08aed2011-07-01 19:47:50 +0000840 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000841 {
cristy9e0719b2011-12-29 03:45:45 +0000842 register ssize_t
843 i;
844
cristy3ed852e2009-09-05 21:47:34 +0000845 /*
cristy4c08aed2011-07-01 19:47:50 +0000846 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000847 */
cristyed231572011-07-14 02:18:59 +0000848 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000849 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000850 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000851 else
852 {
cristyfd24a062012-01-02 14:46:34 +0000853 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000854 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000855 {
cristy4c08aed2011-07-01 19:47:50 +0000856 status=MagickFalse;
857 break;
cristy3ed852e2009-09-05 21:47:34 +0000858 }
859 }
cristy4c08aed2011-07-01 19:47:50 +0000860 cache_offset+=length;
861 if ((y < (ssize_t) clone_info->rows) &&
862 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000863 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy9e0719b2011-12-29 03:45:45 +0000865 PixelChannel
866 channel;
867
868 PixelTrait
869 traits;
870
871 ssize_t
872 offset;
873
cristy4c08aed2011-07-01 19:47:50 +0000874 /*
cristy3b8fe922011-12-29 18:56:23 +0000875 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000876 */
cristy9e0719b2011-12-29 03:45:45 +0000877 channel=clone_info->channel_map[i].channel;
878 traits=cache_info->channel_map[channel].traits;
879 if (traits == UndefinedPixelTrait)
880 {
cristy0f4425e2011-12-31 20:33:02 +0000881 clone_offset+=sizeof(Quantum);
882 continue;
cristy9e0719b2011-12-29 03:45:45 +0000883 }
cristy0f4425e2011-12-31 20:33:02 +0000884 offset=cache_info->channel_map[channel].offset;
885 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000886 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
887 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000888 else
889 {
cristy0f4425e2011-12-31 20:33:02 +0000890 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000891 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000892 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000893 {
cristy0f4425e2011-12-31 20:33:02 +0000894 status=MagickFalse;
895 break;
cristy4c08aed2011-07-01 19:47:50 +0000896 }
897 }
cristy9e0719b2011-12-29 03:45:45 +0000898 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000899 }
900 }
cristyac245f82012-05-05 17:13:57 +0000901 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000902 {
903 /*
904 Set remaining columns as undefined.
905 */
cristy888e6132012-04-23 19:54:54 +0000906 length=clone_info->number_channels*sizeof(Quantum);
907 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
908 for ( ; x < (ssize_t) clone_info->columns; x++)
909 {
910 if (clone_info->type != DiskCache)
911 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
912 blob,length);
913 else
914 {
915 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
916 if ((MagickSizeType) count != length)
917 {
918 status=MagickFalse;
919 break;
cristye04362f2012-04-23 15:33:05 +0000920 }
cristy888e6132012-04-23 19:54:54 +0000921 }
922 clone_offset+=length;
923 }
cristye04362f2012-04-23 15:33:05 +0000924 }
cristy4c08aed2011-07-01 19:47:50 +0000925 }
cristyed231572011-07-14 02:18:59 +0000926 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000927 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
928 for ( ; y < (ssize_t) clone_info->rows; y++)
929 {
930 /*
cristy9e0719b2011-12-29 03:45:45 +0000931 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000932 */
933 for (x=0; x < (ssize_t) clone_info->columns; x++)
934 {
935 if (clone_info->type != DiskCache)
936 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
937 length);
938 else
939 {
940 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
941 if ((MagickSizeType) count != length)
942 {
943 status=MagickFalse;
944 break;
945 }
946 }
947 clone_offset+=length;
948 }
949 }
cristy9e0719b2011-12-29 03:45:45 +0000950 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000951 (clone_info->metacontent_extent != 0))
952 {
953 /*
954 Clone metacontent.
955 */
956 for (y=0; y < (ssize_t) cache_info->rows; y++)
957 {
958 for (x=0; x < (ssize_t) cache_info->columns; x++)
959 {
960 /*
961 Read a set of metacontent.
962 */
963 length=cache_info->metacontent_extent;
964 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000965 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000966 else
967 {
cristyfd24a062012-01-02 14:46:34 +0000968 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000969 if ((MagickSizeType) count != length)
970 {
971 status=MagickFalse;
972 break;
973 }
974 }
975 cache_offset+=length;
976 if ((y < (ssize_t) clone_info->rows) &&
977 (x < (ssize_t) clone_info->columns))
978 {
979 /*
980 Write a set of metacontent.
981 */
982 length=clone_info->metacontent_extent;
983 if (clone_info->type != DiskCache)
984 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000985 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000986 else
987 {
cristyfd24a062012-01-02 14:46:34 +0000988 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000989 if ((MagickSizeType) count != length)
990 {
991 status=MagickFalse;
992 break;
993 }
994 }
995 clone_offset+=length;
996 }
997 }
998 length=clone_info->metacontent_extent;
999 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1000 for ( ; x < (ssize_t) clone_info->columns; x++)
1001 {
1002 /*
cristy9e0719b2011-12-29 03:45:45 +00001003 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001004 */
1005 if (clone_info->type != DiskCache)
1006 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1007 blob,length);
1008 else
1009 {
cristy208b1002011-08-07 18:51:50 +00001010 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001011 if ((MagickSizeType) count != length)
1012 {
1013 status=MagickFalse;
1014 break;
1015 }
1016 }
1017 clone_offset+=length;
1018 }
1019 }
cristyac245f82012-05-05 17:13:57 +00001020 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001021 {
cristye04362f2012-04-23 15:33:05 +00001022 /*
1023 Set remaining rows as undefined.
1024 */
cristy888e6132012-04-23 19:54:54 +00001025 length=clone_info->metacontent_extent;
1026 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1027 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001028 {
cristy888e6132012-04-23 19:54:54 +00001029 for (x=0; x < (ssize_t) clone_info->columns; x++)
1030 {
1031 if (clone_info->type != DiskCache)
1032 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1033 blob,length);
1034 else
1035 {
1036 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1037 blob);
1038 if ((MagickSizeType) count != length)
1039 {
1040 status=MagickFalse;
1041 break;
1042 }
1043 }
1044 clone_offset+=length;
1045 }
cristye04362f2012-04-23 15:33:05 +00001046 }
cristy4c08aed2011-07-01 19:47:50 +00001047 }
cristy4c08aed2011-07-01 19:47:50 +00001048 }
1049 if (clone_info->type == DiskCache)
1050 (void) ClosePixelCacheOnDisk(clone_info);
1051 if (cache_info->type == DiskCache)
1052 (void) ClosePixelCacheOnDisk(cache_info);
1053 blob=(unsigned char *) RelinquishMagickMemory(blob);
1054 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001055}
1056
1057static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1058 CacheInfo *cache_info,ExceptionInfo *exception)
1059{
cristy3dfccb22011-12-28 21:47:20 +00001060 PixelChannelMap
1061 *p,
1062 *q;
1063
cristy5a7fbfb2010-11-06 16:10:59 +00001064 if (cache_info->type == PingCache)
1065 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001066 p=cache_info->channel_map;
1067 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001068 if ((cache_info->columns == clone_info->columns) &&
1069 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001070 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001071 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001072 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001073 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1074 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001075}
1076
1077/*
1078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079% %
1080% %
1081% %
1082+ C l o n e P i x e l C a c h e M e t h o d s %
1083% %
1084% %
1085% %
1086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087%
1088% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1089% another.
1090%
1091% The format of the ClonePixelCacheMethods() method is:
1092%
1093% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1094%
1095% A description of each parameter follows:
1096%
1097% o clone: Specifies a pointer to a Cache structure.
1098%
1099% o cache: the pixel cache.
1100%
1101*/
cristya6577ff2011-09-02 19:54:26 +00001102MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001103{
1104 CacheInfo
1105 *cache_info,
1106 *source_info;
1107
1108 assert(clone != (Cache) NULL);
1109 source_info=(CacheInfo *) clone;
1110 assert(source_info->signature == MagickSignature);
1111 if (source_info->debug != MagickFalse)
1112 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1113 source_info->filename);
1114 assert(cache != (Cache) NULL);
1115 cache_info=(CacheInfo *) cache;
1116 assert(cache_info->signature == MagickSignature);
1117 source_info->methods=cache_info->methods;
1118}
1119
1120/*
1121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122% %
1123% %
1124% %
1125+ D e s t r o y I m a g e P i x e l C a c h e %
1126% %
1127% %
1128% %
1129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130%
1131% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1132%
1133% The format of the DestroyImagePixelCache() method is:
1134%
1135% void DestroyImagePixelCache(Image *image)
1136%
1137% A description of each parameter follows:
1138%
1139% o image: the image.
1140%
1141*/
1142static void DestroyImagePixelCache(Image *image)
1143{
1144 assert(image != (Image *) NULL);
1145 assert(image->signature == MagickSignature);
1146 if (image->debug != MagickFalse)
1147 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1148 if (image->cache == (void *) NULL)
1149 return;
1150 image->cache=DestroyPixelCache(image->cache);
1151}
1152
1153/*
1154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155% %
1156% %
1157% %
1158+ D e s t r o y I m a g e P i x e l s %
1159% %
1160% %
1161% %
1162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1163%
1164% DestroyImagePixels() deallocates memory associated with the pixel cache.
1165%
1166% The format of the DestroyImagePixels() method is:
1167%
1168% void DestroyImagePixels(Image *image)
1169%
1170% A description of each parameter follows:
1171%
1172% o image: the image.
1173%
1174*/
1175MagickExport void DestroyImagePixels(Image *image)
1176{
1177 CacheInfo
1178 *cache_info;
1179
1180 assert(image != (const Image *) NULL);
1181 assert(image->signature == MagickSignature);
1182 if (image->debug != MagickFalse)
1183 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1184 assert(image->cache != (Cache) NULL);
1185 cache_info=(CacheInfo *) image->cache;
1186 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001187 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1188 {
1189 cache_info->methods.destroy_pixel_handler(image);
1190 return;
1191 }
cristy2036f5c2010-09-19 21:18:17 +00001192 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001193}
1194
1195/*
1196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197% %
1198% %
1199% %
1200+ D e s t r o y P i x e l C a c h e %
1201% %
1202% %
1203% %
1204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205%
1206% DestroyPixelCache() deallocates memory associated with the pixel cache.
1207%
1208% The format of the DestroyPixelCache() method is:
1209%
1210% Cache DestroyPixelCache(Cache cache)
1211%
1212% A description of each parameter follows:
1213%
1214% o cache: the pixel cache.
1215%
1216*/
1217
1218static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1219{
1220 switch (cache_info->type)
1221 {
1222 case MemoryCache:
1223 {
1224 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001225 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001226 cache_info->pixels);
1227 else
cristy4c08aed2011-07-01 19:47:50 +00001228 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001229 (size_t) cache_info->length);
1230 RelinquishMagickResource(MemoryResource,cache_info->length);
1231 break;
1232 }
1233 case MapCache:
1234 {
cristy4c08aed2011-07-01 19:47:50 +00001235 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001236 cache_info->length);
1237 RelinquishMagickResource(MapResource,cache_info->length);
1238 }
1239 case DiskCache:
1240 {
1241 if (cache_info->file != -1)
1242 (void) ClosePixelCacheOnDisk(cache_info);
1243 RelinquishMagickResource(DiskResource,cache_info->length);
1244 break;
1245 }
1246 default:
1247 break;
1248 }
1249 cache_info->type=UndefinedCache;
1250 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001251 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001252}
1253
cristya6577ff2011-09-02 19:54:26 +00001254MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001255{
1256 CacheInfo
1257 *cache_info;
1258
cristy3ed852e2009-09-05 21:47:34 +00001259 assert(cache != (Cache) NULL);
1260 cache_info=(CacheInfo *) cache;
1261 assert(cache_info->signature == MagickSignature);
1262 if (cache_info->debug != MagickFalse)
1263 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1264 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001265 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001266 cache_info->reference_count--;
1267 if (cache_info->reference_count != 0)
1268 {
cristyf84a1932010-01-03 18:00:18 +00001269 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001270 return((Cache) NULL);
1271 }
cristyf84a1932010-01-03 18:00:18 +00001272 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001273 if (cache_info->debug != MagickFalse)
1274 {
1275 char
1276 message[MaxTextExtent];
1277
cristyb51dff52011-05-19 16:55:47 +00001278 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001279 cache_info->filename);
1280 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1281 }
cristyc2e1bdd2009-09-10 23:43:34 +00001282 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1283 (cache_info->type != DiskCache)))
1284 RelinquishPixelCachePixels(cache_info);
1285 else
1286 {
1287 RelinquishPixelCachePixels(cache_info);
1288 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1289 }
cristy3ed852e2009-09-05 21:47:34 +00001290 *cache_info->cache_filename='\0';
1291 if (cache_info->nexus_info != (NexusInfo **) NULL)
1292 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1293 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001294 if (cache_info->random_info != (RandomInfo *) NULL)
1295 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001296 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1297 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1298 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1299 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001300 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001301 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001302 cache=(Cache) NULL;
1303 return(cache);
1304}
1305
1306/*
1307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308% %
1309% %
1310% %
1311+ D e s t r o y P i x e l C a c h e N e x u s %
1312% %
1313% %
1314% %
1315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316%
1317% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1318%
1319% The format of the DestroyPixelCacheNexus() method is:
1320%
1321% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001322% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001323%
1324% A description of each parameter follows:
1325%
1326% o nexus_info: the nexus to destroy.
1327%
1328% o number_threads: the number of nexus threads.
1329%
1330*/
1331
1332static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1333{
1334 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001335 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001336 else
1337 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001338 nexus_info->cache=(Quantum *) NULL;
1339 nexus_info->pixels=(Quantum *) NULL;
1340 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001341 nexus_info->length=0;
1342 nexus_info->mapped=MagickFalse;
1343}
1344
cristya6577ff2011-09-02 19:54:26 +00001345MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001346 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001347{
cristybb503372010-05-27 20:51:26 +00001348 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001349 i;
1350
1351 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001352 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001353 {
cristy4c08aed2011-07-01 19:47:50 +00001354 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001355 RelinquishCacheNexusPixels(nexus_info[i]);
1356 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001357 }
cristye5f87c82012-02-14 12:44:17 +00001358 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001359 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001360 return(nexus_info);
1361}
1362
1363/*
1364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365% %
1366% %
1367% %
cristy4c08aed2011-07-01 19:47:50 +00001368% 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 +00001369% %
1370% %
1371% %
1372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373%
cristy4c08aed2011-07-01 19:47:50 +00001374% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1375% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1376% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001377%
cristy4c08aed2011-07-01 19:47:50 +00001378% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001379%
cristy4c08aed2011-07-01 19:47:50 +00001380% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001381%
1382% A description of each parameter follows:
1383%
1384% o image: the image.
1385%
1386*/
cristy4c08aed2011-07-01 19:47:50 +00001387MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001388{
1389 CacheInfo
1390 *cache_info;
1391
cristy5c9e6f22010-09-17 17:31:01 +00001392 const int
1393 id = GetOpenMPThreadId();
1394
cristy4c08aed2011-07-01 19:47:50 +00001395 void
1396 *metacontent;
1397
cristye7cc7cf2010-09-21 13:26:47 +00001398 assert(image != (const Image *) NULL);
1399 assert(image->signature == MagickSignature);
1400 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001401 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001402 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001403 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1404 (GetAuthenticMetacontentFromHandler) NULL)
1405 {
1406 metacontent=cache_info->methods.
1407 get_authentic_metacontent_from_handler(image);
1408 return(metacontent);
1409 }
cristy6ebe97c2010-07-03 01:17:28 +00001410 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001411 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1412 cache_info->nexus_info[id]);
1413 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001414}
1415
1416/*
1417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418% %
1419% %
1420% %
cristy4c08aed2011-07-01 19:47:50 +00001421+ 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 +00001422% %
1423% %
1424% %
1425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426%
cristy4c08aed2011-07-01 19:47:50 +00001427% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1428% with the last call to QueueAuthenticPixelsCache() or
1429% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001430%
cristy4c08aed2011-07-01 19:47:50 +00001431% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001432%
cristy4c08aed2011-07-01 19:47:50 +00001433% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001434%
1435% A description of each parameter follows:
1436%
1437% o image: the image.
1438%
1439*/
cristy4c08aed2011-07-01 19:47:50 +00001440static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001441{
1442 CacheInfo
1443 *cache_info;
1444
cristy2036f5c2010-09-19 21:18:17 +00001445 const int
1446 id = GetOpenMPThreadId();
1447
cristy4c08aed2011-07-01 19:47:50 +00001448 void
1449 *metacontent;
1450
cristy3ed852e2009-09-05 21:47:34 +00001451 assert(image != (const Image *) NULL);
1452 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001453 assert(image->cache != (Cache) NULL);
1454 cache_info=(CacheInfo *) image->cache;
1455 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001456 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001457 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1458 cache_info->nexus_info[id]);
1459 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001460}
1461
1462/*
1463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464% %
1465% %
1466% %
1467+ 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 %
1468% %
1469% %
1470% %
1471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1472%
1473% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1474% disk pixel cache as defined by the geometry parameters. A pointer to the
1475% pixels is returned if the pixels are transferred, otherwise a NULL is
1476% returned.
1477%
1478% The format of the GetAuthenticPixelCacheNexus() method is:
1479%
cristy4c08aed2011-07-01 19:47:50 +00001480% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001481% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001482% NexusInfo *nexus_info,ExceptionInfo *exception)
1483%
1484% A description of each parameter follows:
1485%
1486% o image: the image.
1487%
1488% o x,y,columns,rows: These values define the perimeter of a region of
1489% pixels.
1490%
1491% o nexus_info: the cache nexus to return.
1492%
1493% o exception: return any errors or warnings in this structure.
1494%
1495*/
1496
cristy4c08aed2011-07-01 19:47:50 +00001497static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001498 NexusInfo *nexus_info)
1499{
cristy4c08aed2011-07-01 19:47:50 +00001500 MagickBooleanType
1501 status;
1502
cristy3ed852e2009-09-05 21:47:34 +00001503 MagickOffsetType
1504 offset;
1505
cristy73724512010-04-12 14:43:14 +00001506 if (cache_info->type == PingCache)
1507 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001508 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1509 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001510 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001511 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001512 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001513}
1514
cristya6577ff2011-09-02 19:54:26 +00001515MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001516 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001517 NexusInfo *nexus_info,ExceptionInfo *exception)
1518{
1519 CacheInfo
1520 *cache_info;
1521
cristy4c08aed2011-07-01 19:47:50 +00001522 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001523 *q;
cristy3ed852e2009-09-05 21:47:34 +00001524
1525 /*
1526 Transfer pixels from the cache.
1527 */
1528 assert(image != (Image *) NULL);
1529 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001530 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1531 exception);
cristyacd2ed22011-08-30 01:44:23 +00001532 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001533 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001534 cache_info=(CacheInfo *) image->cache;
1535 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001536 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001537 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001538 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001539 return((Quantum *) NULL);
1540 if (cache_info->metacontent_extent != 0)
1541 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1542 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001543 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001544}
1545
1546/*
1547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1548% %
1549% %
1550% %
1551+ 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 %
1552% %
1553% %
1554% %
1555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556%
1557% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1558% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1559%
1560% The format of the GetAuthenticPixelsFromCache() method is:
1561%
cristy4c08aed2011-07-01 19:47:50 +00001562% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001563%
1564% A description of each parameter follows:
1565%
1566% o image: the image.
1567%
1568*/
cristy4c08aed2011-07-01 19:47:50 +00001569static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001570{
1571 CacheInfo
1572 *cache_info;
1573
cristy5c9e6f22010-09-17 17:31:01 +00001574 const int
1575 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001576
cristye7cc7cf2010-09-21 13:26:47 +00001577 assert(image != (const Image *) NULL);
1578 assert(image->signature == MagickSignature);
1579 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001580 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001581 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001582 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001583 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001584}
1585
1586/*
1587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588% %
1589% %
1590% %
1591% G e t A u t h e n t i c P i x e l Q u e u e %
1592% %
1593% %
1594% %
1595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596%
cristy4c08aed2011-07-01 19:47:50 +00001597% GetAuthenticPixelQueue() returns the authentic pixels associated
1598% corresponding with the last call to QueueAuthenticPixels() or
1599% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001600%
1601% The format of the GetAuthenticPixelQueue() method is:
1602%
cristy4c08aed2011-07-01 19:47:50 +00001603% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001604%
1605% A description of each parameter follows:
1606%
1607% o image: the image.
1608%
1609*/
cristy4c08aed2011-07-01 19:47:50 +00001610MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001611{
1612 CacheInfo
1613 *cache_info;
1614
cristy2036f5c2010-09-19 21:18:17 +00001615 const int
1616 id = GetOpenMPThreadId();
1617
cristy3ed852e2009-09-05 21:47:34 +00001618 assert(image != (const Image *) NULL);
1619 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001620 assert(image->cache != (Cache) NULL);
1621 cache_info=(CacheInfo *) image->cache;
1622 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001623 if (cache_info->methods.get_authentic_pixels_from_handler !=
1624 (GetAuthenticPixelsFromHandler) NULL)
1625 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001626 assert(id < (int) cache_info->number_threads);
1627 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
1635% G e t A u t h e n t i c P i x e l s %
1636% %
1637% %
cristy4c08aed2011-07-01 19:47:50 +00001638% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001639%
1640% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001641% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001642% representing the region is returned, otherwise NULL is returned.
1643%
1644% The returned pointer may point to a temporary working copy of the pixels
1645% or it may point to the original pixels in memory. Performance is maximized
1646% if the selected region is part of one row, or one or more full rows, since
1647% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001648% if the image is in memory, or in a memory-mapped file. The returned pointer
1649% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001650%
1651% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001652% Quantum. If the image has corresponding metacontent,call
1653% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1654% meta-content corresponding to the region. Once the Quantum array has
1655% been updated, the changes must be saved back to the underlying image using
1656% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001657%
1658% The format of the GetAuthenticPixels() method is:
1659%
cristy4c08aed2011-07-01 19:47:50 +00001660% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001661% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001662% ExceptionInfo *exception)
1663%
1664% A description of each parameter follows:
1665%
1666% o image: the image.
1667%
1668% o x,y,columns,rows: These values define the perimeter of a region of
1669% pixels.
1670%
1671% o exception: return any errors or warnings in this structure.
1672%
1673*/
cristy4c08aed2011-07-01 19:47:50 +00001674MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001675 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001676 ExceptionInfo *exception)
1677{
1678 CacheInfo
1679 *cache_info;
1680
cristy2036f5c2010-09-19 21:18:17 +00001681 const int
1682 id = GetOpenMPThreadId();
1683
cristy4c08aed2011-07-01 19:47:50 +00001684 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001685 *q;
cristy4c08aed2011-07-01 19:47:50 +00001686
cristy3ed852e2009-09-05 21:47:34 +00001687 assert(image != (Image *) NULL);
1688 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001689 assert(image->cache != (Cache) NULL);
1690 cache_info=(CacheInfo *) image->cache;
1691 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001692 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001693 (GetAuthenticPixelsHandler) NULL)
1694 {
cristyacd2ed22011-08-30 01:44:23 +00001695 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1696 exception);
1697 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001698 }
cristy2036f5c2010-09-19 21:18:17 +00001699 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001700 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001701 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001702 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001703}
1704
1705/*
1706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707% %
1708% %
1709% %
1710+ G e t A u t h e n t i c P i x e l s C a c h e %
1711% %
1712% %
1713% %
1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715%
1716% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1717% as defined by the geometry parameters. A pointer to the pixels is returned
1718% if the pixels are transferred, otherwise a NULL is returned.
1719%
1720% The format of the GetAuthenticPixelsCache() method is:
1721%
cristy4c08aed2011-07-01 19:47:50 +00001722% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001723% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001724% ExceptionInfo *exception)
1725%
1726% A description of each parameter follows:
1727%
1728% o image: the image.
1729%
1730% o x,y,columns,rows: These values define the perimeter of a region of
1731% pixels.
1732%
1733% o exception: return any errors or warnings in this structure.
1734%
1735*/
cristy4c08aed2011-07-01 19:47:50 +00001736static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001737 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001738 ExceptionInfo *exception)
1739{
1740 CacheInfo
1741 *cache_info;
1742
cristy5c9e6f22010-09-17 17:31:01 +00001743 const int
1744 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001745
cristy4c08aed2011-07-01 19:47:50 +00001746 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001747 *q;
cristy4c08aed2011-07-01 19:47:50 +00001748
cristye7cc7cf2010-09-21 13:26:47 +00001749 assert(image != (const Image *) NULL);
1750 assert(image->signature == MagickSignature);
1751 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001752 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001753 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001754 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001755 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001756 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001757 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001758 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001759 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001760}
1761
1762/*
1763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764% %
1765% %
1766% %
1767+ G e t I m a g e E x t e n t %
1768% %
1769% %
1770% %
1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772%
cristy4c08aed2011-07-01 19:47:50 +00001773% GetImageExtent() returns the extent of the pixels associated corresponding
1774% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001775%
1776% The format of the GetImageExtent() method is:
1777%
1778% MagickSizeType GetImageExtent(const Image *image)
1779%
1780% A description of each parameter follows:
1781%
1782% o image: the image.
1783%
1784*/
1785MagickExport MagickSizeType GetImageExtent(const Image *image)
1786{
1787 CacheInfo
1788 *cache_info;
1789
cristy5c9e6f22010-09-17 17:31:01 +00001790 const int
1791 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001792
cristy3ed852e2009-09-05 21:47:34 +00001793 assert(image != (Image *) NULL);
1794 assert(image->signature == MagickSignature);
1795 if (image->debug != MagickFalse)
1796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1797 assert(image->cache != (Cache) NULL);
1798 cache_info=(CacheInfo *) image->cache;
1799 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001800 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001801 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001802}
1803
1804/*
1805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1806% %
1807% %
1808% %
1809+ G e t I m a g e P i x e l C a c h e %
1810% %
1811% %
1812% %
1813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1814%
1815% GetImagePixelCache() ensures that there is only a single reference to the
1816% pixel cache to be modified, updating the provided cache pointer to point to
1817% a clone of the original pixel cache if necessary.
1818%
1819% The format of the GetImagePixelCache method is:
1820%
1821% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1822% ExceptionInfo *exception)
1823%
1824% A description of each parameter follows:
1825%
1826% o image: the image.
1827%
1828% o clone: any value other than MagickFalse clones the cache pixels.
1829%
1830% o exception: return any errors or warnings in this structure.
1831%
1832*/
cristyaf894d72011-08-06 23:03:10 +00001833
cristy3ed852e2009-09-05 21:47:34 +00001834static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1835{
1836 CacheInfo
1837 *cache_info;
1838
cristy9e0719b2011-12-29 03:45:45 +00001839 PixelChannelMap
1840 *p,
1841 *q;
1842
cristy3ed852e2009-09-05 21:47:34 +00001843 /*
1844 Does the image match the pixel cache morphology?
1845 */
1846 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001847 p=image->channel_map;
1848 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001849 if ((image->storage_class != cache_info->storage_class) ||
1850 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001851 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001852 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001853 (image->columns != cache_info->columns) ||
1854 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001855 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001856 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001857 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001858 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001859 return(MagickFalse);
1860 return(MagickTrue);
1861}
1862
cristycd01fae2011-08-06 23:52:42 +00001863static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1864 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001865{
1866 CacheInfo
1867 *cache_info;
1868
cristy3ed852e2009-09-05 21:47:34 +00001869 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001870 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001871 status;
1872
cristy50a10922010-02-15 18:35:25 +00001873 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001874 cpu_throttle = 0,
1875 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001876 time_limit = 0;
1877
cristy1ea34962010-07-01 19:49:21 +00001878 static time_t
cristy208b1002011-08-07 18:51:50 +00001879 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001880
cristyc4f9f132010-03-04 18:50:01 +00001881 status=MagickTrue;
1882 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001883 if (cpu_throttle == 0)
1884 {
1885 char
1886 *limit;
1887
1888 /*
1889 Set CPU throttle in milleseconds.
1890 */
1891 cpu_throttle=MagickResourceInfinity;
1892 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1893 if (limit == (char *) NULL)
1894 limit=GetPolicyValue("throttle");
1895 if (limit != (char *) NULL)
1896 {
1897 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1898 limit=DestroyString(limit);
1899 }
1900 }
1901 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1902 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001903 if (time_limit == 0)
1904 {
cristy6ebe97c2010-07-03 01:17:28 +00001905 /*
1906 Set the exire time in seconds.
1907 */
cristy1ea34962010-07-01 19:49:21 +00001908 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001909 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001910 }
1911 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001912 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001913 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001914 assert(image->cache != (Cache) NULL);
1915 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001916 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001917 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001918 {
cristyceb55ee2010-11-06 16:05:49 +00001919 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001920 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001921 {
cristyceb55ee2010-11-06 16:05:49 +00001922 Image
1923 clone_image;
1924
1925 CacheInfo
1926 *clone_info;
1927
1928 /*
1929 Clone pixel cache.
1930 */
1931 clone_image=(*image);
1932 clone_image.semaphore=AllocateSemaphoreInfo();
1933 clone_image.reference_count=1;
1934 clone_image.cache=ClonePixelCache(cache_info);
1935 clone_info=(CacheInfo *) clone_image.cache;
1936 status=OpenPixelCache(&clone_image,IOMode,exception);
1937 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001938 {
cristy5a7fbfb2010-11-06 16:10:59 +00001939 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001940 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001941 if (status != MagickFalse)
1942 {
cristy979bf772011-08-08 00:04:15 +00001943 if (cache_info->mode == ReadMode)
1944 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001945 destroy=MagickTrue;
1946 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001947 }
1948 }
cristyceb55ee2010-11-06 16:05:49 +00001949 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001950 }
cristyceb55ee2010-11-06 16:05:49 +00001951 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001952 }
cristy4320e0e2009-09-10 15:00:08 +00001953 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001954 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001955 if (status != MagickFalse)
1956 {
1957 /*
1958 Ensure the image matches the pixel cache morphology.
1959 */
1960 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001961 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001962 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001963 {
1964 status=OpenPixelCache(image,IOMode,exception);
1965 cache_info=(CacheInfo *) image->cache;
1966 if (cache_info->type == DiskCache)
1967 (void) ClosePixelCacheOnDisk(cache_info);
1968 }
cristy3ed852e2009-09-05 21:47:34 +00001969 }
cristyf84a1932010-01-03 18:00:18 +00001970 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001971 if (status == MagickFalse)
1972 return((Cache) NULL);
1973 return(image->cache);
1974}
1975
1976/*
1977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978% %
1979% %
1980% %
1981% G e t O n e A u t h e n t i c P i x e l %
1982% %
1983% %
1984% %
1985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986%
1987% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1988% location. The image background color is returned if an error occurs.
1989%
1990% The format of the GetOneAuthenticPixel() method is:
1991%
cristybb503372010-05-27 20:51:26 +00001992% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001993% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001994%
1995% A description of each parameter follows:
1996%
1997% o image: the image.
1998%
1999% o x,y: These values define the location of the pixel to return.
2000%
2001% o pixel: return a pixel at the specified (x,y) location.
2002%
2003% o exception: return any errors or warnings in this structure.
2004%
2005*/
cristyacbbb7c2010-06-30 18:56:48 +00002006MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002007 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002008{
2009 CacheInfo
2010 *cache_info;
2011
cristy4c08aed2011-07-01 19:47:50 +00002012 register Quantum
2013 *q;
cristy2036f5c2010-09-19 21:18:17 +00002014
cristy2ed42f62011-10-02 19:49:57 +00002015 register ssize_t
2016 i;
2017
cristy3ed852e2009-09-05 21:47:34 +00002018 assert(image != (Image *) NULL);
2019 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002020 assert(image->cache != (Cache) NULL);
2021 cache_info=(CacheInfo *) image->cache;
2022 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002023 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002024 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2025 (GetOneAuthenticPixelFromHandler) NULL)
2026 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2027 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002028 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2029 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002030 {
cristy9e0719b2011-12-29 03:45:45 +00002031 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2032 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2033 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2034 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2035 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002036 return(MagickFalse);
2037 }
2038 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2039 {
2040 PixelChannel
2041 channel;
2042
cristye2a912b2011-12-05 20:02:07 +00002043 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002044 pixel[channel]=q[i];
2045 }
cristy2036f5c2010-09-19 21:18:17 +00002046 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002047}
2048
2049/*
2050%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2051% %
2052% %
2053% %
2054+ 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 %
2055% %
2056% %
2057% %
2058%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2059%
2060% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2061% location. The image background color is returned if an error occurs.
2062%
2063% The format of the GetOneAuthenticPixelFromCache() method is:
2064%
2065% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002066% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002067% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002068%
2069% A description of each parameter follows:
2070%
2071% o image: the image.
2072%
2073% o x,y: These values define the location of the pixel to return.
2074%
2075% o pixel: return a pixel at the specified (x,y) location.
2076%
2077% o exception: return any errors or warnings in this structure.
2078%
2079*/
2080static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002081 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002082{
cristy098f78c2010-09-23 17:28:44 +00002083 CacheInfo
2084 *cache_info;
2085
2086 const int
2087 id = GetOpenMPThreadId();
2088
cristy4c08aed2011-07-01 19:47:50 +00002089 register Quantum
2090 *q;
cristy3ed852e2009-09-05 21:47:34 +00002091
cristy2ed42f62011-10-02 19:49:57 +00002092 register ssize_t
2093 i;
2094
cristy0158a4b2010-09-20 13:59:45 +00002095 assert(image != (const Image *) NULL);
2096 assert(image->signature == MagickSignature);
2097 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002098 cache_info=(CacheInfo *) image->cache;
2099 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002100 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002101 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002102 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2103 exception);
2104 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002105 {
cristy9e0719b2011-12-29 03:45:45 +00002106 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2107 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2108 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2109 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2110 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002111 return(MagickFalse);
2112 }
2113 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2114 {
2115 PixelChannel
2116 channel;
2117
cristye2a912b2011-12-05 20:02:07 +00002118 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002119 pixel[channel]=q[i];
2120 }
cristy3ed852e2009-09-05 21:47:34 +00002121 return(MagickTrue);
2122}
2123
2124/*
2125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2126% %
2127% %
2128% %
cristy3ed852e2009-09-05 21:47:34 +00002129% G e t O n e V i r t u a l P i x e l %
2130% %
2131% %
2132% %
2133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2134%
2135% GetOneVirtualPixel() returns a single virtual pixel at the specified
2136% (x,y) location. The image background color is returned if an error occurs.
2137% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2138%
2139% The format of the GetOneVirtualPixel() method is:
2140%
cristybb503372010-05-27 20:51:26 +00002141% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002142% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002143%
2144% A description of each parameter follows:
2145%
2146% o image: the image.
2147%
2148% o x,y: These values define the location of the pixel to return.
2149%
2150% o pixel: return a pixel at the specified (x,y) location.
2151%
2152% o exception: return any errors or warnings in this structure.
2153%
2154*/
2155MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002156 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002157{
cristy3ed852e2009-09-05 21:47:34 +00002158 CacheInfo
2159 *cache_info;
2160
cristy0158a4b2010-09-20 13:59:45 +00002161 const int
2162 id = GetOpenMPThreadId();
2163
cristy4c08aed2011-07-01 19:47:50 +00002164 const Quantum
2165 *p;
cristy2036f5c2010-09-19 21:18:17 +00002166
cristy2ed42f62011-10-02 19:49:57 +00002167 register ssize_t
2168 i;
2169
cristy3ed852e2009-09-05 21:47:34 +00002170 assert(image != (const Image *) NULL);
2171 assert(image->signature == MagickSignature);
2172 assert(image->cache != (Cache) NULL);
2173 cache_info=(CacheInfo *) image->cache;
2174 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002175 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002176 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2177 (GetOneVirtualPixelFromHandler) NULL)
2178 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2179 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002180 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002181 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002182 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002183 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002184 {
cristy9e0719b2011-12-29 03:45:45 +00002185 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2186 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2187 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2188 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2189 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002190 return(MagickFalse);
2191 }
2192 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2193 {
2194 PixelChannel
2195 channel;
2196
cristye2a912b2011-12-05 20:02:07 +00002197 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002198 pixel[channel]=p[i];
2199 }
cristy2036f5c2010-09-19 21:18:17 +00002200 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002201}
2202
2203/*
2204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205% %
2206% %
2207% %
2208+ 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 %
2209% %
2210% %
2211% %
2212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2213%
2214% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2215% specified (x,y) location. The image background color is returned if an
2216% error occurs.
2217%
2218% The format of the GetOneVirtualPixelFromCache() method is:
2219%
2220% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002221% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002222% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002223%
2224% A description of each parameter follows:
2225%
2226% o image: the image.
2227%
2228% o virtual_pixel_method: the virtual pixel method.
2229%
2230% o x,y: These values define the location of the pixel to return.
2231%
2232% o pixel: return a pixel at the specified (x,y) location.
2233%
2234% o exception: return any errors or warnings in this structure.
2235%
2236*/
2237static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002238 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002239 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002240{
cristy0158a4b2010-09-20 13:59:45 +00002241 CacheInfo
2242 *cache_info;
2243
2244 const int
2245 id = GetOpenMPThreadId();
2246
cristy4c08aed2011-07-01 19:47:50 +00002247 const Quantum
2248 *p;
cristy3ed852e2009-09-05 21:47:34 +00002249
cristy2ed42f62011-10-02 19:49:57 +00002250 register ssize_t
2251 i;
2252
cristye7cc7cf2010-09-21 13:26:47 +00002253 assert(image != (const Image *) NULL);
2254 assert(image->signature == MagickSignature);
2255 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002256 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002257 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002258 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002259 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002260 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002261 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002262 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002263 {
cristy9e0719b2011-12-29 03:45:45 +00002264 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2265 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2266 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2267 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2268 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002269 return(MagickFalse);
2270 }
2271 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2272 {
2273 PixelChannel
2274 channel;
2275
cristye2a912b2011-12-05 20:02:07 +00002276 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002277 pixel[channel]=p[i];
2278 }
cristy3ed852e2009-09-05 21:47:34 +00002279 return(MagickTrue);
2280}
2281
2282/*
2283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284% %
2285% %
2286% %
cristy3aa93752011-12-18 15:54:24 +00002287% G e t O n e V i r t u a l P i x e l I n f o %
2288% %
2289% %
2290% %
2291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2292%
2293% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2294% location. The image background color is returned if an error occurs. If
2295% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2296%
2297% The format of the GetOneVirtualPixelInfo() method is:
2298%
2299% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2300% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2301% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2302%
2303% A description of each parameter follows:
2304%
2305% o image: the image.
2306%
2307% o virtual_pixel_method: the virtual pixel method.
2308%
2309% o x,y: these values define the location of the pixel to return.
2310%
2311% o pixel: return a pixel at the specified (x,y) location.
2312%
2313% o exception: return any errors or warnings in this structure.
2314%
2315*/
2316MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2317 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2318 PixelInfo *pixel,ExceptionInfo *exception)
2319{
2320 CacheInfo
2321 *cache_info;
2322
2323 const int
2324 id = GetOpenMPThreadId();
2325
2326 register const Quantum
2327 *p;
2328
2329 assert(image != (const Image *) NULL);
2330 assert(image->signature == MagickSignature);
2331 assert(image->cache != (Cache) NULL);
2332 cache_info=(CacheInfo *) image->cache;
2333 assert(cache_info->signature == MagickSignature);
2334 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002335 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002336 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2337 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002338 if (p == (const Quantum *) NULL)
2339 return(MagickFalse);
2340 GetPixelInfoPixel(image,p,pixel);
2341 return(MagickTrue);
2342}
2343
2344/*
2345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2346% %
2347% %
2348% %
cristy3ed852e2009-09-05 21:47:34 +00002349+ G e t P i x e l C a c h e C o l o r s p a c e %
2350% %
2351% %
2352% %
2353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2354%
2355% GetPixelCacheColorspace() returns the class type of the pixel cache.
2356%
2357% The format of the GetPixelCacheColorspace() method is:
2358%
2359% Colorspace GetPixelCacheColorspace(Cache cache)
2360%
2361% A description of each parameter follows:
2362%
2363% o cache: the pixel cache.
2364%
2365*/
cristya6577ff2011-09-02 19:54:26 +00002366MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002367{
2368 CacheInfo
2369 *cache_info;
2370
2371 assert(cache != (Cache) NULL);
2372 cache_info=(CacheInfo *) cache;
2373 assert(cache_info->signature == MagickSignature);
2374 if (cache_info->debug != MagickFalse)
2375 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2376 cache_info->filename);
2377 return(cache_info->colorspace);
2378}
2379
2380/*
2381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2382% %
2383% %
2384% %
2385+ G e t P i x e l C a c h e M e t h o d s %
2386% %
2387% %
2388% %
2389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2390%
2391% GetPixelCacheMethods() initializes the CacheMethods structure.
2392%
2393% The format of the GetPixelCacheMethods() method is:
2394%
2395% void GetPixelCacheMethods(CacheMethods *cache_methods)
2396%
2397% A description of each parameter follows:
2398%
2399% o cache_methods: Specifies a pointer to a CacheMethods structure.
2400%
2401*/
cristya6577ff2011-09-02 19:54:26 +00002402MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002403{
2404 assert(cache_methods != (CacheMethods *) NULL);
2405 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2406 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2407 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002408 cache_methods->get_virtual_metacontent_from_handler=
2409 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002410 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2411 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002412 cache_methods->get_authentic_metacontent_from_handler=
2413 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002414 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2415 cache_methods->get_one_authentic_pixel_from_handler=
2416 GetOneAuthenticPixelFromCache;
2417 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2418 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2419 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2420}
2421
2422/*
2423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2424% %
2425% %
2426% %
2427+ G e t P i x e l C a c h e N e x u s E x t e n t %
2428% %
2429% %
2430% %
2431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2432%
cristy4c08aed2011-07-01 19:47:50 +00002433% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2434% corresponding with the last call to SetPixelCacheNexusPixels() or
2435% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002436%
2437% The format of the GetPixelCacheNexusExtent() method is:
2438%
2439% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2440% NexusInfo *nexus_info)
2441%
2442% A description of each parameter follows:
2443%
2444% o nexus_info: the nexus info.
2445%
2446*/
cristya6577ff2011-09-02 19:54:26 +00002447MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002448 NexusInfo *nexus_info)
2449{
2450 CacheInfo
2451 *cache_info;
2452
2453 MagickSizeType
2454 extent;
2455
cristy9f027d12011-09-21 01:17:17 +00002456 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002457 cache_info=(CacheInfo *) cache;
2458 assert(cache_info->signature == MagickSignature);
2459 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2460 if (extent == 0)
2461 return((MagickSizeType) cache_info->columns*cache_info->rows);
2462 return(extent);
2463}
2464
2465/*
2466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2467% %
2468% %
2469% %
cristy4c08aed2011-07-01 19:47:50 +00002470+ 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 +00002471% %
2472% %
2473% %
2474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2475%
cristy4c08aed2011-07-01 19:47:50 +00002476% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2477% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002478%
cristy4c08aed2011-07-01 19:47:50 +00002479% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002480%
cristy4c08aed2011-07-01 19:47:50 +00002481% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002482% NexusInfo *nexus_info)
2483%
2484% A description of each parameter follows:
2485%
2486% o cache: the pixel cache.
2487%
cristy4c08aed2011-07-01 19:47:50 +00002488% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002489%
2490*/
cristya6577ff2011-09-02 19:54:26 +00002491MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002492 NexusInfo *nexus_info)
2493{
2494 CacheInfo
2495 *cache_info;
2496
cristy9f027d12011-09-21 01:17:17 +00002497 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002498 cache_info=(CacheInfo *) cache;
2499 assert(cache_info->signature == MagickSignature);
2500 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002501 return((void *) NULL);
2502 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002503}
2504
2505/*
2506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2507% %
2508% %
2509% %
2510+ G e t P i x e l C a c h e N e x u s P i x e l s %
2511% %
2512% %
2513% %
2514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2515%
2516% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2517% cache nexus.
2518%
2519% The format of the GetPixelCacheNexusPixels() method is:
2520%
cristy4c08aed2011-07-01 19:47:50 +00002521% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002522% NexusInfo *nexus_info)
2523%
2524% A description of each parameter follows:
2525%
2526% o cache: the pixel cache.
2527%
2528% o nexus_info: the cache nexus to return the pixels.
2529%
2530*/
cristya6577ff2011-09-02 19:54:26 +00002531MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002532 NexusInfo *nexus_info)
2533{
2534 CacheInfo
2535 *cache_info;
2536
cristy9f027d12011-09-21 01:17:17 +00002537 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002538 cache_info=(CacheInfo *) cache;
2539 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002540 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002541 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002542 return(nexus_info->pixels);
2543}
2544
2545/*
2546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2547% %
2548% %
2549% %
cristy056ba772010-01-02 23:33:54 +00002550+ G e t P i x e l C a c h e P i x e l s %
2551% %
2552% %
2553% %
2554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2555%
2556% GetPixelCachePixels() returns the pixels associated with the specified image.
2557%
2558% The format of the GetPixelCachePixels() method is:
2559%
cristyf84a1932010-01-03 18:00:18 +00002560% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2561% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002562%
2563% A description of each parameter follows:
2564%
2565% o image: the image.
2566%
2567% o length: the pixel cache length.
2568%
cristyf84a1932010-01-03 18:00:18 +00002569% o exception: return any errors or warnings in this structure.
2570%
cristy056ba772010-01-02 23:33:54 +00002571*/
cristyd1dd6e42011-09-04 01:46:08 +00002572MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002573 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002574{
2575 CacheInfo
2576 *cache_info;
2577
2578 assert(image != (const Image *) NULL);
2579 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002580 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002581 assert(length != (MagickSizeType *) NULL);
2582 assert(exception != (ExceptionInfo *) NULL);
2583 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002584 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002585 assert(cache_info->signature == MagickSignature);
2586 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002587 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002588 return((void *) NULL);
2589 *length=cache_info->length;
2590 return((void *) cache_info->pixels);
2591}
2592
2593/*
2594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2595% %
2596% %
2597% %
cristyb32b90a2009-09-07 21:45:48 +00002598+ 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 +00002599% %
2600% %
2601% %
2602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2603%
2604% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2605%
2606% The format of the GetPixelCacheStorageClass() method is:
2607%
2608% ClassType GetPixelCacheStorageClass(Cache cache)
2609%
2610% A description of each parameter follows:
2611%
2612% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2613%
2614% o cache: the pixel cache.
2615%
2616*/
cristya6577ff2011-09-02 19:54:26 +00002617MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002618{
2619 CacheInfo
2620 *cache_info;
2621
2622 assert(cache != (Cache) NULL);
2623 cache_info=(CacheInfo *) cache;
2624 assert(cache_info->signature == MagickSignature);
2625 if (cache_info->debug != MagickFalse)
2626 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2627 cache_info->filename);
2628 return(cache_info->storage_class);
2629}
2630
2631/*
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633% %
2634% %
2635% %
cristyb32b90a2009-09-07 21:45:48 +00002636+ G e t P i x e l C a c h e T i l e S i z e %
2637% %
2638% %
2639% %
2640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641%
2642% GetPixelCacheTileSize() returns the pixel cache tile size.
2643%
2644% The format of the GetPixelCacheTileSize() method is:
2645%
cristybb503372010-05-27 20:51:26 +00002646% void GetPixelCacheTileSize(const Image *image,size_t *width,
2647% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002648%
2649% A description of each parameter follows:
2650%
2651% o image: the image.
2652%
2653% o width: the optimize cache tile width in pixels.
2654%
2655% o height: the optimize cache tile height in pixels.
2656%
2657*/
cristya6577ff2011-09-02 19:54:26 +00002658MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002659 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002660{
cristy4c08aed2011-07-01 19:47:50 +00002661 CacheInfo
2662 *cache_info;
2663
cristyb32b90a2009-09-07 21:45:48 +00002664 assert(image != (Image *) NULL);
2665 assert(image->signature == MagickSignature);
2666 if (image->debug != MagickFalse)
2667 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002668 cache_info=(CacheInfo *) image->cache;
2669 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002670 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002671 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002672 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002673 *height=(*width);
2674}
2675
2676/*
2677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2678% %
2679% %
2680% %
2681+ G e t P i x e l C a c h e T y p e %
2682% %
2683% %
2684% %
2685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2686%
2687% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2688%
2689% The format of the GetPixelCacheType() method is:
2690%
2691% CacheType GetPixelCacheType(const Image *image)
2692%
2693% A description of each parameter follows:
2694%
2695% o image: the image.
2696%
2697*/
cristya6577ff2011-09-02 19:54:26 +00002698MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002699{
2700 CacheInfo
2701 *cache_info;
2702
2703 assert(image != (Image *) NULL);
2704 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002705 assert(image->cache != (Cache) NULL);
2706 cache_info=(CacheInfo *) image->cache;
2707 assert(cache_info->signature == MagickSignature);
2708 return(cache_info->type);
2709}
2710
2711/*
2712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2713% %
2714% %
2715% %
cristy3ed852e2009-09-05 21:47:34 +00002716+ 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 %
2717% %
2718% %
2719% %
2720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2721%
2722% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2723% pixel cache. A virtual pixel is any pixel access that is outside the
2724% boundaries of the image cache.
2725%
2726% The format of the GetPixelCacheVirtualMethod() method is:
2727%
2728% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2729%
2730% A description of each parameter follows:
2731%
2732% o image: the image.
2733%
2734*/
cristyd1dd6e42011-09-04 01:46:08 +00002735MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002736{
2737 CacheInfo
2738 *cache_info;
2739
2740 assert(image != (Image *) NULL);
2741 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002742 assert(image->cache != (Cache) NULL);
2743 cache_info=(CacheInfo *) image->cache;
2744 assert(cache_info->signature == MagickSignature);
2745 return(cache_info->virtual_pixel_method);
2746}
2747
2748/*
2749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2750% %
2751% %
2752% %
cristy4c08aed2011-07-01 19:47:50 +00002753+ 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 +00002754% %
2755% %
2756% %
2757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2758%
cristy4c08aed2011-07-01 19:47:50 +00002759% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2760% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002761%
cristy4c08aed2011-07-01 19:47:50 +00002762% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002763%
cristy4c08aed2011-07-01 19:47:50 +00002764% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002765%
2766% A description of each parameter follows:
2767%
2768% o image: the image.
2769%
2770*/
cristy4c08aed2011-07-01 19:47:50 +00002771static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002772{
2773 CacheInfo
2774 *cache_info;
2775
cristy5c9e6f22010-09-17 17:31:01 +00002776 const int
2777 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002778
cristy4c08aed2011-07-01 19:47:50 +00002779 const void
2780 *metacontent;
2781
cristye7cc7cf2010-09-21 13:26:47 +00002782 assert(image != (const Image *) NULL);
2783 assert(image->signature == MagickSignature);
2784 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002785 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002786 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002787 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002788 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2789 cache_info->nexus_info[id]);
2790 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002791}
2792
2793/*
2794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2795% %
2796% %
2797% %
cristy4c08aed2011-07-01 19:47:50 +00002798+ 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 +00002799% %
2800% %
2801% %
2802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2803%
cristy4c08aed2011-07-01 19:47:50 +00002804% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2805% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002806%
cristy4c08aed2011-07-01 19:47:50 +00002807% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002808%
cristy4c08aed2011-07-01 19:47:50 +00002809% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002810% NexusInfo *nexus_info)
2811%
2812% A description of each parameter follows:
2813%
2814% o cache: the pixel cache.
2815%
cristy4c08aed2011-07-01 19:47:50 +00002816% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002817%
2818*/
cristya6577ff2011-09-02 19:54:26 +00002819MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002820 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002821{
2822 CacheInfo
2823 *cache_info;
2824
cristye7cc7cf2010-09-21 13:26:47 +00002825 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002826 cache_info=(CacheInfo *) cache;
2827 assert(cache_info->signature == MagickSignature);
2828 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002829 return((void *) NULL);
2830 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002831}
2832
2833/*
2834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2835% %
2836% %
2837% %
cristy4c08aed2011-07-01 19:47:50 +00002838% 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 +00002839% %
2840% %
2841% %
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843%
cristy4c08aed2011-07-01 19:47:50 +00002844% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2845% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2846% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002847%
cristy4c08aed2011-07-01 19:47:50 +00002848% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002849%
cristy4c08aed2011-07-01 19:47:50 +00002850% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002851%
2852% A description of each parameter follows:
2853%
2854% o image: the image.
2855%
2856*/
cristy4c08aed2011-07-01 19:47:50 +00002857MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002858{
2859 CacheInfo
2860 *cache_info;
2861
cristy2036f5c2010-09-19 21:18:17 +00002862 const int
2863 id = GetOpenMPThreadId();
2864
cristy4c08aed2011-07-01 19:47:50 +00002865 const void
2866 *metacontent;
2867
cristy3ed852e2009-09-05 21:47:34 +00002868 assert(image != (const Image *) NULL);
2869 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002870 assert(image->cache != (Cache) NULL);
2871 cache_info=(CacheInfo *) image->cache;
2872 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002873 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2874 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2875 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002876 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002877 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2878 cache_info->nexus_info[id]);
2879 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002880}
2881
2882/*
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884% %
2885% %
2886% %
2887+ 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 %
2888% %
2889% %
2890% %
2891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892%
2893% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2894% pixel cache as defined by the geometry parameters. A pointer to the pixels
2895% is returned if the pixels are transferred, otherwise a NULL is returned.
2896%
2897% The format of the GetVirtualPixelsFromNexus() method is:
2898%
cristy4c08aed2011-07-01 19:47:50 +00002899% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002900% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002901% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2902% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002903%
2904% A description of each parameter follows:
2905%
2906% o image: the image.
2907%
2908% o virtual_pixel_method: the virtual pixel method.
2909%
2910% o x,y,columns,rows: These values define the perimeter of a region of
2911% pixels.
2912%
2913% o nexus_info: the cache nexus to acquire.
2914%
2915% o exception: return any errors or warnings in this structure.
2916%
2917*/
2918
cristybb503372010-05-27 20:51:26 +00002919static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002920 DitherMatrix[64] =
2921 {
2922 0, 48, 12, 60, 3, 51, 15, 63,
2923 32, 16, 44, 28, 35, 19, 47, 31,
2924 8, 56, 4, 52, 11, 59, 7, 55,
2925 40, 24, 36, 20, 43, 27, 39, 23,
2926 2, 50, 14, 62, 1, 49, 13, 61,
2927 34, 18, 46, 30, 33, 17, 45, 29,
2928 10, 58, 6, 54, 9, 57, 5, 53,
2929 42, 26, 38, 22, 41, 25, 37, 21
2930 };
2931
cristybb503372010-05-27 20:51:26 +00002932static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002933{
cristybb503372010-05-27 20:51:26 +00002934 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002935 index;
2936
2937 index=x+DitherMatrix[x & 0x07]-32L;
2938 if (index < 0L)
2939 return(0L);
cristybb503372010-05-27 20:51:26 +00002940 if (index >= (ssize_t) columns)
2941 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002942 return(index);
2943}
2944
cristybb503372010-05-27 20:51:26 +00002945static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002946{
cristybb503372010-05-27 20:51:26 +00002947 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002948 index;
2949
2950 index=y+DitherMatrix[y & 0x07]-32L;
2951 if (index < 0L)
2952 return(0L);
cristybb503372010-05-27 20:51:26 +00002953 if (index >= (ssize_t) rows)
2954 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002955 return(index);
2956}
2957
cristybb503372010-05-27 20:51:26 +00002958static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002959{
2960 if (x < 0L)
2961 return(0L);
cristybb503372010-05-27 20:51:26 +00002962 if (x >= (ssize_t) columns)
2963 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002964 return(x);
2965}
2966
cristybb503372010-05-27 20:51:26 +00002967static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002968{
2969 if (y < 0L)
2970 return(0L);
cristybb503372010-05-27 20:51:26 +00002971 if (y >= (ssize_t) rows)
2972 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002973 return(y);
2974}
2975
cristybb503372010-05-27 20:51:26 +00002976static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002977{
cristybb503372010-05-27 20:51:26 +00002978 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002979}
2980
cristybb503372010-05-27 20:51:26 +00002981static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002982{
cristybb503372010-05-27 20:51:26 +00002983 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002984}
2985
cristybb503372010-05-27 20:51:26 +00002986static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2987 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002988{
2989 MagickModulo
2990 modulo;
2991
cristy6162bb42011-07-18 11:34:09 +00002992 /*
2993 Compute the remainder of dividing offset by extent. It returns not only
2994 the quotient (tile the offset falls in) but also the positive remainer
2995 within that tile such that 0 <= remainder < extent. This method is
2996 essentially a ldiv() using a floored modulo division rather than the
2997 normal default truncated modulo division.
2998 */
cristybb503372010-05-27 20:51:26 +00002999 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003000 if (offset < 0L)
3001 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003002 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003003 return(modulo);
3004}
3005
cristya6577ff2011-09-02 19:54:26 +00003006MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003007 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3008 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003009 ExceptionInfo *exception)
3010{
3011 CacheInfo
3012 *cache_info;
3013
3014 MagickOffsetType
3015 offset;
3016
3017 MagickSizeType
3018 length,
3019 number_pixels;
3020
3021 NexusInfo
3022 **virtual_nexus;
3023
cristy4c08aed2011-07-01 19:47:50 +00003024 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003025 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003026 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003027
3028 RectangleInfo
3029 region;
3030
cristy4c08aed2011-07-01 19:47:50 +00003031 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003032 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003033
cristy4c08aed2011-07-01 19:47:50 +00003034 register const void
3035 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003036
cristy4c08aed2011-07-01 19:47:50 +00003037 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003038 *restrict q;
3039
cristybb503372010-05-27 20:51:26 +00003040 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003041 i,
3042 u;
cristy3ed852e2009-09-05 21:47:34 +00003043
cristy4c08aed2011-07-01 19:47:50 +00003044 register unsigned char
3045 *restrict s;
3046
cristy105ba3c2011-07-18 02:28:38 +00003047 ssize_t
3048 v;
3049
cristy4c08aed2011-07-01 19:47:50 +00003050 void
cristy105ba3c2011-07-18 02:28:38 +00003051 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003052
cristy3ed852e2009-09-05 21:47:34 +00003053 /*
3054 Acquire pixels.
3055 */
cristye7cc7cf2010-09-21 13:26:47 +00003056 assert(image != (const Image *) NULL);
3057 assert(image->signature == MagickSignature);
3058 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003059 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003060 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003061 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003062 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003063 region.x=x;
3064 region.y=y;
3065 region.width=columns;
3066 region.height=rows;
3067 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003068 if (pixels == (Quantum *) NULL)
3069 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003070 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003071 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3072 nexus_info->region.x;
3073 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3074 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003075 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3076 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003077 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3078 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003079 {
3080 MagickBooleanType
3081 status;
3082
3083 /*
3084 Pixel request is inside cache extents.
3085 */
cristy4c08aed2011-07-01 19:47:50 +00003086 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003087 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003088 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3089 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003090 return((const Quantum *) NULL);
3091 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003092 {
cristy4c08aed2011-07-01 19:47:50 +00003093 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003094 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003095 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003096 }
cristyacd2ed22011-08-30 01:44:23 +00003097 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003098 }
3099 /*
3100 Pixel request is outside cache extents.
3101 */
cristy4c08aed2011-07-01 19:47:50 +00003102 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003103 virtual_nexus=AcquirePixelCacheNexus(1);
3104 if (virtual_nexus == (NexusInfo **) NULL)
3105 {
cristy4c08aed2011-07-01 19:47:50 +00003106 if (virtual_nexus != (NexusInfo **) NULL)
3107 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003108 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003109 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003110 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003111 }
cristy105ba3c2011-07-18 02:28:38 +00003112 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3113 sizeof(*virtual_pixel));
3114 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003115 switch (virtual_pixel_method)
3116 {
cristy4c08aed2011-07-01 19:47:50 +00003117 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003120 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003121 case MaskVirtualPixelMethod:
3122 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003123 case EdgeVirtualPixelMethod:
3124 case CheckerTileVirtualPixelMethod:
3125 case HorizontalTileVirtualPixelMethod:
3126 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003127 {
cristy4c08aed2011-07-01 19:47:50 +00003128 if (cache_info->metacontent_extent != 0)
3129 {
cristy6162bb42011-07-18 11:34:09 +00003130 /*
3131 Acquire a metacontent buffer.
3132 */
cristya64b85d2011-09-14 01:02:31 +00003133 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003134 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003135 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003136 {
cristy4c08aed2011-07-01 19:47:50 +00003137 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3138 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003139 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003140 return((const Quantum *) NULL);
3141 }
cristy105ba3c2011-07-18 02:28:38 +00003142 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003143 cache_info->metacontent_extent);
3144 }
3145 switch (virtual_pixel_method)
3146 {
3147 case BlackVirtualPixelMethod:
3148 {
cristy30301712011-07-18 15:06:51 +00003149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3150 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003151 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3152 break;
3153 }
3154 case GrayVirtualPixelMethod:
3155 {
cristy30301712011-07-18 15:06:51 +00003156 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003157 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3158 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003159 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3160 break;
3161 }
3162 case TransparentVirtualPixelMethod:
3163 {
cristy30301712011-07-18 15:06:51 +00003164 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3165 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003166 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3167 break;
3168 }
3169 case MaskVirtualPixelMethod:
3170 case WhiteVirtualPixelMethod:
3171 {
cristy30301712011-07-18 15:06:51 +00003172 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3173 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003174 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3175 break;
3176 }
3177 default:
3178 {
cristy9e0719b2011-12-29 03:45:45 +00003179 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3180 virtual_pixel);
3181 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3182 virtual_pixel);
3183 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3184 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003185 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3186 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003187 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3188 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003189 break;
3190 }
3191 }
cristy3ed852e2009-09-05 21:47:34 +00003192 break;
3193 }
3194 default:
cristy3ed852e2009-09-05 21:47:34 +00003195 break;
cristy3ed852e2009-09-05 21:47:34 +00003196 }
cristybb503372010-05-27 20:51:26 +00003197 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003198 {
cristybb503372010-05-27 20:51:26 +00003199 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003200 {
3201 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003202 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003203 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3204 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003205 {
3206 MagickModulo
3207 x_modulo,
3208 y_modulo;
3209
3210 /*
3211 Transfer a single pixel.
3212 */
3213 length=(MagickSizeType) 1;
3214 switch (virtual_pixel_method)
3215 {
cristy3ed852e2009-09-05 21:47:34 +00003216 default:
3217 {
3218 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003219 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003220 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003221 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003222 break;
3223 }
3224 case RandomVirtualPixelMethod:
3225 {
3226 if (cache_info->random_info == (RandomInfo *) NULL)
3227 cache_info->random_info=AcquireRandomInfo();
3228 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003229 RandomX(cache_info->random_info,cache_info->columns),
3230 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003231 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003232 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003233 break;
3234 }
3235 case DitherVirtualPixelMethod:
3236 {
3237 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003238 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003239 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003240 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003241 break;
3242 }
3243 case TileVirtualPixelMethod:
3244 {
3245 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3246 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3247 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003248 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003249 exception);
cristy4c08aed2011-07-01 19:47:50 +00003250 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003251 break;
3252 }
3253 case MirrorVirtualPixelMethod:
3254 {
3255 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3256 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003257 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003258 x_modulo.remainder-1L;
3259 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3260 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003261 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003262 y_modulo.remainder-1L;
3263 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003264 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003265 exception);
cristy4c08aed2011-07-01 19:47:50 +00003266 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003267 break;
3268 }
3269 case HorizontalTileEdgeVirtualPixelMethod:
3270 {
3271 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003273 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003274 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003275 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003276 break;
3277 }
3278 case VerticalTileEdgeVirtualPixelMethod:
3279 {
3280 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3281 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003282 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003283 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003284 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3285 break;
3286 }
3287 case BackgroundVirtualPixelMethod:
3288 case BlackVirtualPixelMethod:
3289 case GrayVirtualPixelMethod:
3290 case TransparentVirtualPixelMethod:
3291 case MaskVirtualPixelMethod:
3292 case WhiteVirtualPixelMethod:
3293 {
3294 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003295 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003296 break;
3297 }
3298 case EdgeVirtualPixelMethod:
3299 case CheckerTileVirtualPixelMethod:
3300 {
3301 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3302 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3303 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3304 {
3305 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003306 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003307 break;
3308 }
3309 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3310 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3311 exception);
3312 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3313 break;
3314 }
3315 case HorizontalTileVirtualPixelMethod:
3316 {
3317 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3318 {
3319 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003320 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003321 break;
3322 }
3323 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3324 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3325 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3326 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3327 exception);
3328 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3329 break;
3330 }
3331 case VerticalTileVirtualPixelMethod:
3332 {
3333 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3334 {
3335 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003336 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003337 break;
3338 }
3339 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3340 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3341 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3342 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3343 exception);
3344 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003345 break;
3346 }
3347 }
cristy4c08aed2011-07-01 19:47:50 +00003348 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003349 break;
cristyed231572011-07-14 02:18:59 +00003350 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003351 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003352 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003353 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003354 {
3355 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3356 s+=cache_info->metacontent_extent;
3357 }
cristy3ed852e2009-09-05 21:47:34 +00003358 continue;
3359 }
3360 /*
3361 Transfer a run of pixels.
3362 */
cristy4c08aed2011-07-01 19:47:50 +00003363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3364 length,1UL,*virtual_nexus,exception);
3365 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003366 break;
cristy4c08aed2011-07-01 19:47:50 +00003367 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003368 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3369 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003370 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003371 {
cristy4c08aed2011-07-01 19:47:50 +00003372 (void) memcpy(s,r,(size_t) length);
3373 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003374 }
3375 }
3376 }
cristy4c08aed2011-07-01 19:47:50 +00003377 /*
3378 Free resources.
3379 */
cristy105ba3c2011-07-18 02:28:38 +00003380 if (virtual_metacontent != (void *) NULL)
3381 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003382 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3383 return(pixels);
3384}
3385
3386/*
3387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3388% %
3389% %
3390% %
3391+ G e t V i r t u a l P i x e l C a c h e %
3392% %
3393% %
3394% %
3395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3396%
3397% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3398% cache as defined by the geometry parameters. A pointer to the pixels
3399% is returned if the pixels are transferred, otherwise a NULL is returned.
3400%
3401% The format of the GetVirtualPixelCache() method is:
3402%
cristy4c08aed2011-07-01 19:47:50 +00003403% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003404% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3405% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003406% ExceptionInfo *exception)
3407%
3408% A description of each parameter follows:
3409%
3410% o image: the image.
3411%
3412% o virtual_pixel_method: the virtual pixel method.
3413%
3414% o x,y,columns,rows: These values define the perimeter of a region of
3415% pixels.
3416%
3417% o exception: return any errors or warnings in this structure.
3418%
3419*/
cristy4c08aed2011-07-01 19:47:50 +00003420static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003421 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3422 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003423{
3424 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003425 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003426
cristy5c9e6f22010-09-17 17:31:01 +00003427 const int
3428 id = GetOpenMPThreadId();
3429
cristy4c08aed2011-07-01 19:47:50 +00003430 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003431 *p;
cristy4c08aed2011-07-01 19:47:50 +00003432
cristye7cc7cf2010-09-21 13:26:47 +00003433 assert(image != (const Image *) NULL);
3434 assert(image->signature == MagickSignature);
3435 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003436 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003437 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003438 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003440 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003441 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003442}
3443
3444/*
3445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3446% %
3447% %
3448% %
3449% G e t V i r t u a l P i x e l Q u e u e %
3450% %
3451% %
3452% %
3453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3454%
cristy4c08aed2011-07-01 19:47:50 +00003455% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3456% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003457%
3458% The format of the GetVirtualPixelQueue() method is:
3459%
cristy4c08aed2011-07-01 19:47:50 +00003460% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003461%
3462% A description of each parameter follows:
3463%
3464% o image: the image.
3465%
3466*/
cristy4c08aed2011-07-01 19:47:50 +00003467MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003468{
3469 CacheInfo
3470 *cache_info;
3471
cristy2036f5c2010-09-19 21:18:17 +00003472 const int
3473 id = GetOpenMPThreadId();
3474
cristy3ed852e2009-09-05 21:47:34 +00003475 assert(image != (const Image *) NULL);
3476 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003477 assert(image->cache != (Cache) NULL);
3478 cache_info=(CacheInfo *) image->cache;
3479 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003480 if (cache_info->methods.get_virtual_pixels_handler !=
3481 (GetVirtualPixelsHandler) NULL)
3482 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003483 assert(id < (int) cache_info->number_threads);
3484 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003485}
3486
3487/*
3488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3489% %
3490% %
3491% %
3492% G e t V i r t u a l P i x e l s %
3493% %
3494% %
3495% %
3496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3497%
3498% GetVirtualPixels() returns an immutable pixel region. If the
3499% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003500% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003501% copy of the pixels or it may point to the original pixels in memory.
3502% Performance is maximized if the selected region is part of one row, or one
3503% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003504% (without a copy) if the image is in memory, or in a memory-mapped file. The
3505% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003506%
3507% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003508% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3509% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3510% access the meta-content (of type void) corresponding to the the
3511% region.
cristy3ed852e2009-09-05 21:47:34 +00003512%
3513% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3514%
3515% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3516% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3517% GetCacheViewAuthenticPixels() instead.
3518%
3519% The format of the GetVirtualPixels() method is:
3520%
cristy4c08aed2011-07-01 19:47:50 +00003521% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003522% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003523% ExceptionInfo *exception)
3524%
3525% A description of each parameter follows:
3526%
3527% o image: the image.
3528%
3529% o x,y,columns,rows: These values define the perimeter of a region of
3530% pixels.
3531%
3532% o exception: return any errors or warnings in this structure.
3533%
3534*/
cristy4c08aed2011-07-01 19:47:50 +00003535MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003536 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3537 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003538{
3539 CacheInfo
3540 *cache_info;
3541
cristy2036f5c2010-09-19 21:18:17 +00003542 const int
3543 id = GetOpenMPThreadId();
3544
cristy4c08aed2011-07-01 19:47:50 +00003545 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003546 *p;
cristy4c08aed2011-07-01 19:47:50 +00003547
cristy3ed852e2009-09-05 21:47:34 +00003548 assert(image != (const Image *) NULL);
3549 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003550 assert(image->cache != (Cache) NULL);
3551 cache_info=(CacheInfo *) image->cache;
3552 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003553 if (cache_info->methods.get_virtual_pixel_handler !=
3554 (GetVirtualPixelHandler) NULL)
3555 return(cache_info->methods.get_virtual_pixel_handler(image,
3556 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003557 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003558 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003559 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003560 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003561}
3562
3563/*
3564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565% %
3566% %
3567% %
3568+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3569% %
3570% %
3571% %
3572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3573%
cristy4c08aed2011-07-01 19:47:50 +00003574% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3575% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003576%
3577% The format of the GetVirtualPixelsCache() method is:
3578%
cristy4c08aed2011-07-01 19:47:50 +00003579% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003580%
3581% A description of each parameter follows:
3582%
3583% o image: the image.
3584%
3585*/
cristy4c08aed2011-07-01 19:47:50 +00003586static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003587{
3588 CacheInfo
3589 *cache_info;
3590
cristy5c9e6f22010-09-17 17:31:01 +00003591 const int
3592 id = GetOpenMPThreadId();
3593
cristye7cc7cf2010-09-21 13:26:47 +00003594 assert(image != (const Image *) NULL);
3595 assert(image->signature == MagickSignature);
3596 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003597 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003598 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003599 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003600 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003601}
3602
3603/*
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605% %
3606% %
3607% %
3608+ G e t V i r t u a l P i x e l s N e x u s %
3609% %
3610% %
3611% %
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613%
3614% GetVirtualPixelsNexus() returns the pixels associated with the specified
3615% cache nexus.
3616%
3617% The format of the GetVirtualPixelsNexus() method is:
3618%
cristy4c08aed2011-07-01 19:47:50 +00003619% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003620% NexusInfo *nexus_info)
3621%
3622% A description of each parameter follows:
3623%
3624% o cache: the pixel cache.
3625%
3626% o nexus_info: the cache nexus to return the colormap pixels.
3627%
3628*/
cristya6577ff2011-09-02 19:54:26 +00003629MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003630 NexusInfo *nexus_info)
3631{
3632 CacheInfo
3633 *cache_info;
3634
cristye7cc7cf2010-09-21 13:26:47 +00003635 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003636 cache_info=(CacheInfo *) cache;
3637 assert(cache_info->signature == MagickSignature);
3638 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003639 return((Quantum *) NULL);
3640 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003641}
3642
3643/*
3644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3645% %
3646% %
3647% %
cristy3ed852e2009-09-05 21:47:34 +00003648+ O p e n P i x e l C a c h e %
3649% %
3650% %
3651% %
3652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3653%
3654% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3655% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003656% metacontent, and memory mapping the cache if it is disk based. The cache
3657% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003658%
3659% The format of the OpenPixelCache() method is:
3660%
3661% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3662% ExceptionInfo *exception)
3663%
3664% A description of each parameter follows:
3665%
3666% o image: the image.
3667%
3668% o mode: ReadMode, WriteMode, or IOMode.
3669%
3670% o exception: return any errors or warnings in this structure.
3671%
3672*/
3673
cristyd43a46b2010-01-21 02:13:41 +00003674static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003675{
3676 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003677 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003678 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003679 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003680 {
3681 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003682 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003683 cache_info->length);
3684 }
3685}
3686
3687static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3688{
3689 CacheInfo
3690 *cache_info;
3691
3692 MagickOffsetType
3693 count,
3694 extent,
3695 offset;
3696
3697 cache_info=(CacheInfo *) image->cache;
3698 if (image->debug != MagickFalse)
3699 {
3700 char
3701 format[MaxTextExtent],
3702 message[MaxTextExtent];
3703
cristyb9080c92009-12-01 20:13:26 +00003704 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003705 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003706 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003707 cache_info->cache_filename,cache_info->file,format);
3708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3709 }
3710 if (length != (MagickSizeType) ((MagickOffsetType) length))
3711 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003712 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003713 if (extent < 0)
3714 return(MagickFalse);
3715 if ((MagickSizeType) extent >= length)
3716 return(MagickTrue);
3717 offset=(MagickOffsetType) length-1;
3718 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3719 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3720}
3721
3722static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3723 ExceptionInfo *exception)
3724{
cristy3ed852e2009-09-05 21:47:34 +00003725 CacheInfo
3726 *cache_info,
3727 source_info;
3728
cristyf3a6a9d2010-11-07 21:02:56 +00003729 char
3730 format[MaxTextExtent],
3731 message[MaxTextExtent];
3732
cristy4c08aed2011-07-01 19:47:50 +00003733 MagickBooleanType
3734 status;
3735
cristy3ed852e2009-09-05 21:47:34 +00003736 MagickSizeType
3737 length,
3738 number_pixels;
3739
cristy3ed852e2009-09-05 21:47:34 +00003740 size_t
cristye076a6e2010-08-15 19:59:43 +00003741 columns,
cristy3ed852e2009-09-05 21:47:34 +00003742 packet_size;
3743
cristye7cc7cf2010-09-21 13:26:47 +00003744 assert(image != (const Image *) NULL);
3745 assert(image->signature == MagickSignature);
3746 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003747 if (image->debug != MagickFalse)
3748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3749 if ((image->columns == 0) || (image->rows == 0))
3750 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3751 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003752 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003753 source_info=(*cache_info);
3754 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003755 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003756 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003757 cache_info->storage_class=image->storage_class;
3758 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003759 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003760 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003761 cache_info->rows=image->rows;
3762 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003763 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003764 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003765 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3766 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003767 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003768 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003769 if (image->ping != MagickFalse)
3770 {
cristy73724512010-04-12 14:43:14 +00003771 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003772 cache_info->pixels=(Quantum *) NULL;
3773 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003774 cache_info->length=0;
3775 return(MagickTrue);
3776 }
cristy3ed852e2009-09-05 21:47:34 +00003777 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003778 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003779 if (image->metacontent_extent != 0)
3780 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003781 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003782 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003783 if (cache_info->columns != columns)
3784 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3785 image->filename);
3786 cache_info->length=length;
3787 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003788 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003789 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003790 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3791 {
3792 status=AcquireMagickResource(MemoryResource,cache_info->length);
3793 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3794 (cache_info->type == MemoryCache))
3795 {
cristyd43a46b2010-01-21 02:13:41 +00003796 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003797 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003798 cache_info->pixels=source_info.pixels;
3799 else
3800 {
3801 /*
3802 Create memory pixel cache.
3803 */
cristy4c08aed2011-07-01 19:47:50 +00003804 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003805 if (image->debug != MagickFalse)
3806 {
cristy32cacff2011-12-31 03:36:27 +00003807 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003808 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003809 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3810 cache_info->filename,cache_info->mapped != MagickFalse ?
3811 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003812 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003813 format);
cristy3ed852e2009-09-05 21:47:34 +00003814 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3815 message);
3816 }
cristy3ed852e2009-09-05 21:47:34 +00003817 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003818 cache_info->metacontent=(void *) NULL;
3819 if (cache_info->metacontent_extent != 0)
3820 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003821 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003822 if ((source_info.storage_class != UndefinedClass) &&
3823 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003824 {
cristy4c08aed2011-07-01 19:47:50 +00003825 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003826 exception);
3827 RelinquishPixelCachePixels(&source_info);
3828 }
cristy4c08aed2011-07-01 19:47:50 +00003829 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003830 }
3831 }
3832 RelinquishMagickResource(MemoryResource,cache_info->length);
3833 }
3834 /*
3835 Create pixel cache on disk.
3836 */
3837 status=AcquireMagickResource(DiskResource,cache_info->length);
3838 if (status == MagickFalse)
3839 {
3840 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003841 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003842 return(MagickFalse);
3843 }
cristy413f1302012-01-01 17:48:27 +00003844 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3845 {
3846 (void) ClosePixelCacheOnDisk(cache_info);
3847 *cache_info->cache_filename='\0';
3848 }
cristy3ed852e2009-09-05 21:47:34 +00003849 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3850 {
3851 RelinquishMagickResource(DiskResource,cache_info->length);
3852 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3853 image->filename);
3854 return(MagickFalse);
3855 }
3856 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3857 cache_info->length);
3858 if (status == MagickFalse)
3859 {
3860 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3861 image->filename);
3862 return(MagickFalse);
3863 }
cristyed231572011-07-14 02:18:59 +00003864 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003865 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003866 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003867 cache_info->type=DiskCache;
3868 else
3869 {
3870 status=AcquireMagickResource(MapResource,cache_info->length);
3871 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3872 (cache_info->type != MemoryCache))
3873 cache_info->type=DiskCache;
3874 else
3875 {
cristy4c08aed2011-07-01 19:47:50 +00003876 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003877 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003878 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003879 {
cristy3ed852e2009-09-05 21:47:34 +00003880 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003881 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003882 }
3883 else
3884 {
3885 /*
3886 Create file-backed memory-mapped pixel cache.
3887 */
cristy4c08aed2011-07-01 19:47:50 +00003888 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003889 (void) ClosePixelCacheOnDisk(cache_info);
3890 cache_info->type=MapCache;
3891 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003892 cache_info->metacontent=(void *) NULL;
3893 if (cache_info->metacontent_extent != 0)
3894 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003895 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003896 if ((source_info.storage_class != UndefinedClass) &&
3897 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003898 {
3899 status=ClonePixelCachePixels(cache_info,&source_info,
3900 exception);
3901 RelinquishPixelCachePixels(&source_info);
3902 }
3903 if (image->debug != MagickFalse)
3904 {
cristy413f1302012-01-01 17:48:27 +00003905 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003906 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003907 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003908 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003909 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003910 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003911 format);
cristy3ed852e2009-09-05 21:47:34 +00003912 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3913 message);
3914 }
cristy4c08aed2011-07-01 19:47:50 +00003915 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003916 }
3917 }
3918 RelinquishMagickResource(MapResource,cache_info->length);
3919 }
cristy4c08aed2011-07-01 19:47:50 +00003920 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003921 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003922 {
3923 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3924 RelinquishPixelCachePixels(&source_info);
3925 }
3926 if (image->debug != MagickFalse)
3927 {
cristyb9080c92009-12-01 20:13:26 +00003928 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003929 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003930 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003931 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003932 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003933 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003934 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3935 }
cristy4c08aed2011-07-01 19:47:50 +00003936 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003937}
3938
3939/*
3940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3941% %
3942% %
3943% %
3944+ P e r s i s t P i x e l C a c h e %
3945% %
3946% %
3947% %
3948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3949%
3950% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3951% persistent pixel cache is one that resides on disk and is not destroyed
3952% when the program exits.
3953%
3954% The format of the PersistPixelCache() method is:
3955%
3956% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3957% const MagickBooleanType attach,MagickOffsetType *offset,
3958% ExceptionInfo *exception)
3959%
3960% A description of each parameter follows:
3961%
3962% o image: the image.
3963%
3964% o filename: the persistent pixel cache filename.
3965%
cristyf3a6a9d2010-11-07 21:02:56 +00003966% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003967%
cristy3ed852e2009-09-05 21:47:34 +00003968% o initialize: A value other than zero initializes the persistent pixel
3969% cache.
3970%
3971% o offset: the offset in the persistent cache to store pixels.
3972%
3973% o exception: return any errors or warnings in this structure.
3974%
3975*/
3976MagickExport MagickBooleanType PersistPixelCache(Image *image,
3977 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3978 ExceptionInfo *exception)
3979{
3980 CacheInfo
3981 *cache_info,
3982 *clone_info;
3983
3984 Image
3985 clone_image;
3986
cristy3ed852e2009-09-05 21:47:34 +00003987 MagickBooleanType
3988 status;
3989
cristye076a6e2010-08-15 19:59:43 +00003990 ssize_t
3991 page_size;
3992
cristy3ed852e2009-09-05 21:47:34 +00003993 assert(image != (Image *) NULL);
3994 assert(image->signature == MagickSignature);
3995 if (image->debug != MagickFalse)
3996 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3997 assert(image->cache != (void *) NULL);
3998 assert(filename != (const char *) NULL);
3999 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004000 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004001 cache_info=(CacheInfo *) image->cache;
4002 assert(cache_info->signature == MagickSignature);
4003 if (attach != MagickFalse)
4004 {
4005 /*
cristy01b7eb02009-09-10 23:10:14 +00004006 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004007 */
4008 if (image->debug != MagickFalse)
4009 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004010 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004011 (void) CopyMagickString(cache_info->cache_filename,filename,
4012 MaxTextExtent);
4013 cache_info->type=DiskCache;
4014 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004015 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004016 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004017 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004018 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004019 }
cristy01b7eb02009-09-10 23:10:14 +00004020 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4021 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004022 {
cristyf84a1932010-01-03 18:00:18 +00004023 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004024 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004025 (cache_info->reference_count == 1))
4026 {
4027 int
4028 status;
4029
4030 /*
cristy01b7eb02009-09-10 23:10:14 +00004031 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004032 */
cristy320684d2011-09-23 14:55:47 +00004033 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004034 if (status == 0)
4035 {
4036 (void) CopyMagickString(cache_info->cache_filename,filename,
4037 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004038 *offset+=cache_info->length+page_size-(cache_info->length %
4039 page_size);
cristyf84a1932010-01-03 18:00:18 +00004040 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004041 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004042 if (image->debug != MagickFalse)
4043 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4044 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004045 return(MagickTrue);
4046 }
4047 }
cristyf84a1932010-01-03 18:00:18 +00004048 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004049 }
4050 /*
cristy01b7eb02009-09-10 23:10:14 +00004051 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004052 */
4053 clone_image=(*image);
4054 clone_info=(CacheInfo *) clone_image.cache;
4055 image->cache=ClonePixelCache(cache_info);
4056 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4057 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4058 cache_info->type=DiskCache;
4059 cache_info->offset=(*offset);
4060 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004061 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004062 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004063 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004064 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004065 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4066 return(status);
4067}
4068
4069/*
4070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4071% %
4072% %
4073% %
cristyc11dace2012-01-24 16:39:46 +00004074+ Q u e u e A u t h e n t i c P i x e l C a c h e N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00004075% %
4076% %
4077% %
4078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4079%
cristyc11dace2012-01-24 16:39:46 +00004080% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4081% defined by the region rectangle and returns a pointer to the region. This
4082% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004083% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4084% pixels are transferred, otherwise a NULL is returned.
4085%
cristyc11dace2012-01-24 16:39:46 +00004086% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004087%
cristyc11dace2012-01-24 16:39:46 +00004088% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004089% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004090% const MagickBooleanType clone,NexusInfo *nexus_info,
4091% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004092%
4093% A description of each parameter follows:
4094%
4095% o image: the image.
4096%
4097% o x,y,columns,rows: These values define the perimeter of a region of
4098% pixels.
4099%
4100% o nexus_info: the cache nexus to set.
4101%
cristy65dbf172011-10-06 17:32:04 +00004102% o clone: clone the pixel cache.
4103%
cristy3ed852e2009-09-05 21:47:34 +00004104% o exception: return any errors or warnings in this structure.
4105%
4106*/
cristyc11dace2012-01-24 16:39:46 +00004107MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4108 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004109 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004110{
4111 CacheInfo
4112 *cache_info;
4113
4114 MagickOffsetType
4115 offset;
4116
4117 MagickSizeType
4118 number_pixels;
4119
4120 RectangleInfo
4121 region;
4122
4123 /*
4124 Validate pixel cache geometry.
4125 */
cristye7cc7cf2010-09-21 13:26:47 +00004126 assert(image != (const Image *) NULL);
4127 assert(image->signature == MagickSignature);
4128 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004129 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004130 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004131 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004132 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004133 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4134 {
4135 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004136 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004137 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004138 }
cristybb503372010-05-27 20:51:26 +00004139 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4140 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004141 {
4142 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004143 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004144 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004145 }
4146 offset=(MagickOffsetType) y*cache_info->columns+x;
4147 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004148 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004149 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4150 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4151 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004152 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004153 /*
4154 Return pixel cache.
4155 */
4156 region.x=x;
4157 region.y=y;
4158 region.width=columns;
4159 region.height=rows;
4160 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4161}
4162
4163/*
4164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4165% %
4166% %
4167% %
4168+ 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 %
4169% %
4170% %
4171% %
4172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4173%
4174% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4175% defined by the region rectangle and returns a pointer to the region. This
4176% region is subsequently transferred from the pixel cache with
4177% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4178% pixels are transferred, otherwise a NULL is returned.
4179%
4180% The format of the QueueAuthenticPixelsCache() method is:
4181%
cristy4c08aed2011-07-01 19:47:50 +00004182% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004183% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004184% ExceptionInfo *exception)
4185%
4186% A description of each parameter follows:
4187%
4188% o image: the image.
4189%
4190% o x,y,columns,rows: These values define the perimeter of a region of
4191% pixels.
4192%
4193% o exception: return any errors or warnings in this structure.
4194%
4195*/
cristy4c08aed2011-07-01 19:47:50 +00004196static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004197 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004198 ExceptionInfo *exception)
4199{
4200 CacheInfo
4201 *cache_info;
4202
cristy5c9e6f22010-09-17 17:31:01 +00004203 const int
4204 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004205
cristy4c08aed2011-07-01 19:47:50 +00004206 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004207 *q;
cristy4c08aed2011-07-01 19:47:50 +00004208
cristye7cc7cf2010-09-21 13:26:47 +00004209 assert(image != (const Image *) NULL);
4210 assert(image->signature == MagickSignature);
4211 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004212 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004213 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004214 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004215 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004216 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004217 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004218}
4219
4220/*
4221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4222% %
4223% %
4224% %
4225% Q u e u e A u t h e n t i c P i x e l s %
4226% %
4227% %
4228% %
4229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4230%
4231% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004232% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004233% region is returned, otherwise NULL is returned. The returned pointer may
4234% point to a temporary working buffer for the pixels or it may point to the
4235% final location of the pixels in memory.
4236%
4237% Write-only access means that any existing pixel values corresponding to
4238% the region are ignored. This is useful if the initial image is being
4239% created from scratch, or if the existing pixel values are to be
4240% completely replaced without need to refer to their pre-existing values.
4241% The application is free to read and write the pixel buffer returned by
4242% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4243% initialize the pixel array values. Initializing pixel array values is the
4244% application's responsibility.
4245%
4246% Performance is maximized if the selected region is part of one row, or
4247% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004248% pixels in-place (without a copy) if the image is in memory, or in a
4249% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004250% by the user.
4251%
4252% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004253% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4254% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4255% obtain the meta-content (of type void) corresponding to the region.
4256% Once the Quantum (and/or Quantum) array has been updated, the
4257% changes must be saved back to the underlying image using
4258% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004259%
4260% The format of the QueueAuthenticPixels() method is:
4261%
cristy4c08aed2011-07-01 19:47:50 +00004262% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004263% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004264% ExceptionInfo *exception)
4265%
4266% A description of each parameter follows:
4267%
4268% o image: the image.
4269%
4270% o x,y,columns,rows: These values define the perimeter of a region of
4271% pixels.
4272%
4273% o exception: return any errors or warnings in this structure.
4274%
4275*/
cristy4c08aed2011-07-01 19:47:50 +00004276MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004277 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004278 ExceptionInfo *exception)
4279{
4280 CacheInfo
4281 *cache_info;
4282
cristy2036f5c2010-09-19 21:18:17 +00004283 const int
4284 id = GetOpenMPThreadId();
4285
cristy4c08aed2011-07-01 19:47:50 +00004286 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004287 *q;
cristy4c08aed2011-07-01 19:47:50 +00004288
cristy3ed852e2009-09-05 21:47:34 +00004289 assert(image != (Image *) NULL);
4290 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004291 assert(image->cache != (Cache) NULL);
4292 cache_info=(CacheInfo *) image->cache;
4293 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004294 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004295 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004296 {
cristyc36c8822012-02-14 14:02:36 +00004297 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4298 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004299 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004300 }
cristy2036f5c2010-09-19 21:18:17 +00004301 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004302 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004303 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004304 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004305}
4306
4307/*
4308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4309% %
4310% %
4311% %
cristy4c08aed2011-07-01 19:47:50 +00004312+ 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 +00004313% %
4314% %
4315% %
4316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4317%
cristy4c08aed2011-07-01 19:47:50 +00004318% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004319% the pixel cache.
4320%
cristy4c08aed2011-07-01 19:47:50 +00004321% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004322%
cristy4c08aed2011-07-01 19:47:50 +00004323% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004324% NexusInfo *nexus_info,ExceptionInfo *exception)
4325%
4326% A description of each parameter follows:
4327%
4328% o cache_info: the pixel cache.
4329%
cristy4c08aed2011-07-01 19:47:50 +00004330% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004331%
4332% o exception: return any errors or warnings in this structure.
4333%
4334*/
cristy4c08aed2011-07-01 19:47:50 +00004335static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004336 NexusInfo *nexus_info,ExceptionInfo *exception)
4337{
4338 MagickOffsetType
4339 count,
4340 offset;
4341
4342 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004343 extent,
4344 length;
cristy3ed852e2009-09-05 21:47:34 +00004345
cristybb503372010-05-27 20:51:26 +00004346 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004347 y;
4348
cristy4c08aed2011-07-01 19:47:50 +00004349 register unsigned char
4350 *restrict q;
4351
cristybb503372010-05-27 20:51:26 +00004352 size_t
cristy3ed852e2009-09-05 21:47:34 +00004353 rows;
4354
cristy4c08aed2011-07-01 19:47:50 +00004355 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004356 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004357 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004358 return(MagickTrue);
4359 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4360 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004361 length=(MagickSizeType) nexus_info->region.width*
4362 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004363 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004364 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004365 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004366 switch (cache_info->type)
4367 {
4368 case MemoryCache:
4369 case MapCache:
4370 {
cristy4c08aed2011-07-01 19:47:50 +00004371 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004372 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004373
4374 /*
cristy4c08aed2011-07-01 19:47:50 +00004375 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004376 */
cristydd341db2010-03-04 19:06:38 +00004377 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004378 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004379 {
cristy48078b12010-09-23 17:11:01 +00004380 length=extent;
cristydd341db2010-03-04 19:06:38 +00004381 rows=1UL;
4382 }
cristy4c08aed2011-07-01 19:47:50 +00004383 p=(unsigned char *) cache_info->metacontent+offset*
4384 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004385 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004386 {
cristy8f036fe2010-09-18 02:02:00 +00004387 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004388 p+=cache_info->metacontent_extent*cache_info->columns;
4389 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004390 }
4391 break;
4392 }
4393 case DiskCache:
4394 {
4395 /*
cristy4c08aed2011-07-01 19:47:50 +00004396 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004397 */
4398 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4399 {
4400 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4401 cache_info->cache_filename);
4402 return(MagickFalse);
4403 }
cristydd341db2010-03-04 19:06:38 +00004404 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004405 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004406 {
cristy48078b12010-09-23 17:11:01 +00004407 length=extent;
cristydd341db2010-03-04 19:06:38 +00004408 rows=1UL;
4409 }
cristy48078b12010-09-23 17:11:01 +00004410 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004411 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004412 {
cristy48078b12010-09-23 17:11:01 +00004413 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004414 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004415 cache_info->metacontent_extent,length,(unsigned char *) q);
4416 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004417 break;
4418 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004419 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004420 }
cristyc11dace2012-01-24 16:39:46 +00004421 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4422 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004423 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004424 {
4425 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4426 cache_info->cache_filename);
4427 return(MagickFalse);
4428 }
4429 break;
4430 }
4431 default:
4432 break;
4433 }
4434 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004435 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004436 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004437 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004438 nexus_info->region.width,(double) nexus_info->region.height,(double)
4439 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004440 return(MagickTrue);
4441}
4442
4443/*
4444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4445% %
4446% %
4447% %
4448+ R e a d P i x e l C a c h e P i x e l s %
4449% %
4450% %
4451% %
4452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4453%
4454% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4455% cache.
4456%
4457% The format of the ReadPixelCachePixels() method is:
4458%
4459% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4460% NexusInfo *nexus_info,ExceptionInfo *exception)
4461%
4462% A description of each parameter follows:
4463%
4464% o cache_info: the pixel cache.
4465%
4466% o nexus_info: the cache nexus to read the pixels.
4467%
4468% o exception: return any errors or warnings in this structure.
4469%
4470*/
4471static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4472 NexusInfo *nexus_info,ExceptionInfo *exception)
4473{
4474 MagickOffsetType
4475 count,
4476 offset;
4477
4478 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004479 extent,
4480 length;
cristy3ed852e2009-09-05 21:47:34 +00004481
cristy4c08aed2011-07-01 19:47:50 +00004482 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004483 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004484
cristye076a6e2010-08-15 19:59:43 +00004485 register ssize_t
4486 y;
4487
cristybb503372010-05-27 20:51:26 +00004488 size_t
cristy3ed852e2009-09-05 21:47:34 +00004489 rows;
4490
cristy4c08aed2011-07-01 19:47:50 +00004491 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004492 return(MagickTrue);
4493 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4494 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004495 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004496 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004497 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004498 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004499 q=nexus_info->pixels;
4500 switch (cache_info->type)
4501 {
4502 case MemoryCache:
4503 case MapCache:
4504 {
cristy4c08aed2011-07-01 19:47:50 +00004505 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004506 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004507
4508 /*
4509 Read pixels from memory.
4510 */
cristydd341db2010-03-04 19:06:38 +00004511 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004512 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004513 {
cristy48078b12010-09-23 17:11:01 +00004514 length=extent;
cristydd341db2010-03-04 19:06:38 +00004515 rows=1UL;
4516 }
cristyed231572011-07-14 02:18:59 +00004517 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004518 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004519 {
cristy8f036fe2010-09-18 02:02:00 +00004520 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004521 p+=cache_info->number_channels*cache_info->columns;
4522 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004523 }
4524 break;
4525 }
4526 case DiskCache:
4527 {
4528 /*
4529 Read pixels from disk.
4530 */
4531 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4532 {
4533 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4534 cache_info->cache_filename);
4535 return(MagickFalse);
4536 }
cristydd341db2010-03-04 19:06:38 +00004537 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004538 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004539 {
cristy48078b12010-09-23 17:11:01 +00004540 length=extent;
cristydd341db2010-03-04 19:06:38 +00004541 rows=1UL;
4542 }
cristybb503372010-05-27 20:51:26 +00004543 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004544 {
4545 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004546 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004547 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004548 break;
4549 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004550 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004551 }
cristyc11dace2012-01-24 16:39:46 +00004552 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4553 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004554 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004555 {
4556 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4557 cache_info->cache_filename);
4558 return(MagickFalse);
4559 }
4560 break;
4561 }
4562 default:
4563 break;
4564 }
4565 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004566 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004567 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004568 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004569 nexus_info->region.width,(double) nexus_info->region.height,(double)
4570 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004571 return(MagickTrue);
4572}
4573
4574/*
4575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4576% %
4577% %
4578% %
4579+ R e f e r e n c e P i x e l C a c h e %
4580% %
4581% %
4582% %
4583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4584%
4585% ReferencePixelCache() increments the reference count associated with the
4586% pixel cache returning a pointer to the cache.
4587%
4588% The format of the ReferencePixelCache method is:
4589%
4590% Cache ReferencePixelCache(Cache cache_info)
4591%
4592% A description of each parameter follows:
4593%
4594% o cache_info: the pixel cache.
4595%
4596*/
cristya6577ff2011-09-02 19:54:26 +00004597MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004598{
4599 CacheInfo
4600 *cache_info;
4601
4602 assert(cache != (Cache *) NULL);
4603 cache_info=(CacheInfo *) cache;
4604 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004605 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004606 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004607 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004608 return(cache_info);
4609}
4610
4611/*
4612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4613% %
4614% %
4615% %
4616+ S e t P i x e l C a c h e M e t h o d s %
4617% %
4618% %
4619% %
4620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4621%
4622% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4623%
4624% The format of the SetPixelCacheMethods() method is:
4625%
4626% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4627%
4628% A description of each parameter follows:
4629%
4630% o cache: the pixel cache.
4631%
4632% o cache_methods: Specifies a pointer to a CacheMethods structure.
4633%
4634*/
cristya6577ff2011-09-02 19:54:26 +00004635MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004636{
4637 CacheInfo
4638 *cache_info;
4639
4640 GetOneAuthenticPixelFromHandler
4641 get_one_authentic_pixel_from_handler;
4642
4643 GetOneVirtualPixelFromHandler
4644 get_one_virtual_pixel_from_handler;
4645
4646 /*
4647 Set cache pixel methods.
4648 */
4649 assert(cache != (Cache) NULL);
4650 assert(cache_methods != (CacheMethods *) NULL);
4651 cache_info=(CacheInfo *) cache;
4652 assert(cache_info->signature == MagickSignature);
4653 if (cache_info->debug != MagickFalse)
4654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4655 cache_info->filename);
4656 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4657 cache_info->methods.get_virtual_pixel_handler=
4658 cache_methods->get_virtual_pixel_handler;
4659 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4660 cache_info->methods.destroy_pixel_handler=
4661 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004662 if (cache_methods->get_virtual_metacontent_from_handler !=
4663 (GetVirtualMetacontentFromHandler) NULL)
4664 cache_info->methods.get_virtual_metacontent_from_handler=
4665 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004666 if (cache_methods->get_authentic_pixels_handler !=
4667 (GetAuthenticPixelsHandler) NULL)
4668 cache_info->methods.get_authentic_pixels_handler=
4669 cache_methods->get_authentic_pixels_handler;
4670 if (cache_methods->queue_authentic_pixels_handler !=
4671 (QueueAuthenticPixelsHandler) NULL)
4672 cache_info->methods.queue_authentic_pixels_handler=
4673 cache_methods->queue_authentic_pixels_handler;
4674 if (cache_methods->sync_authentic_pixels_handler !=
4675 (SyncAuthenticPixelsHandler) NULL)
4676 cache_info->methods.sync_authentic_pixels_handler=
4677 cache_methods->sync_authentic_pixels_handler;
4678 if (cache_methods->get_authentic_pixels_from_handler !=
4679 (GetAuthenticPixelsFromHandler) NULL)
4680 cache_info->methods.get_authentic_pixels_from_handler=
4681 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004682 if (cache_methods->get_authentic_metacontent_from_handler !=
4683 (GetAuthenticMetacontentFromHandler) NULL)
4684 cache_info->methods.get_authentic_metacontent_from_handler=
4685 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004686 get_one_virtual_pixel_from_handler=
4687 cache_info->methods.get_one_virtual_pixel_from_handler;
4688 if (get_one_virtual_pixel_from_handler !=
4689 (GetOneVirtualPixelFromHandler) NULL)
4690 cache_info->methods.get_one_virtual_pixel_from_handler=
4691 cache_methods->get_one_virtual_pixel_from_handler;
4692 get_one_authentic_pixel_from_handler=
4693 cache_methods->get_one_authentic_pixel_from_handler;
4694 if (get_one_authentic_pixel_from_handler !=
4695 (GetOneAuthenticPixelFromHandler) NULL)
4696 cache_info->methods.get_one_authentic_pixel_from_handler=
4697 cache_methods->get_one_authentic_pixel_from_handler;
4698}
4699
4700/*
4701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4702% %
4703% %
4704% %
4705+ S e t P i x e l C a c h e N e x u s P i x e l s %
4706% %
4707% %
4708% %
4709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4710%
4711% SetPixelCacheNexusPixels() defines the region of the cache for the
4712% specified cache nexus.
4713%
4714% The format of the SetPixelCacheNexusPixels() method is:
4715%
cristy4c08aed2011-07-01 19:47:50 +00004716% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004717% const RectangleInfo *region,NexusInfo *nexus_info,
4718% ExceptionInfo *exception)
4719%
4720% A description of each parameter follows:
4721%
4722% o image: the image.
4723%
4724% o region: A pointer to the RectangleInfo structure that defines the
4725% region of this particular cache nexus.
4726%
4727% o nexus_info: the cache nexus to set.
4728%
4729% o exception: return any errors or warnings in this structure.
4730%
4731*/
cristyabd6e372010-09-15 19:11:26 +00004732
4733static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4734 NexusInfo *nexus_info,ExceptionInfo *exception)
4735{
4736 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4737 return(MagickFalse);
4738 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004739 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004740 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004741 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004742 {
4743 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004744 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004745 nexus_info->length);
4746 }
cristy4c08aed2011-07-01 19:47:50 +00004747 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004748 {
4749 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004750 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004751 cache_info->filename);
4752 return(MagickFalse);
4753 }
4754 return(MagickTrue);
4755}
4756
cristy4c08aed2011-07-01 19:47:50 +00004757static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004758 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4759{
4760 CacheInfo
4761 *cache_info;
4762
4763 MagickBooleanType
4764 status;
4765
cristy3ed852e2009-09-05 21:47:34 +00004766 MagickSizeType
4767 length,
4768 number_pixels;
4769
cristy3ed852e2009-09-05 21:47:34 +00004770 cache_info=(CacheInfo *) image->cache;
4771 assert(cache_info->signature == MagickSignature);
4772 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004773 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004774 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004775 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004776 {
cristybb503372010-05-27 20:51:26 +00004777 ssize_t
cristybad067a2010-02-15 17:20:55 +00004778 x,
4779 y;
cristy3ed852e2009-09-05 21:47:34 +00004780
cristyeaedf062010-05-29 22:36:02 +00004781 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4782 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004783 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4784 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004785 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004786 ((nexus_info->region.width == cache_info->columns) ||
4787 ((nexus_info->region.width % cache_info->columns) == 0)))))
4788 {
4789 MagickOffsetType
4790 offset;
4791
4792 /*
4793 Pixels are accessed directly from memory.
4794 */
4795 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4796 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004797 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004798 offset;
4799 nexus_info->metacontent=(void *) NULL;
4800 if (cache_info->metacontent_extent != 0)
4801 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4802 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004803 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004804 }
4805 }
4806 /*
4807 Pixels are stored in a cache region until they are synced to the cache.
4808 */
4809 number_pixels=(MagickSizeType) nexus_info->region.width*
4810 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004811 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004812 if (cache_info->metacontent_extent != 0)
4813 length+=number_pixels*cache_info->metacontent_extent;
4814 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004815 {
4816 nexus_info->length=length;
4817 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4818 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004819 {
4820 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004821 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004822 }
cristy3ed852e2009-09-05 21:47:34 +00004823 }
4824 else
4825 if (nexus_info->length != length)
4826 {
4827 RelinquishCacheNexusPixels(nexus_info);
4828 nexus_info->length=length;
4829 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4830 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004831 {
4832 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004833 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004834 }
cristy3ed852e2009-09-05 21:47:34 +00004835 }
4836 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004837 nexus_info->metacontent=(void *) NULL;
4838 if (cache_info->metacontent_extent != 0)
4839 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004840 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004841 return(nexus_info->pixels);
4842}
4843
4844/*
4845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4846% %
4847% %
4848% %
4849% 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 %
4850% %
4851% %
4852% %
4853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4854%
4855% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4856% pixel cache and returns the previous setting. A virtual pixel is any pixel
4857% access that is outside the boundaries of the image cache.
4858%
4859% The format of the SetPixelCacheVirtualMethod() method is:
4860%
cristy387430f2012-02-07 13:09:46 +00004861% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4862% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004863%
4864% A description of each parameter follows:
4865%
4866% o image: the image.
4867%
4868% o virtual_pixel_method: choose the type of virtual pixel.
4869%
cristy387430f2012-02-07 13:09:46 +00004870% o exception: return any errors or warnings in this structure.
4871%
cristy3ed852e2009-09-05 21:47:34 +00004872*/
cristy3d4cb882012-02-07 19:11:26 +00004873
4874static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4875 ExceptionInfo *exception)
4876{
4877 CacheInfo
4878 *cache_info;
4879
cristyf2719112012-05-06 18:38:46 +00004880 CacheView
4881 *image_view;
4882
cristy3d4cb882012-02-07 19:11:26 +00004883 MagickBooleanType
4884 status;
4885
4886 ssize_t
4887 y;
4888
4889 assert(image != (Image *) NULL);
4890 assert(image->signature == MagickSignature);
4891 if (image->debug != MagickFalse)
4892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4893 assert(image->cache != (Cache) NULL);
4894 cache_info=(CacheInfo *) image->cache;
4895 assert(cache_info->signature == MagickSignature);
4896 image->matte=MagickTrue;
4897 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004898 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004899#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004900 #pragma omp parallel for schedule(static) shared(status) \
cristyddacdd12012-05-07 23:08:14 +00004901 dynamic_number_threads(image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004902#endif
4903 for (y=0; y < (ssize_t) image->rows; y++)
4904 {
cristy3d4cb882012-02-07 19:11:26 +00004905 register Quantum
4906 *restrict q;
4907
4908 register ssize_t
4909 x;
4910
4911 if (status == MagickFalse)
4912 continue;
cristy23d198a2012-03-13 13:48:08 +00004913 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004914 if (q == (Quantum *) NULL)
4915 {
4916 status=MagickFalse;
4917 continue;
4918 }
4919 for (x=0; x < (ssize_t) image->columns; x++)
4920 {
4921 SetPixelAlpha(image,alpha,q);
4922 q+=GetPixelChannels(image);
4923 }
cristy23d198a2012-03-13 13:48:08 +00004924 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004925 }
cristy23d198a2012-03-13 13:48:08 +00004926 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004927 return(status);
4928}
4929
cristy387430f2012-02-07 13:09:46 +00004930MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4931 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004932{
4933 CacheInfo
4934 *cache_info;
4935
4936 VirtualPixelMethod
4937 method;
4938
4939 assert(image != (Image *) NULL);
4940 assert(image->signature == MagickSignature);
4941 if (image->debug != MagickFalse)
4942 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4943 assert(image->cache != (Cache) NULL);
4944 cache_info=(CacheInfo *) image->cache;
4945 assert(cache_info->signature == MagickSignature);
4946 method=cache_info->virtual_pixel_method;
4947 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004948 switch (virtual_pixel_method)
4949 {
4950 case BackgroundVirtualPixelMethod:
4951 {
4952 if ((image->background_color.matte != MagickFalse) &&
4953 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00004954 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004955 break;
4956 }
4957 case TransparentVirtualPixelMethod:
4958 {
4959 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004960 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004961 break;
4962 }
4963 default:
4964 break;
4965 }
cristy3ed852e2009-09-05 21:47:34 +00004966 return(method);
4967}
4968
4969/*
4970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4971% %
4972% %
4973% %
4974+ 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 %
4975% %
4976% %
4977% %
4978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4979%
4980% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4981% in-memory or disk cache. The method returns MagickTrue if the pixel region
4982% is synced, otherwise MagickFalse.
4983%
4984% The format of the SyncAuthenticPixelCacheNexus() method is:
4985%
4986% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4987% NexusInfo *nexus_info,ExceptionInfo *exception)
4988%
4989% A description of each parameter follows:
4990%
4991% o image: the image.
4992%
4993% o nexus_info: the cache nexus to sync.
4994%
4995% o exception: return any errors or warnings in this structure.
4996%
4997*/
cristya6577ff2011-09-02 19:54:26 +00004998MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004999 NexusInfo *nexus_info,ExceptionInfo *exception)
5000{
5001 CacheInfo
5002 *cache_info;
5003
5004 MagickBooleanType
5005 status;
5006
5007 /*
5008 Transfer pixels to the cache.
5009 */
5010 assert(image != (Image *) NULL);
5011 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005012 if (image->cache == (Cache) NULL)
5013 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5014 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005015 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005016 if (cache_info->type == UndefinedCache)
5017 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005018 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005019 return(MagickTrue);
5020 assert(cache_info->signature == MagickSignature);
5021 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005022 if ((cache_info->metacontent_extent != 0) &&
5023 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005024 return(MagickFalse);
5025 return(status);
5026}
5027
5028/*
5029%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5030% %
5031% %
5032% %
5033+ S y n c A u t h e n t i c P i x e l C a c h e %
5034% %
5035% %
5036% %
5037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5038%
5039% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5040% or disk cache. The method returns MagickTrue if the pixel region is synced,
5041% otherwise MagickFalse.
5042%
5043% The format of the SyncAuthenticPixelsCache() method is:
5044%
5045% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5046% ExceptionInfo *exception)
5047%
5048% A description of each parameter follows:
5049%
5050% o image: the image.
5051%
5052% o exception: return any errors or warnings in this structure.
5053%
5054*/
5055static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5056 ExceptionInfo *exception)
5057{
5058 CacheInfo
5059 *cache_info;
5060
cristy5c9e6f22010-09-17 17:31:01 +00005061 const int
5062 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005063
cristy4c08aed2011-07-01 19:47:50 +00005064 MagickBooleanType
5065 status;
5066
cristye7cc7cf2010-09-21 13:26:47 +00005067 assert(image != (Image *) NULL);
5068 assert(image->signature == MagickSignature);
5069 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005070 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005071 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005072 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005073 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5074 exception);
5075 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005076}
5077
5078/*
5079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5080% %
5081% %
5082% %
5083% S y n c A u t h e n t i c P i x e l s %
5084% %
5085% %
5086% %
5087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5088%
5089% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5090% The method returns MagickTrue if the pixel region is flushed, otherwise
5091% MagickFalse.
5092%
5093% The format of the SyncAuthenticPixels() method is:
5094%
5095% MagickBooleanType SyncAuthenticPixels(Image *image,
5096% ExceptionInfo *exception)
5097%
5098% A description of each parameter follows:
5099%
5100% o image: the image.
5101%
5102% o exception: return any errors or warnings in this structure.
5103%
5104*/
5105MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5106 ExceptionInfo *exception)
5107{
5108 CacheInfo
5109 *cache_info;
5110
cristy2036f5c2010-09-19 21:18:17 +00005111 const int
5112 id = GetOpenMPThreadId();
5113
cristy4c08aed2011-07-01 19:47:50 +00005114 MagickBooleanType
5115 status;
5116
cristy3ed852e2009-09-05 21:47:34 +00005117 assert(image != (Image *) NULL);
5118 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005119 assert(image->cache != (Cache) NULL);
5120 cache_info=(CacheInfo *) image->cache;
5121 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005122 if (cache_info->methods.sync_authentic_pixels_handler !=
5123 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005124 {
5125 status=cache_info->methods.sync_authentic_pixels_handler(image,
5126 exception);
5127 return(status);
5128 }
cristy2036f5c2010-09-19 21:18:17 +00005129 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005130 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5131 exception);
5132 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005133}
5134
5135/*
5136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137% %
5138% %
5139% %
cristyd1dd6e42011-09-04 01:46:08 +00005140+ 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 +00005141% %
5142% %
5143% %
5144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5145%
5146% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5147% The method returns MagickTrue if the pixel region is flushed, otherwise
5148% MagickFalse.
5149%
5150% The format of the SyncImagePixelCache() method is:
5151%
5152% MagickBooleanType SyncImagePixelCache(Image *image,
5153% ExceptionInfo *exception)
5154%
5155% A description of each parameter follows:
5156%
5157% o image: the image.
5158%
5159% o exception: return any errors or warnings in this structure.
5160%
5161*/
cristyd1dd6e42011-09-04 01:46:08 +00005162MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005163 ExceptionInfo *exception)
5164{
5165 CacheInfo
5166 *cache_info;
5167
5168 assert(image != (Image *) NULL);
5169 assert(exception != (ExceptionInfo *) NULL);
5170 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5171 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5172}
5173
5174/*
5175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5176% %
5177% %
5178% %
cristy4c08aed2011-07-01 19:47:50 +00005179+ 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 +00005180% %
5181% %
5182% %
5183%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5184%
cristy4c08aed2011-07-01 19:47:50 +00005185% WritePixelCacheMetacontent() writes the meta-content to the specified region
5186% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005187%
cristy4c08aed2011-07-01 19:47:50 +00005188% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005189%
cristy4c08aed2011-07-01 19:47:50 +00005190% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005191% NexusInfo *nexus_info,ExceptionInfo *exception)
5192%
5193% A description of each parameter follows:
5194%
5195% o cache_info: the pixel cache.
5196%
cristy4c08aed2011-07-01 19:47:50 +00005197% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005198%
5199% o exception: return any errors or warnings in this structure.
5200%
5201*/
cristy4c08aed2011-07-01 19:47:50 +00005202static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005203 NexusInfo *nexus_info,ExceptionInfo *exception)
5204{
5205 MagickOffsetType
5206 count,
5207 offset;
5208
5209 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005210 extent,
5211 length;
cristy3ed852e2009-09-05 21:47:34 +00005212
cristy4c08aed2011-07-01 19:47:50 +00005213 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005214 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005215
cristybb503372010-05-27 20:51:26 +00005216 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005217 y;
5218
cristybb503372010-05-27 20:51:26 +00005219 size_t
cristy3ed852e2009-09-05 21:47:34 +00005220 rows;
5221
cristy4c08aed2011-07-01 19:47:50 +00005222 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005223 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005224 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005225 return(MagickTrue);
5226 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5227 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005228 length=(MagickSizeType) nexus_info->region.width*
5229 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005230 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005231 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005232 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005233 switch (cache_info->type)
5234 {
5235 case MemoryCache:
5236 case MapCache:
5237 {
cristy4c08aed2011-07-01 19:47:50 +00005238 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005239 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005240
5241 /*
cristy4c08aed2011-07-01 19:47:50 +00005242 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005243 */
cristydd341db2010-03-04 19:06:38 +00005244 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005245 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005246 {
cristy48078b12010-09-23 17:11:01 +00005247 length=extent;
cristydd341db2010-03-04 19:06:38 +00005248 rows=1UL;
5249 }
cristy4c08aed2011-07-01 19:47:50 +00005250 q=(unsigned char *) cache_info->metacontent+offset*
5251 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005252 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005253 {
cristy8f036fe2010-09-18 02:02:00 +00005254 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005255 p+=nexus_info->region.width*cache_info->metacontent_extent;
5256 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005257 }
5258 break;
5259 }
5260 case DiskCache:
5261 {
5262 /*
cristy4c08aed2011-07-01 19:47:50 +00005263 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005264 */
5265 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5266 {
5267 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5268 cache_info->cache_filename);
5269 return(MagickFalse);
5270 }
cristydd341db2010-03-04 19:06:38 +00005271 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005272 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005273 {
cristy48078b12010-09-23 17:11:01 +00005274 length=extent;
cristydd341db2010-03-04 19:06:38 +00005275 rows=1UL;
5276 }
cristy48078b12010-09-23 17:11:01 +00005277 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005278 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005279 {
cristy48078b12010-09-23 17:11:01 +00005280 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005281 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005282 cache_info->metacontent_extent,length,(const unsigned char *) p);
5283 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005284 break;
cristy4c08aed2011-07-01 19:47:50 +00005285 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005286 offset+=cache_info->columns;
5287 }
cristyc11dace2012-01-24 16:39:46 +00005288 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5289 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005290 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005291 {
5292 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5293 cache_info->cache_filename);
5294 return(MagickFalse);
5295 }
5296 break;
5297 }
5298 default:
5299 break;
5300 }
5301 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005302 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005303 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005304 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005305 nexus_info->region.width,(double) nexus_info->region.height,(double)
5306 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005307 return(MagickTrue);
5308}
5309
5310/*
5311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5312% %
5313% %
5314% %
5315+ W r i t e C a c h e P i x e l s %
5316% %
5317% %
5318% %
5319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5320%
5321% WritePixelCachePixels() writes image pixels to the specified region of the
5322% pixel cache.
5323%
5324% The format of the WritePixelCachePixels() method is:
5325%
5326% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5327% NexusInfo *nexus_info,ExceptionInfo *exception)
5328%
5329% A description of each parameter follows:
5330%
5331% o cache_info: the pixel cache.
5332%
5333% o nexus_info: the cache nexus to write the pixels.
5334%
5335% o exception: return any errors or warnings in this structure.
5336%
5337*/
5338static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5339 NexusInfo *nexus_info,ExceptionInfo *exception)
5340{
5341 MagickOffsetType
5342 count,
5343 offset;
5344
5345 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005346 extent,
5347 length;
cristy3ed852e2009-09-05 21:47:34 +00005348
cristy4c08aed2011-07-01 19:47:50 +00005349 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005350 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005351
cristybb503372010-05-27 20:51:26 +00005352 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005353 y;
5354
cristybb503372010-05-27 20:51:26 +00005355 size_t
cristy3ed852e2009-09-05 21:47:34 +00005356 rows;
5357
cristy4c08aed2011-07-01 19:47:50 +00005358 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005359 return(MagickTrue);
5360 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5361 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005362 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005363 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005364 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005365 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005366 p=nexus_info->pixels;
5367 switch (cache_info->type)
5368 {
5369 case MemoryCache:
5370 case MapCache:
5371 {
cristy4c08aed2011-07-01 19:47:50 +00005372 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005373 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005374
5375 /*
5376 Write pixels to memory.
5377 */
cristydd341db2010-03-04 19:06:38 +00005378 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005379 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005380 {
cristy48078b12010-09-23 17:11:01 +00005381 length=extent;
cristydd341db2010-03-04 19:06:38 +00005382 rows=1UL;
5383 }
cristyed231572011-07-14 02:18:59 +00005384 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005385 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005386 {
cristy8f036fe2010-09-18 02:02:00 +00005387 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005388 p+=nexus_info->region.width*cache_info->number_channels;
5389 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005390 }
5391 break;
5392 }
5393 case DiskCache:
5394 {
5395 /*
5396 Write pixels to disk.
5397 */
5398 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5399 {
5400 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5401 cache_info->cache_filename);
5402 return(MagickFalse);
5403 }
cristydd341db2010-03-04 19:06:38 +00005404 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005405 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005406 {
cristy48078b12010-09-23 17:11:01 +00005407 length=extent;
cristydd341db2010-03-04 19:06:38 +00005408 rows=1UL;
5409 }
cristybb503372010-05-27 20:51:26 +00005410 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005411 {
5412 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005413 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005414 p);
5415 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005416 break;
cristyed231572011-07-14 02:18:59 +00005417 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005418 offset+=cache_info->columns;
5419 }
cristyc11dace2012-01-24 16:39:46 +00005420 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5421 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005422 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005423 {
5424 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5425 cache_info->cache_filename);
5426 return(MagickFalse);
5427 }
5428 break;
5429 }
5430 default:
5431 break;
5432 }
5433 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005434 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005435 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005436 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005437 nexus_info->region.width,(double) nexus_info->region.height,(double)
5438 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005439 return(MagickTrue);
5440}