blob: c773338ee548d7f99450ac294a1e953e75f5fed2 [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 *),
cristy265a2b22012-05-11 12:48:50 +0000150 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
151 NexusInfo *,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)
cristyfeeb98d2012-05-09 16:32:12 +0000204 cache_info->number_threads=GetOpenMPMaximumThreads();
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;
cristyf84a1932010-01-03 18:00:18 +0000518 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000519 return(MagickTrue);
520}
521
cristyf1832792012-05-08 18:38:18 +0000522static inline MagickOffsetType ReadPixelCacheRegion(
523 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
524 const MagickSizeType length,unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000525{
526 register MagickOffsetType
527 i;
528
529 ssize_t
530 count;
531
532#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000533 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000534 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000535 {
cristyf84a1932010-01-03 18:00:18 +0000536 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000537 return((MagickOffsetType) -1);
538 }
539#endif
540 count=0;
541 for (i=0; i < (MagickOffsetType) length; i+=count)
542 {
543#if !defined(MAGICKCORE_HAVE_PREAD)
544 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
545 (MagickSizeType) SSIZE_MAX));
546#else
547 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000548 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000549#endif
550 if (count > 0)
551 continue;
552 count=0;
553 if (errno != EINTR)
554 {
555 i=(-1);
556 break;
557 }
558 }
559#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000560 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000561#endif
562 return(i);
563}
564
cristyf1832792012-05-08 18:38:18 +0000565static inline MagickOffsetType WritePixelCacheRegion(
566 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
567 const MagickSizeType length,const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000568{
569 register MagickOffsetType
570 i;
571
572 ssize_t
573 count;
574
575#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000576 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000577 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000578 {
cristyf84a1932010-01-03 18:00:18 +0000579 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000580 return((MagickOffsetType) -1);
581 }
582#endif
583 count=0;
584 for (i=0; i < (MagickOffsetType) length; i+=count)
585 {
586#if !defined(MAGICKCORE_HAVE_PWRITE)
587 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
588 (MagickSizeType) SSIZE_MAX));
589#else
590 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000591 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000592#endif
593 if (count > 0)
594 continue;
595 count=0;
596 if (errno != EINTR)
597 {
598 i=(-1);
599 break;
600 }
601 }
602#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000603 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000604#endif
605 return(i);
606}
607
cristy4c08aed2011-07-01 19:47:50 +0000608static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000609 CacheInfo *cache_info,ExceptionInfo *exception)
610{
611 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000612 count;
cristy3ed852e2009-09-05 21:47:34 +0000613
cristy4c08aed2011-07-01 19:47:50 +0000614 register MagickOffsetType
615 i;
cristye076a6e2010-08-15 19:59:43 +0000616
cristybb503372010-05-27 20:51:26 +0000617 size_t
cristy4c08aed2011-07-01 19:47:50 +0000618 length;
cristy3ed852e2009-09-05 21:47:34 +0000619
cristy4c08aed2011-07-01 19:47:50 +0000620 unsigned char
621 *blob;
622
623 /*
624 Clone pixel cache (both caches on disk).
625 */
cristy3ed852e2009-09-05 21:47:34 +0000626 if (cache_info->debug != MagickFalse)
627 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000628 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000629 sizeof(*blob));
630 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000631 {
cristy4c08aed2011-07-01 19:47:50 +0000632 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000633 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000634 cache_info->filename);
635 return(MagickFalse);
636 }
cristy3dedf062011-07-02 14:07:40 +0000637 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000638 {
639 blob=(unsigned char *) RelinquishMagickMemory(blob);
640 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
641 cache_info->cache_filename);
642 return(MagickFalse);
643 }
cristy3dedf062011-07-02 14:07:40 +0000644 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000645 {
646 (void) ClosePixelCacheOnDisk(cache_info);
647 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000648 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
649 clone_info->cache_filename);
650 return(MagickFalse);
651 }
cristy4c08aed2011-07-01 19:47:50 +0000652 count=0;
653 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000654 {
cristy4c08aed2011-07-01 19:47:50 +0000655 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
656 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
657 blob);
658 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000659 {
cristy4c08aed2011-07-01 19:47:50 +0000660 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
661 cache_info->cache_filename);
662 break;
cristy3ed852e2009-09-05 21:47:34 +0000663 }
cristy4c08aed2011-07-01 19:47:50 +0000664 length=(size_t) count;
665 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
666 if ((MagickSizeType) count != length)
667 {
668 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
669 clone_info->cache_filename);
670 break;
671 }
672 }
673 (void) ClosePixelCacheOnDisk(clone_info);
674 (void) ClosePixelCacheOnDisk(cache_info);
675 blob=(unsigned char *) RelinquishMagickMemory(blob);
676 if (i < (MagickOffsetType) cache_info->length)
677 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
cristyfd24a062012-01-02 14:46:34 +0000681static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000682 CacheInfo *cache_info,ExceptionInfo *exception)
683{
684 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000685 count;
cristy3ed852e2009-09-05 21:47:34 +0000686
cristy4c08aed2011-07-01 19:47:50 +0000687 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000688 {
cristy3ed852e2009-09-05 21:47:34 +0000689 /*
cristy4c08aed2011-07-01 19:47:50 +0000690 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000691 */
cristy4c08aed2011-07-01 19:47:50 +0000692 if (cache_info->debug != MagickFalse)
693 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
694 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
695 cache_info->length);
696 return(MagickTrue);
697 }
698 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
699 {
700 /*
701 Clone pixel cache (one cache on disk, one in memory).
702 */
703 if (cache_info->debug != MagickFalse)
704 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
705 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000706 {
cristy4c08aed2011-07-01 19:47:50 +0000707 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000708 cache_info->cache_filename);
709 return(MagickFalse);
710 }
cristy4c08aed2011-07-01 19:47:50 +0000711 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
712 cache_info->length,(unsigned char *) clone_info->pixels);
713 (void) ClosePixelCacheOnDisk(cache_info);
714 if ((MagickSizeType) count != cache_info->length)
715 {
716 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
717 cache_info->cache_filename);
718 return(MagickFalse);
719 }
720 return(MagickTrue);
721 }
722 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
723 {
724 /*
725 Clone pixel cache (one cache on disk, one in memory).
726 */
727 if (clone_info->debug != MagickFalse)
728 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
729 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
730 {
731 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
732 clone_info->cache_filename);
733 return(MagickFalse);
734 }
735 count=WritePixelCacheRegion(clone_info,clone_info->offset,
736 clone_info->length,(unsigned char *) cache_info->pixels);
737 (void) ClosePixelCacheOnDisk(clone_info);
738 if ((MagickSizeType) count != clone_info->length)
739 {
740 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
741 clone_info->cache_filename);
742 return(MagickFalse);
743 }
744 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000745 }
746 /*
cristy4c08aed2011-07-01 19:47:50 +0000747 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000748 */
cristy4c08aed2011-07-01 19:47:50 +0000749 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000750}
751
cristyfd24a062012-01-02 14:46:34 +0000752static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000753 CacheInfo *cache_info,ExceptionInfo *exception)
754{
cristy4c08aed2011-07-01 19:47:50 +0000755 MagickBooleanType
756 status;
cristy3ed852e2009-09-05 21:47:34 +0000757
cristy4c08aed2011-07-01 19:47:50 +0000758 MagickOffsetType
759 cache_offset,
760 clone_offset,
761 count;
762
763 register ssize_t
764 x;
765
cristyfd24a062012-01-02 14:46:34 +0000766 register unsigned char
767 *p;
768
cristy4c08aed2011-07-01 19:47:50 +0000769 size_t
cristy3ed852e2009-09-05 21:47:34 +0000770 length;
771
cristy4c08aed2011-07-01 19:47:50 +0000772 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000773 y;
774
cristy4c08aed2011-07-01 19:47:50 +0000775 unsigned char
776 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000777
cristy4c08aed2011-07-01 19:47:50 +0000778 /*
779 Clone pixel cache (unoptimized).
780 */
cristy3ed852e2009-09-05 21:47:34 +0000781 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000782 {
cristy4c08aed2011-07-01 19:47:50 +0000783 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
784 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
785 else
786 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
787 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
788 else
789 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
791 else
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
793 }
cristyed231572011-07-14 02:18:59 +0000794 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
795 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000796 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000797 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000798 if (blob == (unsigned char *) NULL)
799 {
800 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000801 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy4c08aed2011-07-01 19:47:50 +0000802 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000803 return(MagickFalse);
804 }
cristy4c08aed2011-07-01 19:47:50 +0000805 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
806 cache_offset=0;
807 clone_offset=0;
808 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000809 {
cristy4c08aed2011-07-01 19:47:50 +0000810 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 blob=(unsigned char *) RelinquishMagickMemory(blob);
813 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000814 cache_info->cache_filename);
815 return(MagickFalse);
816 }
cristy4c08aed2011-07-01 19:47:50 +0000817 cache_offset=cache_info->offset;
818 }
819 if (clone_info->type == DiskCache)
820 {
cristy3dedf062011-07-02 14:07:40 +0000821 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000822 {
cristy4c08aed2011-07-01 19:47:50 +0000823 blob=(unsigned char *) RelinquishMagickMemory(blob);
824 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
825 clone_info->cache_filename);
826 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000827 }
cristy4c08aed2011-07-01 19:47:50 +0000828 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000829 }
830 /*
cristy4c08aed2011-07-01 19:47:50 +0000831 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000832 */
cristy4c08aed2011-07-01 19:47:50 +0000833 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000834 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000835 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000836 {
cristy4c08aed2011-07-01 19:47:50 +0000837 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
cristy9e0719b2011-12-29 03:45:45 +0000839 register ssize_t
840 i;
841
cristy3ed852e2009-09-05 21:47:34 +0000842 /*
cristy4c08aed2011-07-01 19:47:50 +0000843 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000844 */
cristyed231572011-07-14 02:18:59 +0000845 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000846 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000847 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000848 else
849 {
cristyfd24a062012-01-02 14:46:34 +0000850 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000851 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000852 {
cristy4c08aed2011-07-01 19:47:50 +0000853 status=MagickFalse;
854 break;
cristy3ed852e2009-09-05 21:47:34 +0000855 }
856 }
cristy4c08aed2011-07-01 19:47:50 +0000857 cache_offset+=length;
858 if ((y < (ssize_t) clone_info->rows) &&
859 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000860 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000861 {
cristy9e0719b2011-12-29 03:45:45 +0000862 PixelChannel
863 channel;
864
865 PixelTrait
866 traits;
867
868 ssize_t
869 offset;
870
cristy4c08aed2011-07-01 19:47:50 +0000871 /*
cristy3b8fe922011-12-29 18:56:23 +0000872 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000873 */
cristy9e0719b2011-12-29 03:45:45 +0000874 channel=clone_info->channel_map[i].channel;
875 traits=cache_info->channel_map[channel].traits;
876 if (traits == UndefinedPixelTrait)
877 {
cristy0f4425e2011-12-31 20:33:02 +0000878 clone_offset+=sizeof(Quantum);
879 continue;
cristy9e0719b2011-12-29 03:45:45 +0000880 }
cristy0f4425e2011-12-31 20:33:02 +0000881 offset=cache_info->channel_map[channel].offset;
882 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000883 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
884 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000885 else
886 {
cristy0f4425e2011-12-31 20:33:02 +0000887 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000888 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000889 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000890 {
cristy0f4425e2011-12-31 20:33:02 +0000891 status=MagickFalse;
892 break;
cristy4c08aed2011-07-01 19:47:50 +0000893 }
894 }
cristy9e0719b2011-12-29 03:45:45 +0000895 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000896 }
897 }
cristyac245f82012-05-05 17:13:57 +0000898 if (y < (ssize_t) clone_info->rows)
cristye04362f2012-04-23 15:33:05 +0000899 {
900 /*
901 Set remaining columns as undefined.
902 */
cristy888e6132012-04-23 19:54:54 +0000903 length=clone_info->number_channels*sizeof(Quantum);
904 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
905 for ( ; x < (ssize_t) clone_info->columns; x++)
906 {
907 if (clone_info->type != DiskCache)
908 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
909 blob,length);
910 else
911 {
912 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
913 if ((MagickSizeType) count != length)
914 {
915 status=MagickFalse;
916 break;
cristye04362f2012-04-23 15:33:05 +0000917 }
cristy888e6132012-04-23 19:54:54 +0000918 }
919 clone_offset+=length;
920 }
cristye04362f2012-04-23 15:33:05 +0000921 }
cristy4c08aed2011-07-01 19:47:50 +0000922 }
cristyed231572011-07-14 02:18:59 +0000923 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000924 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
925 for ( ; y < (ssize_t) clone_info->rows; y++)
926 {
927 /*
cristy9e0719b2011-12-29 03:45:45 +0000928 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000929 */
930 for (x=0; x < (ssize_t) clone_info->columns; x++)
931 {
932 if (clone_info->type != DiskCache)
933 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
934 length);
935 else
936 {
937 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
938 if ((MagickSizeType) count != length)
939 {
940 status=MagickFalse;
941 break;
942 }
943 }
944 clone_offset+=length;
945 }
946 }
cristy9e0719b2011-12-29 03:45:45 +0000947 if ((cache_info->metacontent_extent != 0) ||
cristy4c08aed2011-07-01 19:47:50 +0000948 (clone_info->metacontent_extent != 0))
949 {
950 /*
951 Clone metacontent.
952 */
953 for (y=0; y < (ssize_t) cache_info->rows; y++)
954 {
955 for (x=0; x < (ssize_t) cache_info->columns; x++)
956 {
957 /*
958 Read a set of metacontent.
959 */
960 length=cache_info->metacontent_extent;
961 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000962 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy4c08aed2011-07-01 19:47:50 +0000963 else
964 {
cristyfd24a062012-01-02 14:46:34 +0000965 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000966 if ((MagickSizeType) count != length)
967 {
968 status=MagickFalse;
969 break;
970 }
971 }
972 cache_offset+=length;
973 if ((y < (ssize_t) clone_info->rows) &&
974 (x < (ssize_t) clone_info->columns))
975 {
976 /*
977 Write a set of metacontent.
978 */
979 length=clone_info->metacontent_extent;
980 if (clone_info->type != DiskCache)
981 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000982 p,length);
cristy4c08aed2011-07-01 19:47:50 +0000983 else
984 {
cristyfd24a062012-01-02 14:46:34 +0000985 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000986 if ((MagickSizeType) count != length)
987 {
988 status=MagickFalse;
989 break;
990 }
991 }
992 clone_offset+=length;
993 }
994 }
995 length=clone_info->metacontent_extent;
996 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
997 for ( ; x < (ssize_t) clone_info->columns; x++)
998 {
999 /*
cristy9e0719b2011-12-29 03:45:45 +00001000 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001001 */
1002 if (clone_info->type != DiskCache)
1003 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1004 blob,length);
1005 else
1006 {
cristy208b1002011-08-07 18:51:50 +00001007 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
cristy4c08aed2011-07-01 19:47:50 +00001008 if ((MagickSizeType) count != length)
1009 {
1010 status=MagickFalse;
1011 break;
1012 }
1013 }
1014 clone_offset+=length;
1015 }
1016 }
cristyac245f82012-05-05 17:13:57 +00001017 if (y < (ssize_t) clone_info->rows)
cristy4c08aed2011-07-01 19:47:50 +00001018 {
cristye04362f2012-04-23 15:33:05 +00001019 /*
1020 Set remaining rows as undefined.
1021 */
cristy888e6132012-04-23 19:54:54 +00001022 length=clone_info->metacontent_extent;
1023 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1024 for ( ; y < (ssize_t) clone_info->rows; y++)
cristye04362f2012-04-23 15:33:05 +00001025 {
cristy888e6132012-04-23 19:54:54 +00001026 for (x=0; x < (ssize_t) clone_info->columns; x++)
1027 {
1028 if (clone_info->type != DiskCache)
1029 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1030 blob,length);
1031 else
1032 {
1033 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1034 blob);
1035 if ((MagickSizeType) count != length)
1036 {
1037 status=MagickFalse;
1038 break;
1039 }
1040 }
1041 clone_offset+=length;
1042 }
cristye04362f2012-04-23 15:33:05 +00001043 }
cristy4c08aed2011-07-01 19:47:50 +00001044 }
cristy4c08aed2011-07-01 19:47:50 +00001045 }
1046 if (clone_info->type == DiskCache)
1047 (void) ClosePixelCacheOnDisk(clone_info);
1048 if (cache_info->type == DiskCache)
1049 (void) ClosePixelCacheOnDisk(cache_info);
1050 blob=(unsigned char *) RelinquishMagickMemory(blob);
1051 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001052}
1053
1054static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1055 CacheInfo *cache_info,ExceptionInfo *exception)
1056{
cristy3dfccb22011-12-28 21:47:20 +00001057 PixelChannelMap
1058 *p,
1059 *q;
1060
cristy5a7fbfb2010-11-06 16:10:59 +00001061 if (cache_info->type == PingCache)
1062 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001063 p=cache_info->channel_map;
1064 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001065 if ((cache_info->columns == clone_info->columns) &&
1066 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001067 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001068 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001069 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001070 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1071 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001072}
1073
1074/*
1075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076% %
1077% %
1078% %
1079+ C l o n e P i x e l C a c h e M e t h o d s %
1080% %
1081% %
1082% %
1083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084%
1085% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1086% another.
1087%
1088% The format of the ClonePixelCacheMethods() method is:
1089%
1090% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1091%
1092% A description of each parameter follows:
1093%
1094% o clone: Specifies a pointer to a Cache structure.
1095%
1096% o cache: the pixel cache.
1097%
1098*/
cristya6577ff2011-09-02 19:54:26 +00001099MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001100{
1101 CacheInfo
1102 *cache_info,
1103 *source_info;
1104
1105 assert(clone != (Cache) NULL);
1106 source_info=(CacheInfo *) clone;
1107 assert(source_info->signature == MagickSignature);
1108 if (source_info->debug != MagickFalse)
1109 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1110 source_info->filename);
1111 assert(cache != (Cache) NULL);
1112 cache_info=(CacheInfo *) cache;
1113 assert(cache_info->signature == MagickSignature);
1114 source_info->methods=cache_info->methods;
1115}
1116
1117/*
1118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119% %
1120% %
1121% %
1122+ D e s t r o y I m a g e P i x e l C a c h e %
1123% %
1124% %
1125% %
1126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127%
1128% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1129%
1130% The format of the DestroyImagePixelCache() method is:
1131%
1132% void DestroyImagePixelCache(Image *image)
1133%
1134% A description of each parameter follows:
1135%
1136% o image: the image.
1137%
1138*/
1139static void DestroyImagePixelCache(Image *image)
1140{
1141 assert(image != (Image *) NULL);
1142 assert(image->signature == MagickSignature);
1143 if (image->debug != MagickFalse)
1144 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1145 if (image->cache == (void *) NULL)
1146 return;
1147 image->cache=DestroyPixelCache(image->cache);
1148}
1149
1150/*
1151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152% %
1153% %
1154% %
1155+ D e s t r o y I m a g e P i x e l s %
1156% %
1157% %
1158% %
1159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160%
1161% DestroyImagePixels() deallocates memory associated with the pixel cache.
1162%
1163% The format of the DestroyImagePixels() method is:
1164%
1165% void DestroyImagePixels(Image *image)
1166%
1167% A description of each parameter follows:
1168%
1169% o image: the image.
1170%
1171*/
1172MagickExport void DestroyImagePixels(Image *image)
1173{
1174 CacheInfo
1175 *cache_info;
1176
1177 assert(image != (const Image *) NULL);
1178 assert(image->signature == MagickSignature);
1179 if (image->debug != MagickFalse)
1180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1181 assert(image->cache != (Cache) NULL);
1182 cache_info=(CacheInfo *) image->cache;
1183 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001184 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1185 {
1186 cache_info->methods.destroy_pixel_handler(image);
1187 return;
1188 }
cristy2036f5c2010-09-19 21:18:17 +00001189 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001190}
1191
1192/*
1193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1194% %
1195% %
1196% %
1197+ D e s t r o y P i x e l C a c h e %
1198% %
1199% %
1200% %
1201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202%
1203% DestroyPixelCache() deallocates memory associated with the pixel cache.
1204%
1205% The format of the DestroyPixelCache() method is:
1206%
1207% Cache DestroyPixelCache(Cache cache)
1208%
1209% A description of each parameter follows:
1210%
1211% o cache: the pixel cache.
1212%
1213*/
1214
1215static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1216{
1217 switch (cache_info->type)
1218 {
1219 case MemoryCache:
1220 {
1221 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001222 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001223 cache_info->pixels);
1224 else
cristy4c08aed2011-07-01 19:47:50 +00001225 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001226 (size_t) cache_info->length);
1227 RelinquishMagickResource(MemoryResource,cache_info->length);
1228 break;
1229 }
1230 case MapCache:
1231 {
cristy4c08aed2011-07-01 19:47:50 +00001232 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001233 cache_info->length);
1234 RelinquishMagickResource(MapResource,cache_info->length);
1235 }
1236 case DiskCache:
1237 {
1238 if (cache_info->file != -1)
1239 (void) ClosePixelCacheOnDisk(cache_info);
1240 RelinquishMagickResource(DiskResource,cache_info->length);
1241 break;
1242 }
1243 default:
1244 break;
1245 }
1246 cache_info->type=UndefinedCache;
1247 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001248 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001249}
1250
cristya6577ff2011-09-02 19:54:26 +00001251MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001252{
1253 CacheInfo
1254 *cache_info;
1255
cristy3ed852e2009-09-05 21:47:34 +00001256 assert(cache != (Cache) NULL);
1257 cache_info=(CacheInfo *) cache;
1258 assert(cache_info->signature == MagickSignature);
1259 if (cache_info->debug != MagickFalse)
1260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1261 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001262 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001263 cache_info->reference_count--;
1264 if (cache_info->reference_count != 0)
1265 {
cristyf84a1932010-01-03 18:00:18 +00001266 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001267 return((Cache) NULL);
1268 }
cristyf84a1932010-01-03 18:00:18 +00001269 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001270 if (cache_info->debug != MagickFalse)
1271 {
1272 char
1273 message[MaxTextExtent];
1274
cristyb51dff52011-05-19 16:55:47 +00001275 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001276 cache_info->filename);
1277 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1278 }
cristyc2e1bdd2009-09-10 23:43:34 +00001279 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1280 (cache_info->type != DiskCache)))
1281 RelinquishPixelCachePixels(cache_info);
1282 else
1283 {
1284 RelinquishPixelCachePixels(cache_info);
1285 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1286 }
cristy3ed852e2009-09-05 21:47:34 +00001287 *cache_info->cache_filename='\0';
1288 if (cache_info->nexus_info != (NexusInfo **) NULL)
1289 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1290 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001291 if (cache_info->random_info != (RandomInfo *) NULL)
1292 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001293 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1294 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1295 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1296 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001297 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001298 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001299 cache=(Cache) NULL;
1300 return(cache);
1301}
1302
1303/*
1304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305% %
1306% %
1307% %
1308+ D e s t r o y P i x e l C a c h e N e x u s %
1309% %
1310% %
1311% %
1312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313%
1314% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1315%
1316% The format of the DestroyPixelCacheNexus() method is:
1317%
1318% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001319% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001320%
1321% A description of each parameter follows:
1322%
1323% o nexus_info: the nexus to destroy.
1324%
1325% o number_threads: the number of nexus threads.
1326%
1327*/
1328
1329static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1330{
1331 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001332 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001333 else
1334 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001335 nexus_info->cache=(Quantum *) NULL;
1336 nexus_info->pixels=(Quantum *) NULL;
1337 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001338 nexus_info->length=0;
1339 nexus_info->mapped=MagickFalse;
1340}
1341
cristya6577ff2011-09-02 19:54:26 +00001342MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001343 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001344{
cristybb503372010-05-27 20:51:26 +00001345 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001346 i;
1347
1348 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001349 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001350 {
cristy4c08aed2011-07-01 19:47:50 +00001351 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001352 RelinquishCacheNexusPixels(nexus_info[i]);
1353 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001354 }
cristye5f87c82012-02-14 12:44:17 +00001355 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001356 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001357 return(nexus_info);
1358}
1359
1360/*
1361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362% %
1363% %
1364% %
cristy4c08aed2011-07-01 19:47:50 +00001365% 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 +00001366% %
1367% %
1368% %
1369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370%
cristy4c08aed2011-07-01 19:47:50 +00001371% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1372% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1373% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001374%
cristy4c08aed2011-07-01 19:47:50 +00001375% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001376%
cristy4c08aed2011-07-01 19:47:50 +00001377% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001378%
1379% A description of each parameter follows:
1380%
1381% o image: the image.
1382%
1383*/
cristy4c08aed2011-07-01 19:47:50 +00001384MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001385{
1386 CacheInfo
1387 *cache_info;
1388
cristy5c9e6f22010-09-17 17:31:01 +00001389 const int
1390 id = GetOpenMPThreadId();
1391
cristy4c08aed2011-07-01 19:47:50 +00001392 void
1393 *metacontent;
1394
cristye7cc7cf2010-09-21 13:26:47 +00001395 assert(image != (const Image *) NULL);
1396 assert(image->signature == MagickSignature);
1397 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001398 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001399 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001400 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1401 (GetAuthenticMetacontentFromHandler) NULL)
1402 {
1403 metacontent=cache_info->methods.
1404 get_authentic_metacontent_from_handler(image);
1405 return(metacontent);
1406 }
cristy6ebe97c2010-07-03 01:17:28 +00001407 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001408 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1409 cache_info->nexus_info[id]);
1410 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001411}
1412
1413/*
1414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415% %
1416% %
1417% %
cristy4c08aed2011-07-01 19:47:50 +00001418+ 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 +00001419% %
1420% %
1421% %
1422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423%
cristy4c08aed2011-07-01 19:47:50 +00001424% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1425% with the last call to QueueAuthenticPixelsCache() or
1426% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001427%
cristy4c08aed2011-07-01 19:47:50 +00001428% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001429%
cristy4c08aed2011-07-01 19:47:50 +00001430% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001431%
1432% A description of each parameter follows:
1433%
1434% o image: the image.
1435%
1436*/
cristy4c08aed2011-07-01 19:47:50 +00001437static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001438{
1439 CacheInfo
1440 *cache_info;
1441
cristy2036f5c2010-09-19 21:18:17 +00001442 const int
1443 id = GetOpenMPThreadId();
1444
cristy4c08aed2011-07-01 19:47:50 +00001445 void
1446 *metacontent;
1447
cristy3ed852e2009-09-05 21:47:34 +00001448 assert(image != (const Image *) NULL);
1449 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001450 assert(image->cache != (Cache) NULL);
1451 cache_info=(CacheInfo *) image->cache;
1452 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001453 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001454 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1455 cache_info->nexus_info[id]);
1456 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001457}
1458
1459/*
1460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1461% %
1462% %
1463% %
1464+ 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 %
1465% %
1466% %
1467% %
1468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1469%
1470% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1471% disk pixel cache as defined by the geometry parameters. A pointer to the
1472% pixels is returned if the pixels are transferred, otherwise a NULL is
1473% returned.
1474%
1475% The format of the GetAuthenticPixelCacheNexus() method is:
1476%
cristy4c08aed2011-07-01 19:47:50 +00001477% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001478% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001479% NexusInfo *nexus_info,ExceptionInfo *exception)
1480%
1481% A description of each parameter follows:
1482%
1483% o image: the image.
1484%
1485% o x,y,columns,rows: These values define the perimeter of a region of
1486% pixels.
1487%
1488% o nexus_info: the cache nexus to return.
1489%
1490% o exception: return any errors or warnings in this structure.
1491%
1492*/
1493
cristy7f69b802012-05-08 16:39:59 +00001494static inline MagickBooleanType IsPixelAuthentic(
cristyf1832792012-05-08 18:38:18 +00001495 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00001496{
cristy4c08aed2011-07-01 19:47:50 +00001497 MagickBooleanType
1498 status;
1499
cristy3ed852e2009-09-05 21:47:34 +00001500 MagickOffsetType
1501 offset;
1502
cristy73724512010-04-12 14:43:14 +00001503 if (cache_info->type == PingCache)
1504 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001505 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1506 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001507 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001508 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001509 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001510}
1511
cristya6577ff2011-09-02 19:54:26 +00001512MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001513 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001514 NexusInfo *nexus_info,ExceptionInfo *exception)
1515{
1516 CacheInfo
1517 *cache_info;
1518
cristy4c08aed2011-07-01 19:47:50 +00001519 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001520 *q;
cristy3ed852e2009-09-05 21:47:34 +00001521
1522 /*
1523 Transfer pixels from the cache.
1524 */
1525 assert(image != (Image *) NULL);
1526 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001527 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1528 exception);
cristyacd2ed22011-08-30 01:44:23 +00001529 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001530 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001531 cache_info=(CacheInfo *) image->cache;
1532 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001533 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001534 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001535 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001536 return((Quantum *) NULL);
1537 if (cache_info->metacontent_extent != 0)
1538 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1539 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001540 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001541}
1542
1543/*
1544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545% %
1546% %
1547% %
1548+ 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 %
1549% %
1550% %
1551% %
1552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553%
1554% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1555% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1556%
1557% The format of the GetAuthenticPixelsFromCache() method is:
1558%
cristy4c08aed2011-07-01 19:47:50 +00001559% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001560%
1561% A description of each parameter follows:
1562%
1563% o image: the image.
1564%
1565*/
cristy4c08aed2011-07-01 19:47:50 +00001566static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001567{
1568 CacheInfo
1569 *cache_info;
1570
cristy5c9e6f22010-09-17 17:31:01 +00001571 const int
1572 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001573
cristye7cc7cf2010-09-21 13:26:47 +00001574 assert(image != (const Image *) NULL);
1575 assert(image->signature == MagickSignature);
1576 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001577 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001578 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001579 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001580 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001581}
1582
1583/*
1584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585% %
1586% %
1587% %
1588% G e t A u t h e n t i c P i x e l Q u e u e %
1589% %
1590% %
1591% %
1592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593%
cristy4c08aed2011-07-01 19:47:50 +00001594% GetAuthenticPixelQueue() returns the authentic pixels associated
1595% corresponding with the last call to QueueAuthenticPixels() or
1596% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001597%
1598% The format of the GetAuthenticPixelQueue() method is:
1599%
cristy4c08aed2011-07-01 19:47:50 +00001600% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001601%
1602% A description of each parameter follows:
1603%
1604% o image: the image.
1605%
1606*/
cristy4c08aed2011-07-01 19:47:50 +00001607MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001608{
1609 CacheInfo
1610 *cache_info;
1611
cristy2036f5c2010-09-19 21:18:17 +00001612 const int
1613 id = GetOpenMPThreadId();
1614
cristy3ed852e2009-09-05 21:47:34 +00001615 assert(image != (const Image *) NULL);
1616 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001617 assert(image->cache != (Cache) NULL);
1618 cache_info=(CacheInfo *) image->cache;
1619 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001620 if (cache_info->methods.get_authentic_pixels_from_handler !=
1621 (GetAuthenticPixelsFromHandler) NULL)
1622 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001623 assert(id < (int) cache_info->number_threads);
1624 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001625}
1626
1627/*
1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629% %
1630% %
1631% %
1632% G e t A u t h e n t i c P i x e l s %
1633% %
1634% %
cristy4c08aed2011-07-01 19:47:50 +00001635% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001636%
1637% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001638% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001639% representing the region is returned, otherwise NULL is returned.
1640%
1641% The returned pointer may point to a temporary working copy of the pixels
1642% or it may point to the original pixels in memory. Performance is maximized
1643% if the selected region is part of one row, or one or more full rows, since
1644% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001645% if the image is in memory, or in a memory-mapped file. The returned pointer
1646% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001647%
1648% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001649% Quantum. If the image has corresponding metacontent,call
1650% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1651% meta-content corresponding to the region. Once the Quantum array has
1652% been updated, the changes must be saved back to the underlying image using
1653% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001654%
1655% The format of the GetAuthenticPixels() method is:
1656%
cristy4c08aed2011-07-01 19:47:50 +00001657% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001658% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001659% ExceptionInfo *exception)
1660%
1661% A description of each parameter follows:
1662%
1663% o image: the image.
1664%
1665% o x,y,columns,rows: These values define the perimeter of a region of
1666% pixels.
1667%
1668% o exception: return any errors or warnings in this structure.
1669%
1670*/
cristy4c08aed2011-07-01 19:47:50 +00001671MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001672 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001673 ExceptionInfo *exception)
1674{
1675 CacheInfo
1676 *cache_info;
1677
cristy2036f5c2010-09-19 21:18:17 +00001678 const int
1679 id = GetOpenMPThreadId();
1680
cristy4c08aed2011-07-01 19:47:50 +00001681 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001682 *q;
cristy4c08aed2011-07-01 19:47:50 +00001683
cristy3ed852e2009-09-05 21:47:34 +00001684 assert(image != (Image *) NULL);
1685 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001686 assert(image->cache != (Cache) NULL);
1687 cache_info=(CacheInfo *) image->cache;
1688 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001689 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001690 (GetAuthenticPixelsHandler) NULL)
1691 {
cristyacd2ed22011-08-30 01:44:23 +00001692 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1693 exception);
1694 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001695 }
cristy2036f5c2010-09-19 21:18:17 +00001696 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001697 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001698 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001699 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001700}
1701
1702/*
1703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1704% %
1705% %
1706% %
1707+ G e t A u t h e n t i c P i x e l s C a c h e %
1708% %
1709% %
1710% %
1711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1712%
1713% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1714% as defined by the geometry parameters. A pointer to the pixels is returned
1715% if the pixels are transferred, otherwise a NULL is returned.
1716%
1717% The format of the GetAuthenticPixelsCache() method is:
1718%
cristy4c08aed2011-07-01 19:47:50 +00001719% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001720% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001721% ExceptionInfo *exception)
1722%
1723% A description of each parameter follows:
1724%
1725% o image: the image.
1726%
1727% o x,y,columns,rows: These values define the perimeter of a region of
1728% pixels.
1729%
1730% o exception: return any errors or warnings in this structure.
1731%
1732*/
cristy4c08aed2011-07-01 19:47:50 +00001733static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001734 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001735 ExceptionInfo *exception)
1736{
1737 CacheInfo
1738 *cache_info;
1739
cristy5c9e6f22010-09-17 17:31:01 +00001740 const int
1741 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001742
cristy4c08aed2011-07-01 19:47:50 +00001743 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001744 *q;
cristy4c08aed2011-07-01 19:47:50 +00001745
cristye7cc7cf2010-09-21 13:26:47 +00001746 assert(image != (const Image *) NULL);
1747 assert(image->signature == MagickSignature);
1748 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001749 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001750 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001751 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001752 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001753 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001754 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001755 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001756 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001757}
1758
1759/*
1760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761% %
1762% %
1763% %
1764+ G e t I m a g e E x t e n t %
1765% %
1766% %
1767% %
1768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769%
cristy4c08aed2011-07-01 19:47:50 +00001770% GetImageExtent() returns the extent of the pixels associated corresponding
1771% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001772%
1773% The format of the GetImageExtent() method is:
1774%
1775% MagickSizeType GetImageExtent(const Image *image)
1776%
1777% A description of each parameter follows:
1778%
1779% o image: the image.
1780%
1781*/
1782MagickExport MagickSizeType GetImageExtent(const Image *image)
1783{
1784 CacheInfo
1785 *cache_info;
1786
cristy5c9e6f22010-09-17 17:31:01 +00001787 const int
1788 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001789
cristy3ed852e2009-09-05 21:47:34 +00001790 assert(image != (Image *) NULL);
1791 assert(image->signature == MagickSignature);
1792 if (image->debug != MagickFalse)
1793 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1794 assert(image->cache != (Cache) NULL);
1795 cache_info=(CacheInfo *) image->cache;
1796 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001797 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001798 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001799}
1800
1801/*
1802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1803% %
1804% %
1805% %
1806+ G e t I m a g e P i x e l C a c h e %
1807% %
1808% %
1809% %
1810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1811%
1812% GetImagePixelCache() ensures that there is only a single reference to the
1813% pixel cache to be modified, updating the provided cache pointer to point to
1814% a clone of the original pixel cache if necessary.
1815%
1816% The format of the GetImagePixelCache method is:
1817%
1818% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1819% ExceptionInfo *exception)
1820%
1821% A description of each parameter follows:
1822%
1823% o image: the image.
1824%
1825% o clone: any value other than MagickFalse clones the cache pixels.
1826%
1827% o exception: return any errors or warnings in this structure.
1828%
1829*/
cristyaf894d72011-08-06 23:03:10 +00001830
cristyf1832792012-05-08 18:38:18 +00001831static inline MagickBooleanType ValidatePixelCacheMorphology(
1832 const Image *restrict image)
cristy3ed852e2009-09-05 21:47:34 +00001833{
cristyf1832792012-05-08 18:38:18 +00001834 const CacheInfo
1835 *restrict cache_info;
cristy3ed852e2009-09-05 21:47:34 +00001836
cristyf1832792012-05-08 18:38:18 +00001837 const PixelChannelMap
1838 *restrict p,
1839 *restrict q;
cristy9e0719b2011-12-29 03:45:45 +00001840
cristy3ed852e2009-09-05 21:47:34 +00001841 /*
1842 Does the image match the pixel cache morphology?
1843 */
1844 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001845 p=image->channel_map;
1846 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001847 if ((image->storage_class != cache_info->storage_class) ||
1848 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001849 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001850 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001851 (image->columns != cache_info->columns) ||
1852 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001853 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001854 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001855 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristya90703b2012-05-06 18:59:26 +00001856 (cache_info->nexus_info == (NexusInfo **) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001857 return(MagickFalse);
1858 return(MagickTrue);
1859}
1860
cristycd01fae2011-08-06 23:52:42 +00001861static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1862 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001863{
1864 CacheInfo
1865 *cache_info;
1866
cristy3ed852e2009-09-05 21:47:34 +00001867 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001868 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001869 status;
1870
cristy50a10922010-02-15 18:35:25 +00001871 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001872 cpu_throttle = 0,
1873 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001874 time_limit = 0;
1875
cristy1ea34962010-07-01 19:49:21 +00001876 static time_t
cristy208b1002011-08-07 18:51:50 +00001877 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001878
cristyc4f9f132010-03-04 18:50:01 +00001879 status=MagickTrue;
1880 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001881 if (cpu_throttle == 0)
1882 {
1883 char
1884 *limit;
1885
1886 /*
1887 Set CPU throttle in milleseconds.
1888 */
1889 cpu_throttle=MagickResourceInfinity;
1890 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1891 if (limit == (char *) NULL)
1892 limit=GetPolicyValue("throttle");
1893 if (limit != (char *) NULL)
1894 {
1895 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1896 limit=DestroyString(limit);
1897 }
1898 }
1899 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1900 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001901 if (time_limit == 0)
1902 {
cristy6ebe97c2010-07-03 01:17:28 +00001903 /*
1904 Set the exire time in seconds.
1905 */
cristy1ea34962010-07-01 19:49:21 +00001906 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001907 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001908 }
1909 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001910 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001911 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001912 assert(image->cache != (Cache) NULL);
1913 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001914 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001915 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001916 {
cristyceb55ee2010-11-06 16:05:49 +00001917 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001918 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001919 {
cristyceb55ee2010-11-06 16:05:49 +00001920 Image
1921 clone_image;
1922
1923 CacheInfo
1924 *clone_info;
1925
1926 /*
1927 Clone pixel cache.
1928 */
1929 clone_image=(*image);
1930 clone_image.semaphore=AllocateSemaphoreInfo();
1931 clone_image.reference_count=1;
1932 clone_image.cache=ClonePixelCache(cache_info);
1933 clone_info=(CacheInfo *) clone_image.cache;
1934 status=OpenPixelCache(&clone_image,IOMode,exception);
1935 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001936 {
cristy5a7fbfb2010-11-06 16:10:59 +00001937 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001938 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001939 if (status != MagickFalse)
1940 {
cristy979bf772011-08-08 00:04:15 +00001941 if (cache_info->mode == ReadMode)
1942 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001943 destroy=MagickTrue;
1944 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001945 }
1946 }
cristyceb55ee2010-11-06 16:05:49 +00001947 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001948 }
cristyceb55ee2010-11-06 16:05:49 +00001949 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001950 }
cristy4320e0e2009-09-10 15:00:08 +00001951 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001952 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001953 if (status != MagickFalse)
1954 {
1955 /*
1956 Ensure the image matches the pixel cache morphology.
1957 */
1958 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001959 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001960 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001961 {
1962 status=OpenPixelCache(image,IOMode,exception);
1963 cache_info=(CacheInfo *) image->cache;
1964 if (cache_info->type == DiskCache)
1965 (void) ClosePixelCacheOnDisk(cache_info);
1966 }
cristy3ed852e2009-09-05 21:47:34 +00001967 }
cristyf84a1932010-01-03 18:00:18 +00001968 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001969 if (status == MagickFalse)
1970 return((Cache) NULL);
1971 return(image->cache);
1972}
1973
1974/*
1975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1976% %
1977% %
1978% %
1979% G e t O n e A u t h e n t i c P i x e l %
1980% %
1981% %
1982% %
1983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1984%
1985% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1986% location. The image background color is returned if an error occurs.
1987%
1988% The format of the GetOneAuthenticPixel() method is:
1989%
cristybb503372010-05-27 20:51:26 +00001990% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001991% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001992%
1993% A description of each parameter follows:
1994%
1995% o image: the image.
1996%
1997% o x,y: These values define the location of the pixel to return.
1998%
1999% o pixel: return a pixel at the specified (x,y) location.
2000%
2001% o exception: return any errors or warnings in this structure.
2002%
2003*/
cristyacbbb7c2010-06-30 18:56:48 +00002004MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002005 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002006{
2007 CacheInfo
2008 *cache_info;
2009
cristy4c08aed2011-07-01 19:47:50 +00002010 register Quantum
2011 *q;
cristy2036f5c2010-09-19 21:18:17 +00002012
cristy2ed42f62011-10-02 19:49:57 +00002013 register ssize_t
2014 i;
2015
cristy3ed852e2009-09-05 21:47:34 +00002016 assert(image != (Image *) NULL);
2017 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002018 assert(image->cache != (Cache) NULL);
2019 cache_info=(CacheInfo *) image->cache;
2020 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002021 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002022 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2023 (GetOneAuthenticPixelFromHandler) NULL)
2024 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2025 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002026 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2027 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002028 {
cristy9e0719b2011-12-29 03:45:45 +00002029 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2030 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2031 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2032 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2033 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002034 return(MagickFalse);
2035 }
2036 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2037 {
2038 PixelChannel
2039 channel;
2040
cristye2a912b2011-12-05 20:02:07 +00002041 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002042 pixel[channel]=q[i];
2043 }
cristy2036f5c2010-09-19 21:18:17 +00002044 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002045}
2046
2047/*
2048%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2049% %
2050% %
2051% %
2052+ 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 %
2053% %
2054% %
2055% %
2056%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2057%
2058% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2059% location. The image background color is returned if an error occurs.
2060%
2061% The format of the GetOneAuthenticPixelFromCache() method is:
2062%
2063% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002064% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002065% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002066%
2067% A description of each parameter follows:
2068%
2069% o image: the image.
2070%
2071% o x,y: These values define the location of the pixel to return.
2072%
2073% o pixel: return a pixel at the specified (x,y) location.
2074%
2075% o exception: return any errors or warnings in this structure.
2076%
2077*/
2078static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002079 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002080{
cristy098f78c2010-09-23 17:28:44 +00002081 CacheInfo
2082 *cache_info;
2083
2084 const int
2085 id = GetOpenMPThreadId();
2086
cristy4c08aed2011-07-01 19:47:50 +00002087 register Quantum
2088 *q;
cristy3ed852e2009-09-05 21:47:34 +00002089
cristy2ed42f62011-10-02 19:49:57 +00002090 register ssize_t
2091 i;
2092
cristy0158a4b2010-09-20 13:59:45 +00002093 assert(image != (const Image *) NULL);
2094 assert(image->signature == MagickSignature);
2095 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002096 cache_info=(CacheInfo *) image->cache;
2097 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002098 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002099 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002100 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2101 exception);
2102 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002103 {
cristy9e0719b2011-12-29 03:45:45 +00002104 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2105 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2106 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2107 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2108 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002109 return(MagickFalse);
2110 }
2111 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2112 {
2113 PixelChannel
2114 channel;
2115
cristye2a912b2011-12-05 20:02:07 +00002116 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002117 pixel[channel]=q[i];
2118 }
cristy3ed852e2009-09-05 21:47:34 +00002119 return(MagickTrue);
2120}
2121
2122/*
2123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2124% %
2125% %
2126% %
cristy3ed852e2009-09-05 21:47:34 +00002127% G e t O n e V i r t u a l P i x e l %
2128% %
2129% %
2130% %
2131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2132%
2133% GetOneVirtualPixel() returns a single virtual pixel at the specified
2134% (x,y) location. The image background color is returned if an error occurs.
2135% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2136%
2137% The format of the GetOneVirtualPixel() method is:
2138%
cristybb503372010-05-27 20:51:26 +00002139% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002140% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002141%
2142% A description of each parameter follows:
2143%
2144% o image: the image.
2145%
2146% o x,y: These values define the location of the pixel to return.
2147%
2148% o pixel: return a pixel at the specified (x,y) location.
2149%
2150% o exception: return any errors or warnings in this structure.
2151%
2152*/
2153MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002154 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002155{
cristy3ed852e2009-09-05 21:47:34 +00002156 CacheInfo
2157 *cache_info;
2158
cristy0158a4b2010-09-20 13:59:45 +00002159 const int
2160 id = GetOpenMPThreadId();
2161
cristy4c08aed2011-07-01 19:47:50 +00002162 const Quantum
2163 *p;
cristy2036f5c2010-09-19 21:18:17 +00002164
cristy2ed42f62011-10-02 19:49:57 +00002165 register ssize_t
2166 i;
2167
cristy3ed852e2009-09-05 21:47:34 +00002168 assert(image != (const Image *) NULL);
2169 assert(image->signature == MagickSignature);
2170 assert(image->cache != (Cache) NULL);
2171 cache_info=(CacheInfo *) image->cache;
2172 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002173 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002174 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2175 (GetOneVirtualPixelFromHandler) NULL)
2176 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2177 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002178 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002179 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002180 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002181 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002182 {
cristy9e0719b2011-12-29 03:45:45 +00002183 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2184 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2185 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2186 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2187 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002188 return(MagickFalse);
2189 }
2190 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2191 {
2192 PixelChannel
2193 channel;
2194
cristye2a912b2011-12-05 20:02:07 +00002195 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002196 pixel[channel]=p[i];
2197 }
cristy2036f5c2010-09-19 21:18:17 +00002198 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002199}
2200
2201/*
2202%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2203% %
2204% %
2205% %
2206+ 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 %
2207% %
2208% %
2209% %
2210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2211%
2212% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2213% specified (x,y) location. The image background color is returned if an
2214% error occurs.
2215%
2216% The format of the GetOneVirtualPixelFromCache() method is:
2217%
2218% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002219% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002220% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002221%
2222% A description of each parameter follows:
2223%
2224% o image: the image.
2225%
2226% o virtual_pixel_method: the virtual pixel method.
2227%
2228% o x,y: These values define the location of the pixel to return.
2229%
2230% o pixel: return a pixel at the specified (x,y) location.
2231%
2232% o exception: return any errors or warnings in this structure.
2233%
2234*/
2235static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002236 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002237 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002238{
cristy0158a4b2010-09-20 13:59:45 +00002239 CacheInfo
2240 *cache_info;
2241
2242 const int
2243 id = GetOpenMPThreadId();
2244
cristy4c08aed2011-07-01 19:47:50 +00002245 const Quantum
2246 *p;
cristy3ed852e2009-09-05 21:47:34 +00002247
cristy2ed42f62011-10-02 19:49:57 +00002248 register ssize_t
2249 i;
2250
cristye7cc7cf2010-09-21 13:26:47 +00002251 assert(image != (const Image *) NULL);
2252 assert(image->signature == MagickSignature);
2253 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002254 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002255 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002256 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002257 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002258 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002259 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002260 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002261 {
cristy9e0719b2011-12-29 03:45:45 +00002262 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2263 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2264 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2265 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2266 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002267 return(MagickFalse);
2268 }
2269 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2270 {
2271 PixelChannel
2272 channel;
2273
cristye2a912b2011-12-05 20:02:07 +00002274 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002275 pixel[channel]=p[i];
2276 }
cristy3ed852e2009-09-05 21:47:34 +00002277 return(MagickTrue);
2278}
2279
2280/*
2281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2282% %
2283% %
2284% %
cristy3aa93752011-12-18 15:54:24 +00002285% G e t O n e V i r t u a l P i x e l I n f o %
2286% %
2287% %
2288% %
2289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2290%
2291% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2292% location. The image background color is returned if an error occurs. If
2293% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2294%
2295% The format of the GetOneVirtualPixelInfo() method is:
2296%
2297% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2298% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2299% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2300%
2301% A description of each parameter follows:
2302%
2303% o image: the image.
2304%
2305% o virtual_pixel_method: the virtual pixel method.
2306%
2307% o x,y: these values define the location of the pixel to return.
2308%
2309% o pixel: return a pixel at the specified (x,y) location.
2310%
2311% o exception: return any errors or warnings in this structure.
2312%
2313*/
2314MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2315 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2316 PixelInfo *pixel,ExceptionInfo *exception)
2317{
2318 CacheInfo
2319 *cache_info;
2320
2321 const int
2322 id = GetOpenMPThreadId();
2323
2324 register const Quantum
2325 *p;
2326
2327 assert(image != (const Image *) NULL);
2328 assert(image->signature == MagickSignature);
2329 assert(image->cache != (Cache) NULL);
2330 cache_info=(CacheInfo *) image->cache;
2331 assert(cache_info->signature == MagickSignature);
2332 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002333 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2335 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002336 if (p == (const Quantum *) NULL)
2337 return(MagickFalse);
2338 GetPixelInfoPixel(image,p,pixel);
2339 return(MagickTrue);
2340}
2341
2342/*
2343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2344% %
2345% %
2346% %
cristy3ed852e2009-09-05 21:47:34 +00002347+ G e t P i x e l C a c h e C o l o r s p a c e %
2348% %
2349% %
2350% %
2351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352%
2353% GetPixelCacheColorspace() returns the class type of the pixel cache.
2354%
2355% The format of the GetPixelCacheColorspace() method is:
2356%
2357% Colorspace GetPixelCacheColorspace(Cache cache)
2358%
2359% A description of each parameter follows:
2360%
2361% o cache: the pixel cache.
2362%
2363*/
cristya6577ff2011-09-02 19:54:26 +00002364MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002365{
2366 CacheInfo
2367 *cache_info;
2368
2369 assert(cache != (Cache) NULL);
2370 cache_info=(CacheInfo *) cache;
2371 assert(cache_info->signature == MagickSignature);
2372 if (cache_info->debug != MagickFalse)
2373 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2374 cache_info->filename);
2375 return(cache_info->colorspace);
2376}
2377
2378/*
2379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380% %
2381% %
2382% %
2383+ G e t P i x e l C a c h e M e t h o d s %
2384% %
2385% %
2386% %
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388%
2389% GetPixelCacheMethods() initializes the CacheMethods structure.
2390%
2391% The format of the GetPixelCacheMethods() method is:
2392%
2393% void GetPixelCacheMethods(CacheMethods *cache_methods)
2394%
2395% A description of each parameter follows:
2396%
2397% o cache_methods: Specifies a pointer to a CacheMethods structure.
2398%
2399*/
cristya6577ff2011-09-02 19:54:26 +00002400MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002401{
2402 assert(cache_methods != (CacheMethods *) NULL);
2403 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2404 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2405 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002406 cache_methods->get_virtual_metacontent_from_handler=
2407 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002408 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2409 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002410 cache_methods->get_authentic_metacontent_from_handler=
2411 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002412 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2413 cache_methods->get_one_authentic_pixel_from_handler=
2414 GetOneAuthenticPixelFromCache;
2415 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2416 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2417 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2418}
2419
2420/*
2421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2422% %
2423% %
2424% %
2425+ G e t P i x e l C a c h e N e x u s E x t e n t %
2426% %
2427% %
2428% %
2429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2430%
cristy4c08aed2011-07-01 19:47:50 +00002431% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2432% corresponding with the last call to SetPixelCacheNexusPixels() or
2433% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002434%
2435% The format of the GetPixelCacheNexusExtent() method is:
2436%
2437% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2438% NexusInfo *nexus_info)
2439%
2440% A description of each parameter follows:
2441%
2442% o nexus_info: the nexus info.
2443%
2444*/
cristya6577ff2011-09-02 19:54:26 +00002445MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002446 NexusInfo *nexus_info)
2447{
2448 CacheInfo
2449 *cache_info;
2450
2451 MagickSizeType
2452 extent;
2453
cristy9f027d12011-09-21 01:17:17 +00002454 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002455 cache_info=(CacheInfo *) cache;
2456 assert(cache_info->signature == MagickSignature);
2457 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2458 if (extent == 0)
2459 return((MagickSizeType) cache_info->columns*cache_info->rows);
2460 return(extent);
2461}
2462
2463/*
2464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465% %
2466% %
2467% %
cristy4c08aed2011-07-01 19:47:50 +00002468+ 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 +00002469% %
2470% %
2471% %
2472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473%
cristy4c08aed2011-07-01 19:47:50 +00002474% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2475% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002476%
cristy4c08aed2011-07-01 19:47:50 +00002477% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002478%
cristy4c08aed2011-07-01 19:47:50 +00002479% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002480% NexusInfo *nexus_info)
2481%
2482% A description of each parameter follows:
2483%
2484% o cache: the pixel cache.
2485%
cristy4c08aed2011-07-01 19:47:50 +00002486% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002487%
2488*/
cristya6577ff2011-09-02 19:54:26 +00002489MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002490 NexusInfo *nexus_info)
2491{
2492 CacheInfo
2493 *cache_info;
2494
cristy9f027d12011-09-21 01:17:17 +00002495 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002496 cache_info=(CacheInfo *) cache;
2497 assert(cache_info->signature == MagickSignature);
2498 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002499 return((void *) NULL);
2500 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002501}
2502
2503/*
2504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2505% %
2506% %
2507% %
2508+ G e t P i x e l C a c h e N e x u s P i x e l s %
2509% %
2510% %
2511% %
2512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2513%
2514% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2515% cache nexus.
2516%
2517% The format of the GetPixelCacheNexusPixels() method is:
2518%
cristy4c08aed2011-07-01 19:47:50 +00002519% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002520% NexusInfo *nexus_info)
2521%
2522% A description of each parameter follows:
2523%
2524% o cache: the pixel cache.
2525%
2526% o nexus_info: the cache nexus to return the pixels.
2527%
2528*/
cristya6577ff2011-09-02 19:54:26 +00002529MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002530 NexusInfo *nexus_info)
2531{
2532 CacheInfo
2533 *cache_info;
2534
cristy9f027d12011-09-21 01:17:17 +00002535 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002536 cache_info=(CacheInfo *) cache;
2537 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002538 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002539 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002540 return(nexus_info->pixels);
2541}
2542
2543/*
2544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2545% %
2546% %
2547% %
cristy056ba772010-01-02 23:33:54 +00002548+ G e t P i x e l C a c h e P i x e l s %
2549% %
2550% %
2551% %
2552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2553%
2554% GetPixelCachePixels() returns the pixels associated with the specified image.
2555%
2556% The format of the GetPixelCachePixels() method is:
2557%
cristyf84a1932010-01-03 18:00:18 +00002558% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2559% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002560%
2561% A description of each parameter follows:
2562%
2563% o image: the image.
2564%
2565% o length: the pixel cache length.
2566%
cristyf84a1932010-01-03 18:00:18 +00002567% o exception: return any errors or warnings in this structure.
2568%
cristy056ba772010-01-02 23:33:54 +00002569*/
cristyd1dd6e42011-09-04 01:46:08 +00002570MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002571 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002572{
2573 CacheInfo
2574 *cache_info;
2575
2576 assert(image != (const Image *) NULL);
2577 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002578 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002579 assert(length != (MagickSizeType *) NULL);
2580 assert(exception != (ExceptionInfo *) NULL);
2581 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002582 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002583 assert(cache_info->signature == MagickSignature);
2584 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002585 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002586 return((void *) NULL);
2587 *length=cache_info->length;
2588 return((void *) cache_info->pixels);
2589}
2590
2591/*
2592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593% %
2594% %
2595% %
cristyb32b90a2009-09-07 21:45:48 +00002596+ 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 +00002597% %
2598% %
2599% %
2600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2601%
2602% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2603%
2604% The format of the GetPixelCacheStorageClass() method is:
2605%
2606% ClassType GetPixelCacheStorageClass(Cache cache)
2607%
2608% A description of each parameter follows:
2609%
2610% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2611%
2612% o cache: the pixel cache.
2613%
2614*/
cristya6577ff2011-09-02 19:54:26 +00002615MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002616{
2617 CacheInfo
2618 *cache_info;
2619
2620 assert(cache != (Cache) NULL);
2621 cache_info=(CacheInfo *) cache;
2622 assert(cache_info->signature == MagickSignature);
2623 if (cache_info->debug != MagickFalse)
2624 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2625 cache_info->filename);
2626 return(cache_info->storage_class);
2627}
2628
2629/*
2630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2631% %
2632% %
2633% %
cristyb32b90a2009-09-07 21:45:48 +00002634+ G e t P i x e l C a c h e T i l e S i z e %
2635% %
2636% %
2637% %
2638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2639%
2640% GetPixelCacheTileSize() returns the pixel cache tile size.
2641%
2642% The format of the GetPixelCacheTileSize() method is:
2643%
cristybb503372010-05-27 20:51:26 +00002644% void GetPixelCacheTileSize(const Image *image,size_t *width,
2645% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002646%
2647% A description of each parameter follows:
2648%
2649% o image: the image.
2650%
2651% o width: the optimize cache tile width in pixels.
2652%
2653% o height: the optimize cache tile height in pixels.
2654%
2655*/
cristya6577ff2011-09-02 19:54:26 +00002656MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002657 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002658{
cristy4c08aed2011-07-01 19:47:50 +00002659 CacheInfo
2660 *cache_info;
2661
cristyb32b90a2009-09-07 21:45:48 +00002662 assert(image != (Image *) NULL);
2663 assert(image->signature == MagickSignature);
2664 if (image->debug != MagickFalse)
2665 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002666 cache_info=(CacheInfo *) image->cache;
2667 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002668 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002669 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002670 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002671 *height=(*width);
2672}
2673
2674/*
2675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676% %
2677% %
2678% %
2679+ G e t P i x e l C a c h e T y p e %
2680% %
2681% %
2682% %
2683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2684%
2685% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2686%
2687% The format of the GetPixelCacheType() method is:
2688%
2689% CacheType GetPixelCacheType(const Image *image)
2690%
2691% A description of each parameter follows:
2692%
2693% o image: the image.
2694%
2695*/
cristya6577ff2011-09-02 19:54:26 +00002696MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002697{
2698 CacheInfo
2699 *cache_info;
2700
2701 assert(image != (Image *) NULL);
2702 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002703 assert(image->cache != (Cache) NULL);
2704 cache_info=(CacheInfo *) image->cache;
2705 assert(cache_info->signature == MagickSignature);
2706 return(cache_info->type);
2707}
2708
2709/*
2710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711% %
2712% %
2713% %
cristy3ed852e2009-09-05 21:47:34 +00002714+ 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 %
2715% %
2716% %
2717% %
2718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719%
2720% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2721% pixel cache. A virtual pixel is any pixel access that is outside the
2722% boundaries of the image cache.
2723%
2724% The format of the GetPixelCacheVirtualMethod() method is:
2725%
2726% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2727%
2728% A description of each parameter follows:
2729%
2730% o image: the image.
2731%
2732*/
cristyd1dd6e42011-09-04 01:46:08 +00002733MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002734{
2735 CacheInfo
2736 *cache_info;
2737
2738 assert(image != (Image *) NULL);
2739 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002740 assert(image->cache != (Cache) NULL);
2741 cache_info=(CacheInfo *) image->cache;
2742 assert(cache_info->signature == MagickSignature);
2743 return(cache_info->virtual_pixel_method);
2744}
2745
2746/*
2747%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2748% %
2749% %
2750% %
cristy4c08aed2011-07-01 19:47:50 +00002751+ 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 +00002752% %
2753% %
2754% %
2755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2756%
cristy4c08aed2011-07-01 19:47:50 +00002757% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2758% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002759%
cristy4c08aed2011-07-01 19:47:50 +00002760% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002761%
cristy4c08aed2011-07-01 19:47:50 +00002762% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002763%
2764% A description of each parameter follows:
2765%
2766% o image: the image.
2767%
2768*/
cristy4c08aed2011-07-01 19:47:50 +00002769static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002770{
2771 CacheInfo
2772 *cache_info;
2773
cristy5c9e6f22010-09-17 17:31:01 +00002774 const int
2775 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002776
cristy4c08aed2011-07-01 19:47:50 +00002777 const void
2778 *metacontent;
2779
cristye7cc7cf2010-09-21 13:26:47 +00002780 assert(image != (const Image *) NULL);
2781 assert(image->signature == MagickSignature);
2782 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002783 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002784 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002785 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002786 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2787 cache_info->nexus_info[id]);
2788 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002789}
2790
2791/*
2792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2793% %
2794% %
2795% %
cristy4c08aed2011-07-01 19:47:50 +00002796+ 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 +00002797% %
2798% %
2799% %
2800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2801%
cristy4c08aed2011-07-01 19:47:50 +00002802% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2803% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002804%
cristy4c08aed2011-07-01 19:47:50 +00002805% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002806%
cristy4c08aed2011-07-01 19:47:50 +00002807% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002808% NexusInfo *nexus_info)
2809%
2810% A description of each parameter follows:
2811%
2812% o cache: the pixel cache.
2813%
cristy4c08aed2011-07-01 19:47:50 +00002814% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002815%
2816*/
cristya6577ff2011-09-02 19:54:26 +00002817MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002818 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002819{
2820 CacheInfo
2821 *cache_info;
2822
cristye7cc7cf2010-09-21 13:26:47 +00002823 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002824 cache_info=(CacheInfo *) cache;
2825 assert(cache_info->signature == MagickSignature);
2826 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002827 return((void *) NULL);
2828 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002829}
2830
2831/*
2832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2833% %
2834% %
2835% %
cristy4c08aed2011-07-01 19:47:50 +00002836% 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 +00002837% %
2838% %
2839% %
2840%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2841%
cristy4c08aed2011-07-01 19:47:50 +00002842% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2843% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2844% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002845%
cristy4c08aed2011-07-01 19:47:50 +00002846% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002847%
cristy4c08aed2011-07-01 19:47:50 +00002848% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002849%
2850% A description of each parameter follows:
2851%
2852% o image: the image.
2853%
2854*/
cristy4c08aed2011-07-01 19:47:50 +00002855MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002856{
2857 CacheInfo
2858 *cache_info;
2859
cristy2036f5c2010-09-19 21:18:17 +00002860 const int
2861 id = GetOpenMPThreadId();
2862
cristy4c08aed2011-07-01 19:47:50 +00002863 const void
2864 *metacontent;
2865
cristy3ed852e2009-09-05 21:47:34 +00002866 assert(image != (const Image *) NULL);
2867 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002868 assert(image->cache != (Cache) NULL);
2869 cache_info=(CacheInfo *) image->cache;
2870 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002871 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2872 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2873 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002874 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002875 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2876 cache_info->nexus_info[id]);
2877 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002878}
2879
2880/*
2881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882% %
2883% %
2884% %
2885+ 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 %
2886% %
2887% %
2888% %
2889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2890%
2891% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2892% pixel cache as defined by the geometry parameters. A pointer to the pixels
2893% is returned if the pixels are transferred, otherwise a NULL is returned.
2894%
2895% The format of the GetVirtualPixelsFromNexus() method is:
2896%
cristy4c08aed2011-07-01 19:47:50 +00002897% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002898% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002899% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2900% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002901%
2902% A description of each parameter follows:
2903%
2904% o image: the image.
2905%
2906% o virtual_pixel_method: the virtual pixel method.
2907%
2908% o x,y,columns,rows: These values define the perimeter of a region of
2909% pixels.
2910%
2911% o nexus_info: the cache nexus to acquire.
2912%
2913% o exception: return any errors or warnings in this structure.
2914%
2915*/
2916
cristybb503372010-05-27 20:51:26 +00002917static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002918 DitherMatrix[64] =
2919 {
2920 0, 48, 12, 60, 3, 51, 15, 63,
2921 32, 16, 44, 28, 35, 19, 47, 31,
2922 8, 56, 4, 52, 11, 59, 7, 55,
2923 40, 24, 36, 20, 43, 27, 39, 23,
2924 2, 50, 14, 62, 1, 49, 13, 61,
2925 34, 18, 46, 30, 33, 17, 45, 29,
2926 10, 58, 6, 54, 9, 57, 5, 53,
2927 42, 26, 38, 22, 41, 25, 37, 21
2928 };
2929
cristybb503372010-05-27 20:51:26 +00002930static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002931{
cristybb503372010-05-27 20:51:26 +00002932 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002933 index;
2934
2935 index=x+DitherMatrix[x & 0x07]-32L;
2936 if (index < 0L)
2937 return(0L);
cristybb503372010-05-27 20:51:26 +00002938 if (index >= (ssize_t) columns)
2939 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002940 return(index);
2941}
2942
cristybb503372010-05-27 20:51:26 +00002943static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002944{
cristybb503372010-05-27 20:51:26 +00002945 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002946 index;
2947
2948 index=y+DitherMatrix[y & 0x07]-32L;
2949 if (index < 0L)
2950 return(0L);
cristybb503372010-05-27 20:51:26 +00002951 if (index >= (ssize_t) rows)
2952 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002953 return(index);
2954}
2955
cristybb503372010-05-27 20:51:26 +00002956static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002957{
2958 if (x < 0L)
2959 return(0L);
cristybb503372010-05-27 20:51:26 +00002960 if (x >= (ssize_t) columns)
2961 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002962 return(x);
2963}
2964
cristybb503372010-05-27 20:51:26 +00002965static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002966{
2967 if (y < 0L)
2968 return(0L);
cristybb503372010-05-27 20:51:26 +00002969 if (y >= (ssize_t) rows)
2970 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002971 return(y);
2972}
2973
cristybb503372010-05-27 20:51:26 +00002974static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002975{
cristybb503372010-05-27 20:51:26 +00002976 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002977}
2978
cristybb503372010-05-27 20:51:26 +00002979static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002980{
cristybb503372010-05-27 20:51:26 +00002981 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002982}
2983
cristybb503372010-05-27 20:51:26 +00002984static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2985 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002986{
2987 MagickModulo
2988 modulo;
2989
cristy6162bb42011-07-18 11:34:09 +00002990 /*
2991 Compute the remainder of dividing offset by extent. It returns not only
2992 the quotient (tile the offset falls in) but also the positive remainer
2993 within that tile such that 0 <= remainder < extent. This method is
2994 essentially a ldiv() using a floored modulo division rather than the
2995 normal default truncated modulo division.
2996 */
cristybb503372010-05-27 20:51:26 +00002997 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002998 if (offset < 0L)
2999 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003000 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003001 return(modulo);
3002}
3003
cristya6577ff2011-09-02 19:54:26 +00003004MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003005 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3006 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003007 ExceptionInfo *exception)
3008{
3009 CacheInfo
3010 *cache_info;
3011
3012 MagickOffsetType
3013 offset;
3014
3015 MagickSizeType
3016 length,
3017 number_pixels;
3018
3019 NexusInfo
3020 **virtual_nexus;
3021
cristy4c08aed2011-07-01 19:47:50 +00003022 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003023 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003024 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003025
3026 RectangleInfo
3027 region;
3028
cristy4c08aed2011-07-01 19:47:50 +00003029 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003030 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003031
cristy4c08aed2011-07-01 19:47:50 +00003032 register const void
3033 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003034
cristy4c08aed2011-07-01 19:47:50 +00003035 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003036 *restrict q;
3037
cristybb503372010-05-27 20:51:26 +00003038 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003039 i,
3040 u;
cristy3ed852e2009-09-05 21:47:34 +00003041
cristy4c08aed2011-07-01 19:47:50 +00003042 register unsigned char
3043 *restrict s;
3044
cristy105ba3c2011-07-18 02:28:38 +00003045 ssize_t
3046 v;
3047
cristy4c08aed2011-07-01 19:47:50 +00003048 void
cristy105ba3c2011-07-18 02:28:38 +00003049 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003050
cristy3ed852e2009-09-05 21:47:34 +00003051 /*
3052 Acquire pixels.
3053 */
cristye7cc7cf2010-09-21 13:26:47 +00003054 assert(image != (const Image *) NULL);
3055 assert(image->signature == MagickSignature);
3056 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003057 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003058 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003059 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003060 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003061 region.x=x;
3062 region.y=y;
3063 region.width=columns;
3064 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00003065 pixels=SetPixelCacheNexusPixels(image,ReadMode,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003066 if (pixels == (Quantum *) NULL)
3067 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003068 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003069 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3070 nexus_info->region.x;
3071 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3072 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003073 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3074 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003075 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3076 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003077 {
3078 MagickBooleanType
3079 status;
3080
3081 /*
3082 Pixel request is inside cache extents.
3083 */
cristy4c08aed2011-07-01 19:47:50 +00003084 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003085 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003086 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3087 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003088 return((const Quantum *) NULL);
3089 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003090 {
cristy4c08aed2011-07-01 19:47:50 +00003091 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003092 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003093 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003094 }
cristyacd2ed22011-08-30 01:44:23 +00003095 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003096 }
3097 /*
3098 Pixel request is outside cache extents.
3099 */
cristy4c08aed2011-07-01 19:47:50 +00003100 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003101 virtual_nexus=AcquirePixelCacheNexus(1);
3102 if (virtual_nexus == (NexusInfo **) NULL)
3103 {
cristy4c08aed2011-07-01 19:47:50 +00003104 if (virtual_nexus != (NexusInfo **) NULL)
3105 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003106 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003107 "UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003108 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003109 }
cristy105ba3c2011-07-18 02:28:38 +00003110 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3111 sizeof(*virtual_pixel));
3112 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003113 switch (virtual_pixel_method)
3114 {
cristy4c08aed2011-07-01 19:47:50 +00003115 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003116 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003117 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003118 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003119 case MaskVirtualPixelMethod:
3120 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003121 case EdgeVirtualPixelMethod:
3122 case CheckerTileVirtualPixelMethod:
3123 case HorizontalTileVirtualPixelMethod:
3124 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003125 {
cristy4c08aed2011-07-01 19:47:50 +00003126 if (cache_info->metacontent_extent != 0)
3127 {
cristy6162bb42011-07-18 11:34:09 +00003128 /*
3129 Acquire a metacontent buffer.
3130 */
cristya64b85d2011-09-14 01:02:31 +00003131 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003132 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003133 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003134 {
cristy4c08aed2011-07-01 19:47:50 +00003135 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3136 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00003137 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003138 return((const Quantum *) NULL);
3139 }
cristy105ba3c2011-07-18 02:28:38 +00003140 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003141 cache_info->metacontent_extent);
3142 }
3143 switch (virtual_pixel_method)
3144 {
3145 case BlackVirtualPixelMethod:
3146 {
cristy30301712011-07-18 15:06:51 +00003147 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3148 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003149 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3150 break;
3151 }
3152 case GrayVirtualPixelMethod:
3153 {
cristy30301712011-07-18 15:06:51 +00003154 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003155 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3156 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003157 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3158 break;
3159 }
3160 case TransparentVirtualPixelMethod:
3161 {
cristy30301712011-07-18 15:06:51 +00003162 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3163 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003164 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3165 break;
3166 }
3167 case MaskVirtualPixelMethod:
3168 case WhiteVirtualPixelMethod:
3169 {
cristy30301712011-07-18 15:06:51 +00003170 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3171 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003172 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3173 break;
3174 }
3175 default:
3176 {
cristy9e0719b2011-12-29 03:45:45 +00003177 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3178 virtual_pixel);
3179 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3180 virtual_pixel);
3181 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3182 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003183 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3184 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003185 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3186 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003187 break;
3188 }
3189 }
cristy3ed852e2009-09-05 21:47:34 +00003190 break;
3191 }
3192 default:
cristy3ed852e2009-09-05 21:47:34 +00003193 break;
cristy3ed852e2009-09-05 21:47:34 +00003194 }
cristybb503372010-05-27 20:51:26 +00003195 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003196 {
cristybb503372010-05-27 20:51:26 +00003197 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003198 {
3199 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003200 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003201 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3202 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003203 {
3204 MagickModulo
3205 x_modulo,
3206 y_modulo;
3207
3208 /*
3209 Transfer a single pixel.
3210 */
3211 length=(MagickSizeType) 1;
3212 switch (virtual_pixel_method)
3213 {
cristy3ed852e2009-09-05 21:47:34 +00003214 default:
3215 {
3216 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003217 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003218 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003219 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003220 break;
3221 }
3222 case RandomVirtualPixelMethod:
3223 {
3224 if (cache_info->random_info == (RandomInfo *) NULL)
3225 cache_info->random_info=AcquireRandomInfo();
3226 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003227 RandomX(cache_info->random_info,cache_info->columns),
3228 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003229 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003230 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003231 break;
3232 }
3233 case DitherVirtualPixelMethod:
3234 {
3235 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003236 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003237 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003238 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003239 break;
3240 }
3241 case TileVirtualPixelMethod:
3242 {
3243 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3244 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3245 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003246 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003247 exception);
cristy4c08aed2011-07-01 19:47:50 +00003248 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003249 break;
3250 }
3251 case MirrorVirtualPixelMethod:
3252 {
3253 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3254 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003255 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003256 x_modulo.remainder-1L;
3257 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3258 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003259 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003260 y_modulo.remainder-1L;
3261 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003262 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003263 exception);
cristy4c08aed2011-07-01 19:47:50 +00003264 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003265 break;
3266 }
3267 case HorizontalTileEdgeVirtualPixelMethod:
3268 {
3269 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3270 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003271 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003272 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003273 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003274 break;
3275 }
3276 case VerticalTileEdgeVirtualPixelMethod:
3277 {
3278 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3279 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003280 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003281 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003282 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3283 break;
3284 }
3285 case BackgroundVirtualPixelMethod:
3286 case BlackVirtualPixelMethod:
3287 case GrayVirtualPixelMethod:
3288 case TransparentVirtualPixelMethod:
3289 case MaskVirtualPixelMethod:
3290 case WhiteVirtualPixelMethod:
3291 {
3292 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003293 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003294 break;
3295 }
3296 case EdgeVirtualPixelMethod:
3297 case CheckerTileVirtualPixelMethod:
3298 {
3299 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3300 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3301 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3302 {
3303 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003304 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003305 break;
3306 }
3307 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3308 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3309 exception);
3310 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3311 break;
3312 }
3313 case HorizontalTileVirtualPixelMethod:
3314 {
3315 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3316 {
3317 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003318 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003319 break;
3320 }
3321 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3322 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3323 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3324 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3325 exception);
3326 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3327 break;
3328 }
3329 case VerticalTileVirtualPixelMethod:
3330 {
3331 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3332 {
3333 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003334 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003335 break;
3336 }
3337 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3338 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3339 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3340 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3341 exception);
3342 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003343 break;
3344 }
3345 }
cristy4c08aed2011-07-01 19:47:50 +00003346 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003347 break;
cristyed231572011-07-14 02:18:59 +00003348 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003349 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003350 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003351 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003352 {
3353 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3354 s+=cache_info->metacontent_extent;
3355 }
cristy3ed852e2009-09-05 21:47:34 +00003356 continue;
3357 }
3358 /*
3359 Transfer a run of pixels.
3360 */
cristy4c08aed2011-07-01 19:47:50 +00003361 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3362 length,1UL,*virtual_nexus,exception);
3363 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003364 break;
cristy4c08aed2011-07-01 19:47:50 +00003365 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003366 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3367 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003368 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003369 {
cristy4c08aed2011-07-01 19:47:50 +00003370 (void) memcpy(s,r,(size_t) length);
3371 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003372 }
3373 }
3374 }
cristy4c08aed2011-07-01 19:47:50 +00003375 /*
3376 Free resources.
3377 */
cristy105ba3c2011-07-18 02:28:38 +00003378 if (virtual_metacontent != (void *) NULL)
3379 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003380 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3381 return(pixels);
3382}
3383
3384/*
3385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3386% %
3387% %
3388% %
3389+ G e t V i r t u a l P i x e l C a c h e %
3390% %
3391% %
3392% %
3393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3394%
3395% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3396% cache as defined by the geometry parameters. A pointer to the pixels
3397% is returned if the pixels are transferred, otherwise a NULL is returned.
3398%
3399% The format of the GetVirtualPixelCache() method is:
3400%
cristy4c08aed2011-07-01 19:47:50 +00003401% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003402% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3403% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003404% ExceptionInfo *exception)
3405%
3406% A description of each parameter follows:
3407%
3408% o image: the image.
3409%
3410% o virtual_pixel_method: the virtual pixel method.
3411%
3412% o x,y,columns,rows: These values define the perimeter of a region of
3413% pixels.
3414%
3415% o exception: return any errors or warnings in this structure.
3416%
3417*/
cristy4c08aed2011-07-01 19:47:50 +00003418static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003419 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3420 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003421{
3422 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003423 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003424
cristy5c9e6f22010-09-17 17:31:01 +00003425 const int
3426 id = GetOpenMPThreadId();
3427
cristy4c08aed2011-07-01 19:47:50 +00003428 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003429 *p;
cristy4c08aed2011-07-01 19:47:50 +00003430
cristye7cc7cf2010-09-21 13:26:47 +00003431 assert(image != (const Image *) NULL);
3432 assert(image->signature == MagickSignature);
3433 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003434 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003435 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003436 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003437 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003438 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003439 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003440}
3441
3442/*
3443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3444% %
3445% %
3446% %
3447% G e t V i r t u a l P i x e l Q u e u e %
3448% %
3449% %
3450% %
3451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3452%
cristy4c08aed2011-07-01 19:47:50 +00003453% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3454% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003455%
3456% The format of the GetVirtualPixelQueue() method is:
3457%
cristy4c08aed2011-07-01 19:47:50 +00003458% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003459%
3460% A description of each parameter follows:
3461%
3462% o image: the image.
3463%
3464*/
cristy4c08aed2011-07-01 19:47:50 +00003465MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003466{
3467 CacheInfo
3468 *cache_info;
3469
cristy2036f5c2010-09-19 21:18:17 +00003470 const int
3471 id = GetOpenMPThreadId();
3472
cristy3ed852e2009-09-05 21:47:34 +00003473 assert(image != (const Image *) NULL);
3474 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003475 assert(image->cache != (Cache) NULL);
3476 cache_info=(CacheInfo *) image->cache;
3477 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003478 if (cache_info->methods.get_virtual_pixels_handler !=
3479 (GetVirtualPixelsHandler) NULL)
3480 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003481 assert(id < (int) cache_info->number_threads);
3482 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003483}
3484
3485/*
3486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3487% %
3488% %
3489% %
3490% G e t V i r t u a l P i x e l s %
3491% %
3492% %
3493% %
3494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3495%
3496% GetVirtualPixels() returns an immutable pixel region. If the
3497% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003498% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003499% copy of the pixels or it may point to the original pixels in memory.
3500% Performance is maximized if the selected region is part of one row, or one
3501% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003502% (without a copy) if the image is in memory, or in a memory-mapped file. The
3503% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003504%
3505% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003506% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3507% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3508% access the meta-content (of type void) corresponding to the the
3509% region.
cristy3ed852e2009-09-05 21:47:34 +00003510%
3511% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3512%
3513% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3514% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3515% GetCacheViewAuthenticPixels() instead.
3516%
3517% The format of the GetVirtualPixels() method is:
3518%
cristy4c08aed2011-07-01 19:47:50 +00003519% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003520% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003521% ExceptionInfo *exception)
3522%
3523% A description of each parameter follows:
3524%
3525% o image: the image.
3526%
3527% o x,y,columns,rows: These values define the perimeter of a region of
3528% pixels.
3529%
3530% o exception: return any errors or warnings in this structure.
3531%
3532*/
cristy4c08aed2011-07-01 19:47:50 +00003533MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003534 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3535 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003536{
3537 CacheInfo
3538 *cache_info;
3539
cristy2036f5c2010-09-19 21:18:17 +00003540 const int
3541 id = GetOpenMPThreadId();
3542
cristy4c08aed2011-07-01 19:47:50 +00003543 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003544 *p;
cristy4c08aed2011-07-01 19:47:50 +00003545
cristy3ed852e2009-09-05 21:47:34 +00003546 assert(image != (const Image *) NULL);
3547 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003548 assert(image->cache != (Cache) NULL);
3549 cache_info=(CacheInfo *) image->cache;
3550 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003551 if (cache_info->methods.get_virtual_pixel_handler !=
3552 (GetVirtualPixelHandler) NULL)
3553 return(cache_info->methods.get_virtual_pixel_handler(image,
3554 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003555 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003556 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003557 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003558 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003559}
3560
3561/*
3562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3563% %
3564% %
3565% %
3566+ 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 %
3567% %
3568% %
3569% %
3570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3571%
cristy4c08aed2011-07-01 19:47:50 +00003572% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3573% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003574%
3575% The format of the GetVirtualPixelsCache() method is:
3576%
cristy4c08aed2011-07-01 19:47:50 +00003577% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003578%
3579% A description of each parameter follows:
3580%
3581% o image: the image.
3582%
3583*/
cristy4c08aed2011-07-01 19:47:50 +00003584static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003585{
3586 CacheInfo
3587 *cache_info;
3588
cristy5c9e6f22010-09-17 17:31:01 +00003589 const int
3590 id = GetOpenMPThreadId();
3591
cristye7cc7cf2010-09-21 13:26:47 +00003592 assert(image != (const Image *) NULL);
3593 assert(image->signature == MagickSignature);
3594 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003595 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003596 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003597 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003598 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003599}
3600
3601/*
3602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3603% %
3604% %
3605% %
3606+ G e t V i r t u a l P i x e l s N e x u s %
3607% %
3608% %
3609% %
3610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3611%
3612% GetVirtualPixelsNexus() returns the pixels associated with the specified
3613% cache nexus.
3614%
3615% The format of the GetVirtualPixelsNexus() method is:
3616%
cristy4c08aed2011-07-01 19:47:50 +00003617% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003618% NexusInfo *nexus_info)
3619%
3620% A description of each parameter follows:
3621%
3622% o cache: the pixel cache.
3623%
3624% o nexus_info: the cache nexus to return the colormap pixels.
3625%
3626*/
cristya6577ff2011-09-02 19:54:26 +00003627MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003628 NexusInfo *nexus_info)
3629{
3630 CacheInfo
3631 *cache_info;
3632
cristye7cc7cf2010-09-21 13:26:47 +00003633 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003634 cache_info=(CacheInfo *) cache;
3635 assert(cache_info->signature == MagickSignature);
3636 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003637 return((Quantum *) NULL);
3638 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003639}
3640
3641/*
3642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3643% %
3644% %
3645% %
cristy3ed852e2009-09-05 21:47:34 +00003646+ O p e n P i x e l C a c h e %
3647% %
3648% %
3649% %
3650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3651%
3652% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3653% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003654% metacontent, and memory mapping the cache if it is disk based. The cache
3655% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003656%
3657% The format of the OpenPixelCache() method is:
3658%
3659% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3660% ExceptionInfo *exception)
3661%
3662% A description of each parameter follows:
3663%
3664% o image: the image.
3665%
3666% o mode: ReadMode, WriteMode, or IOMode.
3667%
3668% o exception: return any errors or warnings in this structure.
3669%
3670*/
3671
cristyd43a46b2010-01-21 02:13:41 +00003672static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003673{
3674 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003675 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003676 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003677 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003678 {
3679 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003680 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003681 cache_info->length);
3682 }
3683}
3684
3685static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3686{
3687 CacheInfo
3688 *cache_info;
3689
3690 MagickOffsetType
3691 count,
3692 extent,
3693 offset;
3694
3695 cache_info=(CacheInfo *) image->cache;
3696 if (image->debug != MagickFalse)
3697 {
3698 char
3699 format[MaxTextExtent],
3700 message[MaxTextExtent];
3701
cristyb9080c92009-12-01 20:13:26 +00003702 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003703 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003704 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003705 cache_info->cache_filename,cache_info->file,format);
3706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3707 }
3708 if (length != (MagickSizeType) ((MagickOffsetType) length))
3709 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003710 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003711 if (extent < 0)
3712 return(MagickFalse);
3713 if ((MagickSizeType) extent >= length)
3714 return(MagickTrue);
3715 offset=(MagickOffsetType) length-1;
3716 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3717 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3718}
3719
3720static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3721 ExceptionInfo *exception)
3722{
cristy3ed852e2009-09-05 21:47:34 +00003723 CacheInfo
3724 *cache_info,
3725 source_info;
3726
cristyf3a6a9d2010-11-07 21:02:56 +00003727 char
3728 format[MaxTextExtent],
3729 message[MaxTextExtent];
3730
cristy4c08aed2011-07-01 19:47:50 +00003731 MagickBooleanType
3732 status;
3733
cristy3ed852e2009-09-05 21:47:34 +00003734 MagickSizeType
3735 length,
3736 number_pixels;
3737
cristy3ed852e2009-09-05 21:47:34 +00003738 size_t
cristye076a6e2010-08-15 19:59:43 +00003739 columns,
cristy3ed852e2009-09-05 21:47:34 +00003740 packet_size;
3741
cristye7cc7cf2010-09-21 13:26:47 +00003742 assert(image != (const Image *) NULL);
3743 assert(image->signature == MagickSignature);
3744 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003745 if (image->debug != MagickFalse)
3746 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3747 if ((image->columns == 0) || (image->rows == 0))
3748 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3749 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003750 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003751 source_info=(*cache_info);
3752 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003753 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003754 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003755 cache_info->storage_class=image->storage_class;
3756 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003757 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003758 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003759 cache_info->rows=image->rows;
3760 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003761 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003762 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003763 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3764 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003765 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003766 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003767 if (image->ping != MagickFalse)
3768 {
cristy73724512010-04-12 14:43:14 +00003769 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003770 cache_info->pixels=(Quantum *) NULL;
3771 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003772 cache_info->length=0;
3773 return(MagickTrue);
3774 }
cristy3ed852e2009-09-05 21:47:34 +00003775 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003776 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003777 if (image->metacontent_extent != 0)
3778 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003779 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003780 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003781 if (cache_info->columns != columns)
3782 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3783 image->filename);
3784 cache_info->length=length;
3785 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003786 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003787 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003788 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3789 {
3790 status=AcquireMagickResource(MemoryResource,cache_info->length);
3791 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3792 (cache_info->type == MemoryCache))
3793 {
cristyd43a46b2010-01-21 02:13:41 +00003794 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003795 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003796 cache_info->pixels=source_info.pixels;
3797 else
3798 {
3799 /*
3800 Create memory pixel cache.
3801 */
cristy4c08aed2011-07-01 19:47:50 +00003802 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003803 if (image->debug != MagickFalse)
3804 {
cristy32cacff2011-12-31 03:36:27 +00003805 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003806 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003807 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3808 cache_info->filename,cache_info->mapped != MagickFalse ?
3809 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003810 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003811 format);
cristy3ed852e2009-09-05 21:47:34 +00003812 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3813 message);
3814 }
cristy3ed852e2009-09-05 21:47:34 +00003815 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003816 cache_info->metacontent=(void *) NULL;
3817 if (cache_info->metacontent_extent != 0)
3818 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003819 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003820 if ((source_info.storage_class != UndefinedClass) &&
3821 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003822 {
cristy4c08aed2011-07-01 19:47:50 +00003823 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003824 exception);
3825 RelinquishPixelCachePixels(&source_info);
3826 }
cristy4c08aed2011-07-01 19:47:50 +00003827 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003828 }
3829 }
3830 RelinquishMagickResource(MemoryResource,cache_info->length);
3831 }
3832 /*
3833 Create pixel cache on disk.
3834 */
3835 status=AcquireMagickResource(DiskResource,cache_info->length);
3836 if (status == MagickFalse)
3837 {
3838 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00003839 "CacheResourcesExhausted","'%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00003840 return(MagickFalse);
3841 }
cristy413f1302012-01-01 17:48:27 +00003842 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3843 {
3844 (void) ClosePixelCacheOnDisk(cache_info);
3845 *cache_info->cache_filename='\0';
3846 }
cristy3ed852e2009-09-05 21:47:34 +00003847 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3848 {
3849 RelinquishMagickResource(DiskResource,cache_info->length);
3850 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3851 image->filename);
3852 return(MagickFalse);
3853 }
3854 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3855 cache_info->length);
3856 if (status == MagickFalse)
3857 {
3858 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3859 image->filename);
3860 return(MagickFalse);
3861 }
cristyed231572011-07-14 02:18:59 +00003862 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003863 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003864 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003865 cache_info->type=DiskCache;
3866 else
3867 {
3868 status=AcquireMagickResource(MapResource,cache_info->length);
3869 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3870 (cache_info->type != MemoryCache))
3871 cache_info->type=DiskCache;
3872 else
3873 {
cristy4c08aed2011-07-01 19:47:50 +00003874 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003875 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003876 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003877 {
cristy3ed852e2009-09-05 21:47:34 +00003878 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003879 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003880 }
3881 else
3882 {
3883 /*
3884 Create file-backed memory-mapped pixel cache.
3885 */
cristy4c08aed2011-07-01 19:47:50 +00003886 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003887 (void) ClosePixelCacheOnDisk(cache_info);
3888 cache_info->type=MapCache;
3889 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003890 cache_info->metacontent=(void *) NULL;
3891 if (cache_info->metacontent_extent != 0)
3892 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003893 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003894 if ((source_info.storage_class != UndefinedClass) &&
3895 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003896 {
3897 status=ClonePixelCachePixels(cache_info,&source_info,
3898 exception);
3899 RelinquishPixelCachePixels(&source_info);
3900 }
3901 if (image->debug != MagickFalse)
3902 {
cristy413f1302012-01-01 17:48:27 +00003903 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003904 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003905 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003906 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003907 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003908 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003909 format);
cristy3ed852e2009-09-05 21:47:34 +00003910 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3911 message);
3912 }
cristy4c08aed2011-07-01 19:47:50 +00003913 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003914 }
3915 }
3916 RelinquishMagickResource(MapResource,cache_info->length);
3917 }
cristy4c08aed2011-07-01 19:47:50 +00003918 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003919 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003920 {
3921 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3922 RelinquishPixelCachePixels(&source_info);
3923 }
3924 if (image->debug != MagickFalse)
3925 {
cristyb9080c92009-12-01 20:13:26 +00003926 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003927 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003928 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003929 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003930 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003931 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003932 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3933 }
cristy4c08aed2011-07-01 19:47:50 +00003934 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003935}
3936
3937/*
3938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3939% %
3940% %
3941% %
3942+ P e r s i s t P i x e l C a c h e %
3943% %
3944% %
3945% %
3946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3947%
3948% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3949% persistent pixel cache is one that resides on disk and is not destroyed
3950% when the program exits.
3951%
3952% The format of the PersistPixelCache() method is:
3953%
3954% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3955% const MagickBooleanType attach,MagickOffsetType *offset,
3956% ExceptionInfo *exception)
3957%
3958% A description of each parameter follows:
3959%
3960% o image: the image.
3961%
3962% o filename: the persistent pixel cache filename.
3963%
cristyf3a6a9d2010-11-07 21:02:56 +00003964% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003965%
cristy3ed852e2009-09-05 21:47:34 +00003966% o initialize: A value other than zero initializes the persistent pixel
3967% cache.
3968%
3969% o offset: the offset in the persistent cache to store pixels.
3970%
3971% o exception: return any errors or warnings in this structure.
3972%
3973*/
3974MagickExport MagickBooleanType PersistPixelCache(Image *image,
3975 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3976 ExceptionInfo *exception)
3977{
3978 CacheInfo
3979 *cache_info,
3980 *clone_info;
3981
3982 Image
3983 clone_image;
3984
cristy3ed852e2009-09-05 21:47:34 +00003985 MagickBooleanType
3986 status;
3987
cristye076a6e2010-08-15 19:59:43 +00003988 ssize_t
3989 page_size;
3990
cristy3ed852e2009-09-05 21:47:34 +00003991 assert(image != (Image *) NULL);
3992 assert(image->signature == MagickSignature);
3993 if (image->debug != MagickFalse)
3994 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3995 assert(image->cache != (void *) NULL);
3996 assert(filename != (const char *) NULL);
3997 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00003998 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00003999 cache_info=(CacheInfo *) image->cache;
4000 assert(cache_info->signature == MagickSignature);
4001 if (attach != MagickFalse)
4002 {
4003 /*
cristy01b7eb02009-09-10 23:10:14 +00004004 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004005 */
4006 if (image->debug != MagickFalse)
4007 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004008 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004009 (void) CopyMagickString(cache_info->cache_filename,filename,
4010 MaxTextExtent);
4011 cache_info->type=DiskCache;
4012 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004013 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004014 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004015 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004016 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004017 }
cristy01b7eb02009-09-10 23:10:14 +00004018 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4019 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004020 {
cristyf84a1932010-01-03 18:00:18 +00004021 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004022 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004023 (cache_info->reference_count == 1))
4024 {
4025 int
4026 status;
4027
4028 /*
cristy01b7eb02009-09-10 23:10:14 +00004029 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004030 */
cristy320684d2011-09-23 14:55:47 +00004031 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004032 if (status == 0)
4033 {
4034 (void) CopyMagickString(cache_info->cache_filename,filename,
4035 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004036 *offset+=cache_info->length+page_size-(cache_info->length %
4037 page_size);
cristyf84a1932010-01-03 18:00:18 +00004038 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004039 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004040 if (image->debug != MagickFalse)
4041 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4042 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004043 return(MagickTrue);
4044 }
4045 }
cristyf84a1932010-01-03 18:00:18 +00004046 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004047 }
4048 /*
cristy01b7eb02009-09-10 23:10:14 +00004049 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004050 */
4051 clone_image=(*image);
4052 clone_info=(CacheInfo *) clone_image.cache;
4053 image->cache=ClonePixelCache(cache_info);
4054 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4055 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4056 cache_info->type=DiskCache;
4057 cache_info->offset=(*offset);
4058 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004059 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004060 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004061 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004062 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004063 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4064 return(status);
4065}
4066
4067/*
4068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4069% %
4070% %
4071% %
cristyc11dace2012-01-24 16:39:46 +00004072+ 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 +00004073% %
4074% %
4075% %
4076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4077%
cristyc11dace2012-01-24 16:39:46 +00004078% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4079% defined by the region rectangle and returns a pointer to the region. This
4080% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004081% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4082% pixels are transferred, otherwise a NULL is returned.
4083%
cristyc11dace2012-01-24 16:39:46 +00004084% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004085%
cristyc11dace2012-01-24 16:39:46 +00004086% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004087% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004088% const MagickBooleanType clone,NexusInfo *nexus_info,
4089% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004090%
4091% A description of each parameter follows:
4092%
4093% o image: the image.
4094%
4095% o x,y,columns,rows: These values define the perimeter of a region of
4096% pixels.
4097%
4098% o nexus_info: the cache nexus to set.
4099%
cristy65dbf172011-10-06 17:32:04 +00004100% o clone: clone the pixel cache.
4101%
cristy3ed852e2009-09-05 21:47:34 +00004102% o exception: return any errors or warnings in this structure.
4103%
4104*/
cristyc11dace2012-01-24 16:39:46 +00004105MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4106 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004107 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004108{
4109 CacheInfo
4110 *cache_info;
4111
4112 MagickOffsetType
4113 offset;
4114
4115 MagickSizeType
4116 number_pixels;
4117
4118 RectangleInfo
4119 region;
4120
4121 /*
4122 Validate pixel cache geometry.
4123 */
cristye7cc7cf2010-09-21 13:26:47 +00004124 assert(image != (const Image *) NULL);
4125 assert(image->signature == MagickSignature);
4126 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004127 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004128 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004129 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004130 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004131 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4132 {
4133 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004134 "NoPixelsDefinedInCache","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004135 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004136 }
cristybb503372010-05-27 20:51:26 +00004137 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4138 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004139 {
4140 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
anthonye5b39652012-04-21 05:37:29 +00004141 "PixelsAreNotAuthentic","'%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004142 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004143 }
4144 offset=(MagickOffsetType) y*cache_info->columns+x;
4145 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004146 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004147 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4148 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4149 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004150 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004151 /*
4152 Return pixel cache.
4153 */
4154 region.x=x;
4155 region.y=y;
4156 region.width=columns;
4157 region.height=rows;
cristy265a2b22012-05-11 12:48:50 +00004158 return(SetPixelCacheNexusPixels(image,WriteMode,&region,nexus_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00004159}
4160
4161/*
4162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4163% %
4164% %
4165% %
4166+ 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 %
4167% %
4168% %
4169% %
4170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4171%
4172% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4173% defined by the region rectangle and returns a pointer to the region. This
4174% region is subsequently transferred from the pixel cache with
4175% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4176% pixels are transferred, otherwise a NULL is returned.
4177%
4178% The format of the QueueAuthenticPixelsCache() method is:
4179%
cristy4c08aed2011-07-01 19:47:50 +00004180% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004181% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004182% ExceptionInfo *exception)
4183%
4184% A description of each parameter follows:
4185%
4186% o image: the image.
4187%
4188% o x,y,columns,rows: These values define the perimeter of a region of
4189% pixels.
4190%
4191% o exception: return any errors or warnings in this structure.
4192%
4193*/
cristy4c08aed2011-07-01 19:47:50 +00004194static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004195 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004196 ExceptionInfo *exception)
4197{
4198 CacheInfo
4199 *cache_info;
4200
cristy5c9e6f22010-09-17 17:31:01 +00004201 const int
4202 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004203
cristy4c08aed2011-07-01 19:47:50 +00004204 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004205 *q;
cristy4c08aed2011-07-01 19:47:50 +00004206
cristye7cc7cf2010-09-21 13:26:47 +00004207 assert(image != (const Image *) NULL);
4208 assert(image->signature == MagickSignature);
4209 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004210 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004211 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004212 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004213 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004214 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004215 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004216}
4217
4218/*
4219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4220% %
4221% %
4222% %
4223% Q u e u e A u t h e n t i c P i x e l s %
4224% %
4225% %
4226% %
4227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4228%
4229% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004230% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004231% region is returned, otherwise NULL is returned. The returned pointer may
4232% point to a temporary working buffer for the pixels or it may point to the
4233% final location of the pixels in memory.
4234%
4235% Write-only access means that any existing pixel values corresponding to
4236% the region are ignored. This is useful if the initial image is being
4237% created from scratch, or if the existing pixel values are to be
4238% completely replaced without need to refer to their pre-existing values.
4239% The application is free to read and write the pixel buffer returned by
4240% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4241% initialize the pixel array values. Initializing pixel array values is the
4242% application's responsibility.
4243%
4244% Performance is maximized if the selected region is part of one row, or
4245% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004246% pixels in-place (without a copy) if the image is in memory, or in a
4247% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004248% by the user.
4249%
4250% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004251% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4252% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4253% obtain the meta-content (of type void) corresponding to the region.
4254% Once the Quantum (and/or Quantum) array has been updated, the
4255% changes must be saved back to the underlying image using
4256% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004257%
4258% The format of the QueueAuthenticPixels() method is:
4259%
cristy4c08aed2011-07-01 19:47:50 +00004260% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004261% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004262% ExceptionInfo *exception)
4263%
4264% A description of each parameter follows:
4265%
4266% o image: the image.
4267%
4268% o x,y,columns,rows: These values define the perimeter of a region of
4269% pixels.
4270%
4271% o exception: return any errors or warnings in this structure.
4272%
4273*/
cristy4c08aed2011-07-01 19:47:50 +00004274MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004275 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004276 ExceptionInfo *exception)
4277{
4278 CacheInfo
4279 *cache_info;
4280
cristy2036f5c2010-09-19 21:18:17 +00004281 const int
4282 id = GetOpenMPThreadId();
4283
cristy4c08aed2011-07-01 19:47:50 +00004284 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004285 *q;
cristy4c08aed2011-07-01 19:47:50 +00004286
cristy3ed852e2009-09-05 21:47:34 +00004287 assert(image != (Image *) NULL);
4288 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004289 assert(image->cache != (Cache) NULL);
4290 cache_info=(CacheInfo *) image->cache;
4291 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004292 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004293 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004294 {
cristyc36c8822012-02-14 14:02:36 +00004295 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4296 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004297 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004298 }
cristy2036f5c2010-09-19 21:18:17 +00004299 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004300 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004301 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004302 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004303}
4304
4305/*
4306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4307% %
4308% %
4309% %
cristy4c08aed2011-07-01 19:47:50 +00004310+ 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 +00004311% %
4312% %
4313% %
4314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4315%
cristy4c08aed2011-07-01 19:47:50 +00004316% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004317% the pixel cache.
4318%
cristy4c08aed2011-07-01 19:47:50 +00004319% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004320%
cristy4c08aed2011-07-01 19:47:50 +00004321% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004322% NexusInfo *nexus_info,ExceptionInfo *exception)
4323%
4324% A description of each parameter follows:
4325%
4326% o cache_info: the pixel cache.
4327%
cristy4c08aed2011-07-01 19:47:50 +00004328% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004329%
4330% o exception: return any errors or warnings in this structure.
4331%
4332*/
cristy4c08aed2011-07-01 19:47:50 +00004333static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004334 NexusInfo *nexus_info,ExceptionInfo *exception)
4335{
4336 MagickOffsetType
4337 count,
4338 offset;
4339
4340 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004341 extent,
4342 length;
cristy3ed852e2009-09-05 21:47:34 +00004343
cristybb503372010-05-27 20:51:26 +00004344 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004345 y;
4346
cristy4c08aed2011-07-01 19:47:50 +00004347 register unsigned char
4348 *restrict q;
4349
cristybb503372010-05-27 20:51:26 +00004350 size_t
cristy3ed852e2009-09-05 21:47:34 +00004351 rows;
4352
cristy4c08aed2011-07-01 19:47:50 +00004353 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004354 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004355 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004356 return(MagickTrue);
4357 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4358 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004359 length=(MagickSizeType) nexus_info->region.width*
4360 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004361 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004362 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004363 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004364 switch (cache_info->type)
4365 {
4366 case MemoryCache:
4367 case MapCache:
4368 {
cristy4c08aed2011-07-01 19:47:50 +00004369 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004370 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004371
4372 /*
cristy4c08aed2011-07-01 19:47:50 +00004373 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004374 */
cristydd341db2010-03-04 19:06:38 +00004375 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004376 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004377 {
cristy48078b12010-09-23 17:11:01 +00004378 length=extent;
cristydd341db2010-03-04 19:06:38 +00004379 rows=1UL;
4380 }
cristy4c08aed2011-07-01 19:47:50 +00004381 p=(unsigned char *) cache_info->metacontent+offset*
4382 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004383 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004384 {
cristy8f036fe2010-09-18 02:02:00 +00004385 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004386 p+=cache_info->metacontent_extent*cache_info->columns;
4387 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004388 }
4389 break;
4390 }
4391 case DiskCache:
4392 {
4393 /*
cristy4c08aed2011-07-01 19:47:50 +00004394 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004395 */
4396 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4397 {
4398 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4399 cache_info->cache_filename);
4400 return(MagickFalse);
4401 }
cristydd341db2010-03-04 19:06:38 +00004402 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004403 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004404 {
cristy48078b12010-09-23 17:11:01 +00004405 length=extent;
cristydd341db2010-03-04 19:06:38 +00004406 rows=1UL;
4407 }
cristy48078b12010-09-23 17:11:01 +00004408 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004409 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004410 {
cristy48078b12010-09-23 17:11:01 +00004411 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004412 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004413 cache_info->metacontent_extent,length,(unsigned char *) q);
4414 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004415 break;
4416 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004417 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004418 }
cristyc11dace2012-01-24 16:39:46 +00004419 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4420 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004421 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004422 {
4423 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4424 cache_info->cache_filename);
4425 return(MagickFalse);
4426 }
4427 break;
4428 }
4429 default:
4430 break;
4431 }
4432 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004433 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004434 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004435 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004436 nexus_info->region.width,(double) nexus_info->region.height,(double)
4437 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004438 return(MagickTrue);
4439}
4440
4441/*
4442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4443% %
4444% %
4445% %
4446+ R e a d P i x e l C a c h e P i x e l s %
4447% %
4448% %
4449% %
4450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4451%
4452% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4453% cache.
4454%
4455% The format of the ReadPixelCachePixels() method is:
4456%
4457% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4458% NexusInfo *nexus_info,ExceptionInfo *exception)
4459%
4460% A description of each parameter follows:
4461%
4462% o cache_info: the pixel cache.
4463%
4464% o nexus_info: the cache nexus to read the pixels.
4465%
4466% o exception: return any errors or warnings in this structure.
4467%
4468*/
4469static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4470 NexusInfo *nexus_info,ExceptionInfo *exception)
4471{
4472 MagickOffsetType
4473 count,
4474 offset;
4475
4476 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004477 extent,
4478 length;
cristy3ed852e2009-09-05 21:47:34 +00004479
cristy4c08aed2011-07-01 19:47:50 +00004480 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004481 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004482
cristye076a6e2010-08-15 19:59:43 +00004483 register ssize_t
4484 y;
4485
cristybb503372010-05-27 20:51:26 +00004486 size_t
cristy3ed852e2009-09-05 21:47:34 +00004487 rows;
4488
cristy4c08aed2011-07-01 19:47:50 +00004489 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004490 return(MagickTrue);
4491 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4492 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004493 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004494 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004495 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004496 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004497 q=nexus_info->pixels;
4498 switch (cache_info->type)
4499 {
4500 case MemoryCache:
4501 case MapCache:
4502 {
cristy4c08aed2011-07-01 19:47:50 +00004503 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004504 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004505
4506 /*
4507 Read pixels from memory.
4508 */
cristydd341db2010-03-04 19:06:38 +00004509 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004510 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004511 {
cristy48078b12010-09-23 17:11:01 +00004512 length=extent;
cristydd341db2010-03-04 19:06:38 +00004513 rows=1UL;
4514 }
cristyed231572011-07-14 02:18:59 +00004515 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004516 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004517 {
cristy8f036fe2010-09-18 02:02:00 +00004518 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004519 p+=cache_info->number_channels*cache_info->columns;
4520 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004521 }
4522 break;
4523 }
4524 case DiskCache:
4525 {
4526 /*
4527 Read pixels from disk.
4528 */
4529 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4530 {
4531 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4532 cache_info->cache_filename);
4533 return(MagickFalse);
4534 }
cristydd341db2010-03-04 19:06:38 +00004535 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004536 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004537 {
cristy48078b12010-09-23 17:11:01 +00004538 length=extent;
cristydd341db2010-03-04 19:06:38 +00004539 rows=1UL;
4540 }
cristybb503372010-05-27 20:51:26 +00004541 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004542 {
4543 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004544 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004545 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004546 break;
4547 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004548 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004549 }
cristyc11dace2012-01-24 16:39:46 +00004550 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4551 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004552 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004553 {
4554 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4555 cache_info->cache_filename);
4556 return(MagickFalse);
4557 }
4558 break;
4559 }
4560 default:
4561 break;
4562 }
4563 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004564 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004565 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004566 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004567 nexus_info->region.width,(double) nexus_info->region.height,(double)
4568 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004569 return(MagickTrue);
4570}
4571
4572/*
4573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4574% %
4575% %
4576% %
4577+ R e f e r e n c e P i x e l C a c h e %
4578% %
4579% %
4580% %
4581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4582%
4583% ReferencePixelCache() increments the reference count associated with the
4584% pixel cache returning a pointer to the cache.
4585%
4586% The format of the ReferencePixelCache method is:
4587%
4588% Cache ReferencePixelCache(Cache cache_info)
4589%
4590% A description of each parameter follows:
4591%
4592% o cache_info: the pixel cache.
4593%
4594*/
cristya6577ff2011-09-02 19:54:26 +00004595MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004596{
4597 CacheInfo
4598 *cache_info;
4599
4600 assert(cache != (Cache *) NULL);
4601 cache_info=(CacheInfo *) cache;
4602 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004603 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004604 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004605 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004606 return(cache_info);
4607}
4608
4609/*
4610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4611% %
4612% %
4613% %
4614+ S e t P i x e l C a c h e M e t h o d s %
4615% %
4616% %
4617% %
4618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4619%
4620% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4621%
4622% The format of the SetPixelCacheMethods() method is:
4623%
4624% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4625%
4626% A description of each parameter follows:
4627%
4628% o cache: the pixel cache.
4629%
4630% o cache_methods: Specifies a pointer to a CacheMethods structure.
4631%
4632*/
cristya6577ff2011-09-02 19:54:26 +00004633MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004634{
4635 CacheInfo
4636 *cache_info;
4637
4638 GetOneAuthenticPixelFromHandler
4639 get_one_authentic_pixel_from_handler;
4640
4641 GetOneVirtualPixelFromHandler
4642 get_one_virtual_pixel_from_handler;
4643
4644 /*
4645 Set cache pixel methods.
4646 */
4647 assert(cache != (Cache) NULL);
4648 assert(cache_methods != (CacheMethods *) NULL);
4649 cache_info=(CacheInfo *) cache;
4650 assert(cache_info->signature == MagickSignature);
4651 if (cache_info->debug != MagickFalse)
4652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4653 cache_info->filename);
4654 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4655 cache_info->methods.get_virtual_pixel_handler=
4656 cache_methods->get_virtual_pixel_handler;
4657 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4658 cache_info->methods.destroy_pixel_handler=
4659 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004660 if (cache_methods->get_virtual_metacontent_from_handler !=
4661 (GetVirtualMetacontentFromHandler) NULL)
4662 cache_info->methods.get_virtual_metacontent_from_handler=
4663 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004664 if (cache_methods->get_authentic_pixels_handler !=
4665 (GetAuthenticPixelsHandler) NULL)
4666 cache_info->methods.get_authentic_pixels_handler=
4667 cache_methods->get_authentic_pixels_handler;
4668 if (cache_methods->queue_authentic_pixels_handler !=
4669 (QueueAuthenticPixelsHandler) NULL)
4670 cache_info->methods.queue_authentic_pixels_handler=
4671 cache_methods->queue_authentic_pixels_handler;
4672 if (cache_methods->sync_authentic_pixels_handler !=
4673 (SyncAuthenticPixelsHandler) NULL)
4674 cache_info->methods.sync_authentic_pixels_handler=
4675 cache_methods->sync_authentic_pixels_handler;
4676 if (cache_methods->get_authentic_pixels_from_handler !=
4677 (GetAuthenticPixelsFromHandler) NULL)
4678 cache_info->methods.get_authentic_pixels_from_handler=
4679 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004680 if (cache_methods->get_authentic_metacontent_from_handler !=
4681 (GetAuthenticMetacontentFromHandler) NULL)
4682 cache_info->methods.get_authentic_metacontent_from_handler=
4683 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004684 get_one_virtual_pixel_from_handler=
4685 cache_info->methods.get_one_virtual_pixel_from_handler;
4686 if (get_one_virtual_pixel_from_handler !=
4687 (GetOneVirtualPixelFromHandler) NULL)
4688 cache_info->methods.get_one_virtual_pixel_from_handler=
4689 cache_methods->get_one_virtual_pixel_from_handler;
4690 get_one_authentic_pixel_from_handler=
4691 cache_methods->get_one_authentic_pixel_from_handler;
4692 if (get_one_authentic_pixel_from_handler !=
4693 (GetOneAuthenticPixelFromHandler) NULL)
4694 cache_info->methods.get_one_authentic_pixel_from_handler=
4695 cache_methods->get_one_authentic_pixel_from_handler;
4696}
4697
4698/*
4699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4700% %
4701% %
4702% %
4703+ S e t P i x e l C a c h e N e x u s P i x e l s %
4704% %
4705% %
4706% %
4707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4708%
4709% SetPixelCacheNexusPixels() defines the region of the cache for the
4710% specified cache nexus.
4711%
4712% The format of the SetPixelCacheNexusPixels() method is:
4713%
cristy265a2b22012-05-11 12:48:50 +00004714% Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004715% const RectangleInfo *region,NexusInfo *nexus_info,
4716% ExceptionInfo *exception)
4717%
4718% A description of each parameter follows:
4719%
4720% o image: the image.
4721%
cristy265a2b22012-05-11 12:48:50 +00004722% o mode: ReadMode, WriteMode, or IOMode.
4723%
cristy3ed852e2009-09-05 21:47:34 +00004724% 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
cristyf1832792012-05-08 18:38:18 +00004733static inline MagickBooleanType AcquireCacheNexusPixels(
4734 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4735 ExceptionInfo *exception)
cristyabd6e372010-09-15 19:11:26 +00004736{
4737 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4738 return(MagickFalse);
4739 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004740 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004741 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004742 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004743 {
4744 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004745 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004746 nexus_info->length);
4747 }
cristy4c08aed2011-07-01 19:47:50 +00004748 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004749 {
4750 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +00004751 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristyabd6e372010-09-15 19:11:26 +00004752 cache_info->filename);
4753 return(MagickFalse);
4754 }
4755 return(MagickTrue);
4756}
4757
cristy265a2b22012-05-11 12:48:50 +00004758static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
cristy3ed852e2009-09-05 21:47:34 +00004759 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4760{
4761 CacheInfo
4762 *cache_info;
4763
4764 MagickBooleanType
4765 status;
4766
cristy3ed852e2009-09-05 21:47:34 +00004767 MagickSizeType
4768 length,
4769 number_pixels;
4770
cristy3ed852e2009-09-05 21:47:34 +00004771 cache_info=(CacheInfo *) image->cache;
4772 assert(cache_info->signature == MagickSignature);
4773 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004774 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004775 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004776 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004777 {
cristybb503372010-05-27 20:51:26 +00004778 ssize_t
cristybad067a2010-02-15 17:20:55 +00004779 x,
4780 y;
cristy3ed852e2009-09-05 21:47:34 +00004781
cristyeaedf062010-05-29 22:36:02 +00004782 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4783 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004784 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4785 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004786 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004787 ((nexus_info->region.width == cache_info->columns) ||
4788 ((nexus_info->region.width % cache_info->columns) == 0)))))
4789 {
4790 MagickOffsetType
4791 offset;
4792
4793 /*
4794 Pixels are accessed directly from memory.
4795 */
4796 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4797 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004798 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004799 offset;
cristy265a2b22012-05-11 12:48:50 +00004800 if (mode == ReadMode)
4801 MagickCachePrefetch(nexus_info->pixels,0,0);
4802 else
4803 MagickCachePrefetch(nexus_info->pixels,1,1);
cristy4c08aed2011-07-01 19:47:50 +00004804 nexus_info->metacontent=(void *) NULL;
4805 if (cache_info->metacontent_extent != 0)
4806 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4807 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004808 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004809 }
4810 }
4811 /*
4812 Pixels are stored in a cache region until they are synced to the cache.
4813 */
4814 number_pixels=(MagickSizeType) nexus_info->region.width*
4815 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004816 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004817 if (cache_info->metacontent_extent != 0)
4818 length+=number_pixels*cache_info->metacontent_extent;
4819 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004820 {
4821 nexus_info->length=length;
4822 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4823 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004824 {
4825 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004826 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004827 }
cristy3ed852e2009-09-05 21:47:34 +00004828 }
4829 else
4830 if (nexus_info->length != length)
4831 {
4832 RelinquishCacheNexusPixels(nexus_info);
4833 nexus_info->length=length;
4834 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4835 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004836 {
4837 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004838 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004839 }
cristy3ed852e2009-09-05 21:47:34 +00004840 }
4841 nexus_info->pixels=nexus_info->cache;
cristy265a2b22012-05-11 12:48:50 +00004842 if (mode == ReadMode)
4843 MagickCachePrefetch(nexus_info->pixels,0,0);
4844 else
4845 MagickCachePrefetch(nexus_info->pixels,1,1);
cristy4c08aed2011-07-01 19:47:50 +00004846 nexus_info->metacontent=(void *) NULL;
4847 if (cache_info->metacontent_extent != 0)
4848 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004849 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004850 return(nexus_info->pixels);
4851}
4852
4853/*
4854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4855% %
4856% %
4857% %
4858% 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 %
4859% %
4860% %
4861% %
4862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4863%
4864% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4865% pixel cache and returns the previous setting. A virtual pixel is any pixel
4866% access that is outside the boundaries of the image cache.
4867%
4868% The format of the SetPixelCacheVirtualMethod() method is:
4869%
cristy387430f2012-02-07 13:09:46 +00004870% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4871% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004872%
4873% A description of each parameter follows:
4874%
4875% o image: the image.
4876%
4877% o virtual_pixel_method: choose the type of virtual pixel.
4878%
cristy387430f2012-02-07 13:09:46 +00004879% o exception: return any errors or warnings in this structure.
4880%
cristy3ed852e2009-09-05 21:47:34 +00004881*/
cristy3d4cb882012-02-07 19:11:26 +00004882
4883static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4884 ExceptionInfo *exception)
4885{
4886 CacheInfo
4887 *cache_info;
4888
cristyf2719112012-05-06 18:38:46 +00004889 CacheView
4890 *image_view;
4891
cristy3d4cb882012-02-07 19:11:26 +00004892 MagickBooleanType
4893 status;
4894
4895 ssize_t
4896 y;
4897
4898 assert(image != (Image *) NULL);
4899 assert(image->signature == MagickSignature);
4900 if (image->debug != MagickFalse)
4901 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4902 assert(image->cache != (Cache) NULL);
4903 cache_info=(CacheInfo *) image->cache;
4904 assert(cache_info->signature == MagickSignature);
4905 image->matte=MagickTrue;
4906 status=MagickTrue;
cristya1022ad2012-05-02 13:01:59 +00004907 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
cristy3d4cb882012-02-07 19:11:26 +00004908#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00004909 #pragma omp parallel for schedule(static) shared(status) \
cristyddacdd12012-05-07 23:08:14 +00004910 dynamic_number_threads(image->columns,image->rows,1)
cristy3d4cb882012-02-07 19:11:26 +00004911#endif
4912 for (y=0; y < (ssize_t) image->rows; y++)
4913 {
cristy3d4cb882012-02-07 19:11:26 +00004914 register Quantum
4915 *restrict q;
4916
4917 register ssize_t
4918 x;
4919
4920 if (status == MagickFalse)
4921 continue;
cristy23d198a2012-03-13 13:48:08 +00004922 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004923 if (q == (Quantum *) NULL)
4924 {
4925 status=MagickFalse;
4926 continue;
4927 }
4928 for (x=0; x < (ssize_t) image->columns; x++)
4929 {
4930 SetPixelAlpha(image,alpha,q);
4931 q+=GetPixelChannels(image);
4932 }
cristy23d198a2012-03-13 13:48:08 +00004933 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004934 }
cristy23d198a2012-03-13 13:48:08 +00004935 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004936 return(status);
4937}
4938
cristy387430f2012-02-07 13:09:46 +00004939MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4940 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004941{
4942 CacheInfo
4943 *cache_info;
4944
4945 VirtualPixelMethod
4946 method;
4947
4948 assert(image != (Image *) NULL);
4949 assert(image->signature == MagickSignature);
4950 if (image->debug != MagickFalse)
4951 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4952 assert(image->cache != (Cache) NULL);
4953 cache_info=(CacheInfo *) image->cache;
4954 assert(cache_info->signature == MagickSignature);
4955 method=cache_info->virtual_pixel_method;
4956 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004957 switch (virtual_pixel_method)
4958 {
4959 case BackgroundVirtualPixelMethod:
4960 {
4961 if ((image->background_color.matte != MagickFalse) &&
4962 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00004963 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004964 break;
4965 }
4966 case TransparentVirtualPixelMethod:
4967 {
4968 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004969 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004970 break;
4971 }
4972 default:
4973 break;
4974 }
cristy3ed852e2009-09-05 21:47:34 +00004975 return(method);
4976}
4977
4978/*
4979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4980% %
4981% %
4982% %
4983+ 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 %
4984% %
4985% %
4986% %
4987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4988%
4989% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4990% in-memory or disk cache. The method returns MagickTrue if the pixel region
4991% is synced, otherwise MagickFalse.
4992%
4993% The format of the SyncAuthenticPixelCacheNexus() method is:
4994%
4995% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4996% NexusInfo *nexus_info,ExceptionInfo *exception)
4997%
4998% A description of each parameter follows:
4999%
5000% o image: the image.
5001%
5002% o nexus_info: the cache nexus to sync.
5003%
5004% o exception: return any errors or warnings in this structure.
5005%
5006*/
cristya6577ff2011-09-02 19:54:26 +00005007MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005008 NexusInfo *nexus_info,ExceptionInfo *exception)
5009{
5010 CacheInfo
5011 *cache_info;
5012
5013 MagickBooleanType
5014 status;
5015
5016 /*
5017 Transfer pixels to the cache.
5018 */
5019 assert(image != (Image *) NULL);
5020 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005021 if (image->cache == (Cache) NULL)
5022 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5023 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005024 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005025 if (cache_info->type == UndefinedCache)
5026 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005027 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005028 return(MagickTrue);
5029 assert(cache_info->signature == MagickSignature);
5030 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005031 if ((cache_info->metacontent_extent != 0) &&
5032 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005033 return(MagickFalse);
5034 return(status);
5035}
5036
5037/*
5038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5039% %
5040% %
5041% %
5042+ S y n c A u t h e n t i c P i x e l C a c h e %
5043% %
5044% %
5045% %
5046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5047%
5048% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5049% or disk cache. The method returns MagickTrue if the pixel region is synced,
5050% otherwise MagickFalse.
5051%
5052% The format of the SyncAuthenticPixelsCache() method is:
5053%
5054% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5055% ExceptionInfo *exception)
5056%
5057% A description of each parameter follows:
5058%
5059% o image: the image.
5060%
5061% o exception: return any errors or warnings in this structure.
5062%
5063*/
5064static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5065 ExceptionInfo *exception)
5066{
5067 CacheInfo
5068 *cache_info;
5069
cristy5c9e6f22010-09-17 17:31:01 +00005070 const int
5071 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005072
cristy4c08aed2011-07-01 19:47:50 +00005073 MagickBooleanType
5074 status;
5075
cristye7cc7cf2010-09-21 13:26:47 +00005076 assert(image != (Image *) NULL);
5077 assert(image->signature == MagickSignature);
5078 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005079 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005080 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005081 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005082 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5083 exception);
5084 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005085}
5086
5087/*
5088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5089% %
5090% %
5091% %
5092% S y n c A u t h e n t i c P i x e l s %
5093% %
5094% %
5095% %
5096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5097%
5098% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5099% The method returns MagickTrue if the pixel region is flushed, otherwise
5100% MagickFalse.
5101%
5102% The format of the SyncAuthenticPixels() method is:
5103%
5104% MagickBooleanType SyncAuthenticPixels(Image *image,
5105% ExceptionInfo *exception)
5106%
5107% A description of each parameter follows:
5108%
5109% o image: the image.
5110%
5111% o exception: return any errors or warnings in this structure.
5112%
5113*/
5114MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5115 ExceptionInfo *exception)
5116{
5117 CacheInfo
5118 *cache_info;
5119
cristy2036f5c2010-09-19 21:18:17 +00005120 const int
5121 id = GetOpenMPThreadId();
5122
cristy4c08aed2011-07-01 19:47:50 +00005123 MagickBooleanType
5124 status;
5125
cristy3ed852e2009-09-05 21:47:34 +00005126 assert(image != (Image *) NULL);
5127 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005128 assert(image->cache != (Cache) NULL);
5129 cache_info=(CacheInfo *) image->cache;
5130 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005131 if (cache_info->methods.sync_authentic_pixels_handler !=
5132 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005133 {
5134 status=cache_info->methods.sync_authentic_pixels_handler(image,
5135 exception);
5136 return(status);
5137 }
cristy2036f5c2010-09-19 21:18:17 +00005138 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005139 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5140 exception);
5141 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005142}
5143
5144/*
5145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5146% %
5147% %
5148% %
cristyd1dd6e42011-09-04 01:46:08 +00005149+ 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 +00005150% %
5151% %
5152% %
5153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5154%
5155% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5156% The method returns MagickTrue if the pixel region is flushed, otherwise
5157% MagickFalse.
5158%
5159% The format of the SyncImagePixelCache() method is:
5160%
5161% MagickBooleanType SyncImagePixelCache(Image *image,
5162% ExceptionInfo *exception)
5163%
5164% A description of each parameter follows:
5165%
5166% o image: the image.
5167%
5168% o exception: return any errors or warnings in this structure.
5169%
5170*/
cristyd1dd6e42011-09-04 01:46:08 +00005171MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005172 ExceptionInfo *exception)
5173{
5174 CacheInfo
5175 *cache_info;
5176
5177 assert(image != (Image *) NULL);
5178 assert(exception != (ExceptionInfo *) NULL);
5179 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5180 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5181}
5182
5183/*
5184%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5185% %
5186% %
5187% %
cristy4c08aed2011-07-01 19:47:50 +00005188+ 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 +00005189% %
5190% %
5191% %
5192%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5193%
cristy4c08aed2011-07-01 19:47:50 +00005194% WritePixelCacheMetacontent() writes the meta-content to the specified region
5195% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005196%
cristy4c08aed2011-07-01 19:47:50 +00005197% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005198%
cristy4c08aed2011-07-01 19:47:50 +00005199% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005200% NexusInfo *nexus_info,ExceptionInfo *exception)
5201%
5202% A description of each parameter follows:
5203%
5204% o cache_info: the pixel cache.
5205%
cristy4c08aed2011-07-01 19:47:50 +00005206% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005207%
5208% o exception: return any errors or warnings in this structure.
5209%
5210*/
cristy4c08aed2011-07-01 19:47:50 +00005211static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005212 NexusInfo *nexus_info,ExceptionInfo *exception)
5213{
5214 MagickOffsetType
5215 count,
5216 offset;
5217
5218 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005219 extent,
5220 length;
cristy3ed852e2009-09-05 21:47:34 +00005221
cristy4c08aed2011-07-01 19:47:50 +00005222 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005223 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005224
cristybb503372010-05-27 20:51:26 +00005225 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005226 y;
5227
cristybb503372010-05-27 20:51:26 +00005228 size_t
cristy3ed852e2009-09-05 21:47:34 +00005229 rows;
5230
cristy4c08aed2011-07-01 19:47:50 +00005231 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005232 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005233 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005234 return(MagickTrue);
5235 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5236 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005237 length=(MagickSizeType) nexus_info->region.width*
5238 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005239 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005240 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005241 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005242 switch (cache_info->type)
5243 {
5244 case MemoryCache:
5245 case MapCache:
5246 {
cristy4c08aed2011-07-01 19:47:50 +00005247 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005248 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005249
5250 /*
cristy4c08aed2011-07-01 19:47:50 +00005251 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005252 */
cristydd341db2010-03-04 19:06:38 +00005253 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005254 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005255 {
cristy48078b12010-09-23 17:11:01 +00005256 length=extent;
cristydd341db2010-03-04 19:06:38 +00005257 rows=1UL;
5258 }
cristy4c08aed2011-07-01 19:47:50 +00005259 q=(unsigned char *) cache_info->metacontent+offset*
5260 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005261 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005262 {
cristy8f036fe2010-09-18 02:02:00 +00005263 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005264 p+=nexus_info->region.width*cache_info->metacontent_extent;
5265 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005266 }
5267 break;
5268 }
5269 case DiskCache:
5270 {
5271 /*
cristy4c08aed2011-07-01 19:47:50 +00005272 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005273 */
5274 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5275 {
5276 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5277 cache_info->cache_filename);
5278 return(MagickFalse);
5279 }
cristydd341db2010-03-04 19:06:38 +00005280 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005281 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005282 {
cristy48078b12010-09-23 17:11:01 +00005283 length=extent;
cristydd341db2010-03-04 19:06:38 +00005284 rows=1UL;
5285 }
cristy48078b12010-09-23 17:11:01 +00005286 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005287 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005288 {
cristy48078b12010-09-23 17:11:01 +00005289 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005290 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005291 cache_info->metacontent_extent,length,(const unsigned char *) p);
5292 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005293 break;
cristy4c08aed2011-07-01 19:47:50 +00005294 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005295 offset+=cache_info->columns;
5296 }
cristyc11dace2012-01-24 16:39:46 +00005297 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5298 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005299 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005300 {
5301 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5302 cache_info->cache_filename);
5303 return(MagickFalse);
5304 }
5305 break;
5306 }
5307 default:
5308 break;
5309 }
5310 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005311 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005312 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005313 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005314 nexus_info->region.width,(double) nexus_info->region.height,(double)
5315 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005316 return(MagickTrue);
5317}
5318
5319/*
5320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5321% %
5322% %
5323% %
5324+ W r i t e C a c h e P i x e l s %
5325% %
5326% %
5327% %
5328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5329%
5330% WritePixelCachePixels() writes image pixels to the specified region of the
5331% pixel cache.
5332%
5333% The format of the WritePixelCachePixels() method is:
5334%
5335% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5336% NexusInfo *nexus_info,ExceptionInfo *exception)
5337%
5338% A description of each parameter follows:
5339%
5340% o cache_info: the pixel cache.
5341%
5342% o nexus_info: the cache nexus to write the pixels.
5343%
5344% o exception: return any errors or warnings in this structure.
5345%
5346*/
5347static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5348 NexusInfo *nexus_info,ExceptionInfo *exception)
5349{
5350 MagickOffsetType
5351 count,
5352 offset;
5353
5354 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005355 extent,
5356 length;
cristy3ed852e2009-09-05 21:47:34 +00005357
cristy4c08aed2011-07-01 19:47:50 +00005358 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005359 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005360
cristybb503372010-05-27 20:51:26 +00005361 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005362 y;
5363
cristybb503372010-05-27 20:51:26 +00005364 size_t
cristy3ed852e2009-09-05 21:47:34 +00005365 rows;
5366
cristy4c08aed2011-07-01 19:47:50 +00005367 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005368 return(MagickTrue);
5369 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5370 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005371 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005372 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005373 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005374 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005375 p=nexus_info->pixels;
5376 switch (cache_info->type)
5377 {
5378 case MemoryCache:
5379 case MapCache:
5380 {
cristy4c08aed2011-07-01 19:47:50 +00005381 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005382 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005383
5384 /*
5385 Write pixels to memory.
5386 */
cristydd341db2010-03-04 19:06:38 +00005387 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005388 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005389 {
cristy48078b12010-09-23 17:11:01 +00005390 length=extent;
cristydd341db2010-03-04 19:06:38 +00005391 rows=1UL;
5392 }
cristyed231572011-07-14 02:18:59 +00005393 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005394 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005395 {
cristy8f036fe2010-09-18 02:02:00 +00005396 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005397 p+=nexus_info->region.width*cache_info->number_channels;
5398 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005399 }
5400 break;
5401 }
5402 case DiskCache:
5403 {
5404 /*
5405 Write pixels to disk.
5406 */
5407 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5408 {
5409 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5410 cache_info->cache_filename);
5411 return(MagickFalse);
5412 }
cristydd341db2010-03-04 19:06:38 +00005413 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005414 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005415 {
cristy48078b12010-09-23 17:11:01 +00005416 length=extent;
cristydd341db2010-03-04 19:06:38 +00005417 rows=1UL;
5418 }
cristybb503372010-05-27 20:51:26 +00005419 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005420 {
5421 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005422 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005423 p);
5424 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005425 break;
cristyed231572011-07-14 02:18:59 +00005426 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005427 offset+=cache_info->columns;
5428 }
cristyc11dace2012-01-24 16:39:46 +00005429 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5430 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005431 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005432 {
5433 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5434 cache_info->cache_filename);
5435 return(MagickFalse);
5436 }
5437 break;
5438 }
5439 default:
5440 break;
5441 }
5442 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005443 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005444 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005445 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005446 nexus_info->region.width,(double) nexus_info->region.height,(double)
5447 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005448 return(MagickTrue);
5449}