blob: 5a2f652f0c09c66e1d889386c37548c3e3880e1a [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
cristye7cc7cf2010-09-21 13:26:47 +0000134 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
cristy2ed42f62011-10-02 19:49:57 +0000135 Quantum *,ExceptionInfo *),
cristye7cc7cf2010-09-21 13:26:47 +0000136 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristy2ed42f62011-10-02 19:49:57 +0000137 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000138 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000139 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000140 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
141 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000142 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000143 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
144
cristy4c08aed2011-07-01 19:47:50 +0000145static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000146 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
147 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000148 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
149 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000150 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristy19596d62012-02-19 00:24:59 +0000151 ExceptionInfo *) magick_hot_spot;
cristy3ed852e2009-09-05 21:47:34 +0000152
153#if defined(__cplusplus) || defined(c_plusplus)
154}
155#endif
156
157/*
158 Global declarations.
159*/
160static volatile MagickBooleanType
161 instantiate_cache = MagickFalse;
162
163static SemaphoreInfo
164 *cache_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000165
166/*
167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168% %
169% %
170% %
171+ A c q u i r e P i x e l C a c h e %
172% %
173% %
174% %
175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176%
177% AcquirePixelCache() acquires a pixel cache.
178%
179% The format of the AcquirePixelCache() method is:
180%
cristybb503372010-05-27 20:51:26 +0000181% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000182%
183% A description of each parameter follows:
184%
185% o number_threads: the number of nexus threads.
186%
187*/
cristya6577ff2011-09-02 19:54:26 +0000188MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000189{
190 CacheInfo
191 *cache_info;
192
cristya64b85d2011-09-14 01:02:31 +0000193 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000194 if (cache_info == (CacheInfo *) NULL)
195 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
196 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
197 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000198 cache_info->mode=IOMode;
cristyc511e882012-04-16 21:11:14 +0000199 cache_info->colorspace=sRGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +0000200 cache_info->file=(-1);
201 cache_info->id=GetMagickThreadId();
202 cache_info->number_threads=number_threads;
203 if (number_threads == 0)
204 cache_info->number_threads=GetOpenMPMaximumThreads();
205 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
206 if (cache_info->nexus_info == (NexusInfo **) NULL)
207 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000208 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000209 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000210 cache_info->disk_semaphore=AllocateSemaphoreInfo();
211 cache_info->debug=IsEventLogging();
212 cache_info->signature=MagickSignature;
cristy3ed852e2009-09-05 21:47:34 +0000213 return((Cache ) cache_info);
214}
215
216/*
217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218% %
219% %
220% %
221% A c q u i r e P i x e l C a c h e N e x u s %
222% %
223% %
224% %
225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226%
227% AcquirePixelCacheNexus() allocates the NexusInfo structure.
228%
229% The format of the AcquirePixelCacheNexus method is:
230%
cristybb503372010-05-27 20:51:26 +0000231% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000232%
233% A description of each parameter follows:
234%
235% o number_threads: the number of nexus threads.
236%
237*/
cristya6577ff2011-09-02 19:54:26 +0000238MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000239{
cristy3ed852e2009-09-05 21:47:34 +0000240 NexusInfo
241 **nexus_info;
242
cristye076a6e2010-08-15 19:59:43 +0000243 register ssize_t
244 i;
245
cristy64c3edf2012-04-13 18:50:13 +0000246 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000247 sizeof(*nexus_info));
248 if (nexus_info == (NexusInfo **) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristye5f87c82012-02-14 12:44:17 +0000250 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
251 sizeof(**nexus_info));
252 if (nexus_info[0] == (NexusInfo *) NULL)
253 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
254 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
cristybb503372010-05-27 20:51:26 +0000255 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000256 {
cristye5f87c82012-02-14 12:44:17 +0000257 nexus_info[i]=(&nexus_info[0][i]);
cristy3ed852e2009-09-05 21:47:34 +0000258 nexus_info[i]->signature=MagickSignature;
259 }
260 return(nexus_info);
261}
262
263/*
264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265% %
266% %
267% %
cristyd43a46b2010-01-21 02:13:41 +0000268+ A c q u i r e P i x e l C a c h e P i x e l s %
269% %
270% %
271% %
272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273%
274% AcquirePixelCachePixels() returns the pixels associated with the specified
275% image.
276%
277% The format of the AcquirePixelCachePixels() method is:
278%
279% const void *AcquirePixelCachePixels(const Image *image,
280% MagickSizeType *length,ExceptionInfo *exception)
281%
282% A description of each parameter follows:
283%
284% o image: the image.
285%
286% o length: the pixel cache length.
287%
288% o exception: return any errors or warnings in this structure.
289%
290*/
cristyd1dd6e42011-09-04 01:46:08 +0000291MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
cristyd43a46b2010-01-21 02:13:41 +0000292 MagickSizeType *length,ExceptionInfo *exception)
293{
294 CacheInfo
295 *cache_info;
296
297 assert(image != (const Image *) NULL);
298 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000299 assert(exception != (ExceptionInfo *) NULL);
300 assert(exception->signature == MagickSignature);
301 assert(image->cache != (Cache) NULL);
302 cache_info=(CacheInfo *) image->cache;
303 assert(cache_info->signature == MagickSignature);
304 *length=0;
305 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
306 return((const void *) NULL);
307 *length=cache_info->length;
308 return((const void *) cache_info->pixels);
309}
310
311/*
312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313% %
314% %
315% %
cristyf34a1452009-10-24 22:29:27 +0000316+ C a c h e C o m p o n e n t G e n e s i s %
317% %
318% %
319% %
320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321%
322% CacheComponentGenesis() instantiates the cache component.
323%
324% The format of the CacheComponentGenesis method is:
325%
326% MagickBooleanType CacheComponentGenesis(void)
327%
328*/
cristy5ff4eaf2011-09-03 01:38:02 +0000329MagickPrivate MagickBooleanType CacheComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000330{
cristy165b6092009-10-26 13:52:10 +0000331 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000332 return(MagickTrue);
333}
334
335/*
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337% %
338% %
339% %
340+ C a c h e C o m p o n e n t T e r m i n u s %
341% %
342% %
343% %
344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345%
346% CacheComponentTerminus() destroys the cache component.
347%
348% The format of the CacheComponentTerminus() method is:
349%
350% CacheComponentTerminus(void)
351%
352*/
cristy5ff4eaf2011-09-03 01:38:02 +0000353MagickPrivate void CacheComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +0000354{
cristy18b17442009-10-25 18:36:48 +0000355 if (cache_semaphore == (SemaphoreInfo *) NULL)
356 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000357 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000358 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000359 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000360 DestroySemaphoreInfo(&cache_semaphore);
361}
362
363/*
364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365% %
366% %
367% %
cristy3ed852e2009-09-05 21:47:34 +0000368+ C l o n e P i x e l C a c h e %
369% %
370% %
371% %
372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373%
374% ClonePixelCache() clones a pixel cache.
375%
376% The format of the ClonePixelCache() method is:
377%
378% Cache ClonePixelCache(const Cache cache)
379%
380% A description of each parameter follows:
381%
382% o cache: the pixel cache.
383%
384*/
cristya6577ff2011-09-02 19:54:26 +0000385MagickPrivate Cache ClonePixelCache(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +0000386{
387 CacheInfo
388 *clone_info;
389
390 const CacheInfo
391 *cache_info;
392
cristy9f027d12011-09-21 01:17:17 +0000393 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +0000394 cache_info=(const CacheInfo *) cache;
395 assert(cache_info->signature == MagickSignature);
396 if (cache_info->debug != MagickFalse)
397 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
398 cache_info->filename);
399 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
400 if (clone_info == (Cache) NULL)
401 return((Cache) NULL);
402 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
403 return((Cache ) clone_info);
404}
405
406/*
407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408% %
409% %
410% %
cristy60c44a82009-10-07 00:58:49 +0000411+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000412% %
413% %
414% %
415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
416% ClonePixelCachePixels() clones the source pixel cache to the destination
417% cache.
418%
419% The format of the ClonePixelCachePixels() method is:
420%
421% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
422% CacheInfo *source_info,ExceptionInfo *exception)
423%
424% A description of each parameter follows:
425%
426% o cache_info: the pixel cache.
427%
428% o source_info: the source pixel cache.
429%
430% o exception: return any errors or warnings in this structure.
431%
432*/
433
434static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
435{
436 int
437 status;
438
cristy5ee247a2010-02-12 15:42:34 +0000439 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000440 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000441 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000442 {
443 status=close(cache_info->file);
444 cache_info->file=(-1);
445 RelinquishMagickResource(FileResource,1);
446 }
cristyf84a1932010-01-03 18:00:18 +0000447 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000448 return(status == -1 ? MagickFalse : MagickTrue);
449}
450
cristy3ed852e2009-09-05 21:47:34 +0000451static inline MagickSizeType MagickMax(const MagickSizeType x,
452 const MagickSizeType y)
453{
454 if (x > y)
455 return(x);
456 return(y);
457}
458
459static inline MagickSizeType MagickMin(const MagickSizeType x,
460 const MagickSizeType y)
461{
462 if (x < y)
463 return(x);
464 return(y);
465}
466
467static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
468 const MapMode mode)
469{
470 int
471 file;
472
473 /*
474 Open pixel cache on disk.
475 */
cristyf84a1932010-01-03 18:00:18 +0000476 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000477 if (cache_info->file != -1)
478 {
cristyf84a1932010-01-03 18:00:18 +0000479 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000480 return(MagickTrue); /* cache already open */
481 }
cristy3ed852e2009-09-05 21:47:34 +0000482 if (*cache_info->cache_filename == '\0')
483 file=AcquireUniqueFileResource(cache_info->cache_filename);
484 else
485 switch (mode)
486 {
487 case ReadMode:
488 {
cristy18c6c272011-09-23 14:40:37 +0000489 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000490 break;
491 }
492 case WriteMode:
493 {
cristy18c6c272011-09-23 14:40:37 +0000494 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
495 O_BINARY | O_EXCL,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000496 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000497 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000498 break;
499 }
500 case IOMode:
501 default:
502 {
cristy18c6c272011-09-23 14:40:37 +0000503 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
cristy3ed852e2009-09-05 21:47:34 +0000504 O_EXCL,S_MODE);
505 if (file == -1)
cristy18c6c272011-09-23 14:40:37 +0000506 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000507 break;
508 }
509 }
510 if (file == -1)
511 {
cristyf84a1932010-01-03 18:00:18 +0000512 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000513 return(MagickFalse);
514 }
515 (void) AcquireMagickResource(FileResource,1);
516 cache_info->file=file;
cristy4d9c1922011-12-31 18:37:34 +0000517 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +0000518 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000519 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000520 return(MagickTrue);
521}
522
523static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
524 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000525 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000526{
527 register MagickOffsetType
528 i;
529
530 ssize_t
531 count;
532
cristy08a88202010-03-04 19:18:05 +0000533 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000534#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000535 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000536 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000537 {
cristyf84a1932010-01-03 18:00:18 +0000538 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000539 return((MagickOffsetType) -1);
540 }
541#endif
542 count=0;
543 for (i=0; i < (MagickOffsetType) length; i+=count)
544 {
545#if !defined(MAGICKCORE_HAVE_PREAD)
546 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
547 (MagickSizeType) SSIZE_MAX));
548#else
549 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000550 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000551#endif
552 if (count > 0)
553 continue;
554 count=0;
555 if (errno != EINTR)
556 {
557 i=(-1);
558 break;
559 }
560 }
561#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563#endif
564 return(i);
565}
566
567static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
568 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000569 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000570{
571 register MagickOffsetType
572 i;
573
574 ssize_t
575 count;
576
cristy08a88202010-03-04 19:18:05 +0000577 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000578#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000579 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000580 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000581 {
cristyf84a1932010-01-03 18:00:18 +0000582 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000583 return((MagickOffsetType) -1);
584 }
585#endif
586 count=0;
587 for (i=0; i < (MagickOffsetType) length; i+=count)
588 {
589#if !defined(MAGICKCORE_HAVE_PWRITE)
590 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
591 (MagickSizeType) SSIZE_MAX));
592#else
593 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000594 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000595#endif
596 if (count > 0)
597 continue;
598 count=0;
599 if (errno != EINTR)
600 {
601 i=(-1);
602 break;
603 }
604 }
605#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607#endif
608 return(i);
609}
610
cristy4c08aed2011-07-01 19:47:50 +0000611static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000612 CacheInfo *cache_info,ExceptionInfo *exception)
613{
614 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000615 count;
cristy3ed852e2009-09-05 21:47:34 +0000616
cristy4c08aed2011-07-01 19:47:50 +0000617 register MagickOffsetType
618 i;
cristye076a6e2010-08-15 19:59:43 +0000619
cristybb503372010-05-27 20:51:26 +0000620 size_t
cristy4c08aed2011-07-01 19:47:50 +0000621 length;
cristy3ed852e2009-09-05 21:47:34 +0000622
cristy4c08aed2011-07-01 19:47:50 +0000623 unsigned char
624 *blob;
625
626 /*
627 Clone pixel cache (both caches on disk).
628 */
cristy3ed852e2009-09-05 21:47:34 +0000629 if (cache_info->debug != MagickFalse)
630 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristya64b85d2011-09-14 01:02:31 +0000631 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000632 sizeof(*blob));
633 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000634 {
cristy4c08aed2011-07-01 19:47:50 +0000635 (void) ThrowMagickException(exception,GetMagickModule(),
636 ResourceLimitError,"MemoryAllocationFailed","`%s'",
637 cache_info->filename);
638 return(MagickFalse);
639 }
cristy3dedf062011-07-02 14:07:40 +0000640 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000641 {
642 blob=(unsigned char *) RelinquishMagickMemory(blob);
643 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
644 cache_info->cache_filename);
645 return(MagickFalse);
646 }
cristy3dedf062011-07-02 14:07:40 +0000647 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000648 {
649 (void) ClosePixelCacheOnDisk(cache_info);
650 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000651 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
652 clone_info->cache_filename);
653 return(MagickFalse);
654 }
cristy4c08aed2011-07-01 19:47:50 +0000655 count=0;
656 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000657 {
cristy4c08aed2011-07-01 19:47:50 +0000658 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
659 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
660 blob);
661 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000662 {
cristy4c08aed2011-07-01 19:47:50 +0000663 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
664 cache_info->cache_filename);
665 break;
cristy3ed852e2009-09-05 21:47:34 +0000666 }
cristy4c08aed2011-07-01 19:47:50 +0000667 length=(size_t) count;
668 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
669 if ((MagickSizeType) count != length)
670 {
671 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
672 clone_info->cache_filename);
673 break;
674 }
675 }
676 (void) ClosePixelCacheOnDisk(clone_info);
677 (void) ClosePixelCacheOnDisk(cache_info);
678 blob=(unsigned char *) RelinquishMagickMemory(blob);
679 if (i < (MagickOffsetType) cache_info->length)
680 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000681 return(MagickTrue);
682}
683
cristyfd24a062012-01-02 14:46:34 +0000684static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000685 CacheInfo *cache_info,ExceptionInfo *exception)
686{
687 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000688 count;
cristy3ed852e2009-09-05 21:47:34 +0000689
cristy4c08aed2011-07-01 19:47:50 +0000690 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000691 {
cristy3ed852e2009-09-05 21:47:34 +0000692 /*
cristy4c08aed2011-07-01 19:47:50 +0000693 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000694 */
cristy4c08aed2011-07-01 19:47:50 +0000695 if (cache_info->debug != MagickFalse)
696 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
697 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
698 cache_info->length);
699 return(MagickTrue);
700 }
701 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
702 {
703 /*
704 Clone pixel cache (one cache on disk, one in memory).
705 */
706 if (cache_info->debug != MagickFalse)
707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
708 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000709 {
cristy4c08aed2011-07-01 19:47:50 +0000710 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000711 cache_info->cache_filename);
712 return(MagickFalse);
713 }
cristy4c08aed2011-07-01 19:47:50 +0000714 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
715 cache_info->length,(unsigned char *) clone_info->pixels);
716 (void) ClosePixelCacheOnDisk(cache_info);
717 if ((MagickSizeType) count != cache_info->length)
718 {
719 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
720 cache_info->cache_filename);
721 return(MagickFalse);
722 }
723 return(MagickTrue);
724 }
725 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
726 {
727 /*
728 Clone pixel cache (one cache on disk, one in memory).
729 */
730 if (clone_info->debug != MagickFalse)
731 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
732 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
733 {
734 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
735 clone_info->cache_filename);
736 return(MagickFalse);
737 }
738 count=WritePixelCacheRegion(clone_info,clone_info->offset,
739 clone_info->length,(unsigned char *) cache_info->pixels);
740 (void) ClosePixelCacheOnDisk(clone_info);
741 if ((MagickSizeType) count != clone_info->length)
742 {
743 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
744 clone_info->cache_filename);
745 return(MagickFalse);
746 }
747 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000748 }
749 /*
cristy4c08aed2011-07-01 19:47:50 +0000750 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000751 */
cristy4c08aed2011-07-01 19:47:50 +0000752 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000753}
754
cristyfd24a062012-01-02 14:46:34 +0000755static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000756 CacheInfo *cache_info,ExceptionInfo *exception)
757{
cristy4c08aed2011-07-01 19:47:50 +0000758 MagickBooleanType
759 status;
cristy3ed852e2009-09-05 21:47:34 +0000760
cristy4c08aed2011-07-01 19:47:50 +0000761 MagickOffsetType
762 cache_offset,
763 clone_offset,
764 count;
765
766 register ssize_t
767 x;
768
cristyfd24a062012-01-02 14:46:34 +0000769 register unsigned char
770 *p;
771
cristy4c08aed2011-07-01 19:47:50 +0000772 size_t
cristy3ed852e2009-09-05 21:47:34 +0000773 length;
774
cristy4c08aed2011-07-01 19:47:50 +0000775 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000776 y;
777
cristy4c08aed2011-07-01 19:47:50 +0000778 unsigned char
779 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000780
cristy4c08aed2011-07-01 19:47:50 +0000781 /*
782 Clone pixel cache (unoptimized).
783 */
cristy3ed852e2009-09-05 21:47:34 +0000784 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000785 {
cristy4c08aed2011-07-01 19:47:50 +0000786 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
787 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
788 else
789 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
791 else
792 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
794 else
795 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
796 }
cristyed231572011-07-14 02:18:59 +0000797 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
798 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000799 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristya64b85d2011-09-14 01:02:31 +0000800 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000801 if (blob == (unsigned char *) NULL)
802 {
803 (void) ThrowMagickException(exception,GetMagickModule(),
804 ResourceLimitError,"MemoryAllocationFailed","`%s'",
805 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000806 return(MagickFalse);
807 }
cristy4c08aed2011-07-01 19:47:50 +0000808 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
809 cache_offset=0;
810 clone_offset=0;
811 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000812 {
cristy4c08aed2011-07-01 19:47:50 +0000813 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000814 {
cristy4c08aed2011-07-01 19:47:50 +0000815 blob=(unsigned char *) RelinquishMagickMemory(blob);
816 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000817 cache_info->cache_filename);
818 return(MagickFalse);
819 }
cristy4c08aed2011-07-01 19:47:50 +0000820 cache_offset=cache_info->offset;
821 }
822 if (clone_info->type == DiskCache)
823 {
cristy3dedf062011-07-02 14:07:40 +0000824 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000825 {
cristy4c08aed2011-07-01 19:47:50 +0000826 blob=(unsigned char *) RelinquishMagickMemory(blob);
827 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
828 clone_info->cache_filename);
829 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000830 }
cristy4c08aed2011-07-01 19:47:50 +0000831 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000832 }
833 /*
cristy4c08aed2011-07-01 19:47:50 +0000834 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000835 */
cristy4c08aed2011-07-01 19:47:50 +0000836 status=MagickTrue;
cristyfd24a062012-01-02 14:46:34 +0000837 p=blob;
cristy4c08aed2011-07-01 19:47:50 +0000838 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000839 {
cristy4c08aed2011-07-01 19:47:50 +0000840 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000841 {
cristy9e0719b2011-12-29 03:45:45 +0000842 register ssize_t
843 i;
844
cristy3ed852e2009-09-05 21:47:34 +0000845 /*
cristy4c08aed2011-07-01 19:47:50 +0000846 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000847 */
cristyed231572011-07-14 02:18:59 +0000848 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000849 if (cache_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000850 p=(unsigned char *) cache_info->pixels+cache_offset;
cristy3ed852e2009-09-05 21:47:34 +0000851 else
852 {
cristyfd24a062012-01-02 14:46:34 +0000853 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
cristy4c08aed2011-07-01 19:47:50 +0000854 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +0000855 {
cristy4c08aed2011-07-01 19:47:50 +0000856 status=MagickFalse;
857 break;
cristy3ed852e2009-09-05 21:47:34 +0000858 }
859 }
cristy4c08aed2011-07-01 19:47:50 +0000860 cache_offset+=length;
861 if ((y < (ssize_t) clone_info->rows) &&
862 (x < (ssize_t) clone_info->columns))
cristy9e0719b2011-12-29 03:45:45 +0000863 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000864 {
cristy9e0719b2011-12-29 03:45:45 +0000865 PixelChannel
866 channel;
867
868 PixelTrait
869 traits;
870
871 ssize_t
872 offset;
873
cristy4c08aed2011-07-01 19:47:50 +0000874 /*
cristy3b8fe922011-12-29 18:56:23 +0000875 Write a set of pixel channels.
cristy4c08aed2011-07-01 19:47:50 +0000876 */
cristy9e0719b2011-12-29 03:45:45 +0000877 channel=clone_info->channel_map[i].channel;
878 traits=cache_info->channel_map[channel].traits;
879 if (traits == UndefinedPixelTrait)
880 {
cristy0f4425e2011-12-31 20:33:02 +0000881 clone_offset+=sizeof(Quantum);
882 continue;
cristy9e0719b2011-12-29 03:45:45 +0000883 }
cristy0f4425e2011-12-31 20:33:02 +0000884 offset=cache_info->channel_map[channel].offset;
885 if (clone_info->type != DiskCache)
cristyfd24a062012-01-02 14:46:34 +0000886 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
887 offset*sizeof(Quantum),sizeof(Quantum));
cristy4c08aed2011-07-01 19:47:50 +0000888 else
889 {
cristy0f4425e2011-12-31 20:33:02 +0000890 count=WritePixelCacheRegion(clone_info,clone_offset,
cristyfd24a062012-01-02 14:46:34 +0000891 sizeof(Quantum),p+offset*sizeof(Quantum));
cristy0f4425e2011-12-31 20:33:02 +0000892 if ((MagickSizeType) count != sizeof(Quantum))
cristy4c08aed2011-07-01 19:47:50 +0000893 {
cristy0f4425e2011-12-31 20:33:02 +0000894 status=MagickFalse;
895 break;
cristy4c08aed2011-07-01 19:47:50 +0000896 }
897 }
cristy9e0719b2011-12-29 03:45:45 +0000898 clone_offset+=sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +0000899 }
900 }
cristyed231572011-07-14 02:18:59 +0000901 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +0000902 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
903 for ( ; x < (ssize_t) clone_info->columns; x++)
904 {
905 /*
cristy9e0719b2011-12-29 03:45:45 +0000906 Set remaining columns as undefined.
cristy4c08aed2011-07-01 19:47:50 +0000907 */
908 if (clone_info->type != DiskCache)
909 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
910 length);
911 else
912 {
913 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
914 if ((MagickSizeType) count != length)
915 {
916 status=MagickFalse;
917 break;
918 }
919 }
920 clone_offset+=length;
921 }
922 }
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 }
1017 length=clone_info->metacontent_extent;
1018 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1019 for ( ; y < (ssize_t) clone_info->rows; y++)
1020 {
1021 /*
cristy9e0719b2011-12-29 03:45:45 +00001022 Set remaining rows as undefined.
cristy4c08aed2011-07-01 19:47:50 +00001023 */
1024 for (x=0; x < (ssize_t) clone_info->columns; x++)
1025 {
1026 if (clone_info->type != DiskCache)
1027 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1028 blob,length);
1029 else
1030 {
1031 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1032 if ((MagickSizeType) count != length)
1033 {
1034 status=MagickFalse;
1035 break;
1036 }
1037 }
1038 clone_offset+=length;
1039 }
1040 }
1041 }
1042 if (clone_info->type == DiskCache)
1043 (void) ClosePixelCacheOnDisk(clone_info);
1044 if (cache_info->type == DiskCache)
1045 (void) ClosePixelCacheOnDisk(cache_info);
1046 blob=(unsigned char *) RelinquishMagickMemory(blob);
1047 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001048}
1049
1050static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1051 CacheInfo *cache_info,ExceptionInfo *exception)
1052{
cristy3dfccb22011-12-28 21:47:20 +00001053 PixelChannelMap
1054 *p,
1055 *q;
1056
cristy5a7fbfb2010-11-06 16:10:59 +00001057 if (cache_info->type == PingCache)
1058 return(MagickTrue);
cristy3dfccb22011-12-28 21:47:20 +00001059 p=cache_info->channel_map;
1060 q=clone_info->channel_map;
cristy4c08aed2011-07-01 19:47:50 +00001061 if ((cache_info->columns == clone_info->columns) &&
1062 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001063 (cache_info->number_channels == clone_info->number_channels) &&
cristy3dfccb22011-12-28 21:47:20 +00001064 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
cristy4c08aed2011-07-01 19:47:50 +00001065 (cache_info->metacontent_extent == clone_info->metacontent_extent))
cristyfd24a062012-01-02 14:46:34 +00001066 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1067 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001068}
1069
1070/*
1071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072% %
1073% %
1074% %
1075+ C l o n e P i x e l C a c h e M e t h o d s %
1076% %
1077% %
1078% %
1079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080%
1081% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1082% another.
1083%
1084% The format of the ClonePixelCacheMethods() method is:
1085%
1086% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1087%
1088% A description of each parameter follows:
1089%
1090% o clone: Specifies a pointer to a Cache structure.
1091%
1092% o cache: the pixel cache.
1093%
1094*/
cristya6577ff2011-09-02 19:54:26 +00001095MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001096{
1097 CacheInfo
1098 *cache_info,
1099 *source_info;
1100
1101 assert(clone != (Cache) NULL);
1102 source_info=(CacheInfo *) clone;
1103 assert(source_info->signature == MagickSignature);
1104 if (source_info->debug != MagickFalse)
1105 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1106 source_info->filename);
1107 assert(cache != (Cache) NULL);
1108 cache_info=(CacheInfo *) cache;
1109 assert(cache_info->signature == MagickSignature);
1110 source_info->methods=cache_info->methods;
1111}
1112
1113/*
1114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115% %
1116% %
1117% %
1118+ D e s t r o y I m a g e P i x e l C a c h e %
1119% %
1120% %
1121% %
1122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1123%
1124% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1125%
1126% The format of the DestroyImagePixelCache() method is:
1127%
1128% void DestroyImagePixelCache(Image *image)
1129%
1130% A description of each parameter follows:
1131%
1132% o image: the image.
1133%
1134*/
1135static void DestroyImagePixelCache(Image *image)
1136{
1137 assert(image != (Image *) NULL);
1138 assert(image->signature == MagickSignature);
1139 if (image->debug != MagickFalse)
1140 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1141 if (image->cache == (void *) NULL)
1142 return;
1143 image->cache=DestroyPixelCache(image->cache);
1144}
1145
1146/*
1147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1148% %
1149% %
1150% %
1151+ D e s t r o y I m a g e P i x e l s %
1152% %
1153% %
1154% %
1155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156%
1157% DestroyImagePixels() deallocates memory associated with the pixel cache.
1158%
1159% The format of the DestroyImagePixels() method is:
1160%
1161% void DestroyImagePixels(Image *image)
1162%
1163% A description of each parameter follows:
1164%
1165% o image: the image.
1166%
1167*/
1168MagickExport void DestroyImagePixels(Image *image)
1169{
1170 CacheInfo
1171 *cache_info;
1172
1173 assert(image != (const Image *) NULL);
1174 assert(image->signature == MagickSignature);
1175 if (image->debug != MagickFalse)
1176 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1177 assert(image->cache != (Cache) NULL);
1178 cache_info=(CacheInfo *) image->cache;
1179 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001180 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1181 {
1182 cache_info->methods.destroy_pixel_handler(image);
1183 return;
1184 }
cristy2036f5c2010-09-19 21:18:17 +00001185 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001186}
1187
1188/*
1189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1190% %
1191% %
1192% %
1193+ D e s t r o y P i x e l C a c h e %
1194% %
1195% %
1196% %
1197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198%
1199% DestroyPixelCache() deallocates memory associated with the pixel cache.
1200%
1201% The format of the DestroyPixelCache() method is:
1202%
1203% Cache DestroyPixelCache(Cache cache)
1204%
1205% A description of each parameter follows:
1206%
1207% o cache: the pixel cache.
1208%
1209*/
1210
1211static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1212{
1213 switch (cache_info->type)
1214 {
1215 case MemoryCache:
1216 {
1217 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001218 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001219 cache_info->pixels);
1220 else
cristy4c08aed2011-07-01 19:47:50 +00001221 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001222 (size_t) cache_info->length);
1223 RelinquishMagickResource(MemoryResource,cache_info->length);
1224 break;
1225 }
1226 case MapCache:
1227 {
cristy4c08aed2011-07-01 19:47:50 +00001228 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001229 cache_info->length);
1230 RelinquishMagickResource(MapResource,cache_info->length);
1231 }
1232 case DiskCache:
1233 {
1234 if (cache_info->file != -1)
1235 (void) ClosePixelCacheOnDisk(cache_info);
1236 RelinquishMagickResource(DiskResource,cache_info->length);
1237 break;
1238 }
1239 default:
1240 break;
1241 }
1242 cache_info->type=UndefinedCache;
1243 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001244 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001245}
1246
cristya6577ff2011-09-02 19:54:26 +00001247MagickPrivate Cache DestroyPixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00001248{
1249 CacheInfo
1250 *cache_info;
1251
cristy3ed852e2009-09-05 21:47:34 +00001252 assert(cache != (Cache) NULL);
1253 cache_info=(CacheInfo *) cache;
1254 assert(cache_info->signature == MagickSignature);
1255 if (cache_info->debug != MagickFalse)
1256 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1257 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001258 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001259 cache_info->reference_count--;
1260 if (cache_info->reference_count != 0)
1261 {
cristyf84a1932010-01-03 18:00:18 +00001262 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001263 return((Cache) NULL);
1264 }
cristyf84a1932010-01-03 18:00:18 +00001265 UnlockSemaphoreInfo(cache_info->semaphore);
cristy5b8de732009-09-10 23:50:40 +00001266 if (cache_info->debug != MagickFalse)
1267 {
1268 char
1269 message[MaxTextExtent];
1270
cristyb51dff52011-05-19 16:55:47 +00001271 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001272 cache_info->filename);
1273 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1274 }
cristyc2e1bdd2009-09-10 23:43:34 +00001275 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1276 (cache_info->type != DiskCache)))
1277 RelinquishPixelCachePixels(cache_info);
1278 else
1279 {
1280 RelinquishPixelCachePixels(cache_info);
1281 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1282 }
cristy3ed852e2009-09-05 21:47:34 +00001283 *cache_info->cache_filename='\0';
1284 if (cache_info->nexus_info != (NexusInfo **) NULL)
1285 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1286 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001287 if (cache_info->random_info != (RandomInfo *) NULL)
1288 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001289 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1290 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1291 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1292 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001293 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001294 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001295 cache=(Cache) NULL;
1296 return(cache);
1297}
1298
1299/*
1300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301% %
1302% %
1303% %
1304+ D e s t r o y P i x e l C a c h e N e x u s %
1305% %
1306% %
1307% %
1308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309%
1310% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1311%
1312% The format of the DestroyPixelCacheNexus() method is:
1313%
1314% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001315% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001316%
1317% A description of each parameter follows:
1318%
1319% o nexus_info: the nexus to destroy.
1320%
1321% o number_threads: the number of nexus threads.
1322%
1323*/
1324
1325static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1326{
1327 if (nexus_info->mapped == MagickFalse)
cristy64c3edf2012-04-13 18:50:13 +00001328 (void) RelinquishMagickMemory(nexus_info->cache);
cristy3ed852e2009-09-05 21:47:34 +00001329 else
1330 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001331 nexus_info->cache=(Quantum *) NULL;
1332 nexus_info->pixels=(Quantum *) NULL;
1333 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001334 nexus_info->length=0;
1335 nexus_info->mapped=MagickFalse;
1336}
1337
cristya6577ff2011-09-02 19:54:26 +00001338MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001339 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001340{
cristybb503372010-05-27 20:51:26 +00001341 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001342 i;
1343
1344 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001345 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001346 {
cristy4c08aed2011-07-01 19:47:50 +00001347 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001348 RelinquishCacheNexusPixels(nexus_info[i]);
1349 nexus_info[i]->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001350 }
cristye5f87c82012-02-14 12:44:17 +00001351 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
cristy64c3edf2012-04-13 18:50:13 +00001352 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001353 return(nexus_info);
1354}
1355
1356/*
1357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1358% %
1359% %
1360% %
cristy4c08aed2011-07-01 19:47:50 +00001361% 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 +00001362% %
1363% %
1364% %
1365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366%
cristy4c08aed2011-07-01 19:47:50 +00001367% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1368% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1369% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001370%
cristy4c08aed2011-07-01 19:47:50 +00001371% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001372%
cristy4c08aed2011-07-01 19:47:50 +00001373% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001374%
1375% A description of each parameter follows:
1376%
1377% o image: the image.
1378%
1379*/
cristy4c08aed2011-07-01 19:47:50 +00001380MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001381{
1382 CacheInfo
1383 *cache_info;
1384
cristy5c9e6f22010-09-17 17:31:01 +00001385 const int
1386 id = GetOpenMPThreadId();
1387
cristy4c08aed2011-07-01 19:47:50 +00001388 void
1389 *metacontent;
1390
cristye7cc7cf2010-09-21 13:26:47 +00001391 assert(image != (const Image *) NULL);
1392 assert(image->signature == MagickSignature);
1393 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001394 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001395 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001396 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1397 (GetAuthenticMetacontentFromHandler) NULL)
1398 {
1399 metacontent=cache_info->methods.
1400 get_authentic_metacontent_from_handler(image);
1401 return(metacontent);
1402 }
cristy6ebe97c2010-07-03 01:17:28 +00001403 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001404 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1405 cache_info->nexus_info[id]);
1406 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001407}
1408
1409/*
1410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411% %
1412% %
1413% %
cristy4c08aed2011-07-01 19:47:50 +00001414+ 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 +00001415% %
1416% %
1417% %
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419%
cristy4c08aed2011-07-01 19:47:50 +00001420% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1421% with the last call to QueueAuthenticPixelsCache() or
1422% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001423%
cristy4c08aed2011-07-01 19:47:50 +00001424% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001425%
cristy4c08aed2011-07-01 19:47:50 +00001426% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001427%
1428% A description of each parameter follows:
1429%
1430% o image: the image.
1431%
1432*/
cristy4c08aed2011-07-01 19:47:50 +00001433static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001434{
1435 CacheInfo
1436 *cache_info;
1437
cristy2036f5c2010-09-19 21:18:17 +00001438 const int
1439 id = GetOpenMPThreadId();
1440
cristy4c08aed2011-07-01 19:47:50 +00001441 void
1442 *metacontent;
1443
cristy3ed852e2009-09-05 21:47:34 +00001444 assert(image != (const Image *) NULL);
1445 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001446 assert(image->cache != (Cache) NULL);
1447 cache_info=(CacheInfo *) image->cache;
1448 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001449 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001450 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1451 cache_info->nexus_info[id]);
1452 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001453}
1454
1455/*
1456%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457% %
1458% %
1459% %
1460+ 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 %
1461% %
1462% %
1463% %
1464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465%
1466% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1467% disk pixel cache as defined by the geometry parameters. A pointer to the
1468% pixels is returned if the pixels are transferred, otherwise a NULL is
1469% returned.
1470%
1471% The format of the GetAuthenticPixelCacheNexus() method is:
1472%
cristy4c08aed2011-07-01 19:47:50 +00001473% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001474% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001475% NexusInfo *nexus_info,ExceptionInfo *exception)
1476%
1477% A description of each parameter follows:
1478%
1479% o image: the image.
1480%
1481% o x,y,columns,rows: These values define the perimeter of a region of
1482% pixels.
1483%
1484% o nexus_info: the cache nexus to return.
1485%
1486% o exception: return any errors or warnings in this structure.
1487%
1488*/
1489
cristy4c08aed2011-07-01 19:47:50 +00001490static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001491 NexusInfo *nexus_info)
1492{
cristy4c08aed2011-07-01 19:47:50 +00001493 MagickBooleanType
1494 status;
1495
cristy3ed852e2009-09-05 21:47:34 +00001496 MagickOffsetType
1497 offset;
1498
cristy73724512010-04-12 14:43:14 +00001499 if (cache_info->type == PingCache)
1500 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001501 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1502 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001503 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001504 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001505 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001506}
1507
cristya6577ff2011-09-02 19:54:26 +00001508MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001509 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001510 NexusInfo *nexus_info,ExceptionInfo *exception)
1511{
1512 CacheInfo
1513 *cache_info;
1514
cristy4c08aed2011-07-01 19:47:50 +00001515 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001516 *q;
cristy3ed852e2009-09-05 21:47:34 +00001517
1518 /*
1519 Transfer pixels from the cache.
1520 */
1521 assert(image != (Image *) NULL);
1522 assert(image->signature == MagickSignature);
cristyc11dace2012-01-24 16:39:46 +00001523 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1524 exception);
cristyacd2ed22011-08-30 01:44:23 +00001525 if (q == (Quantum *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001526 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001527 cache_info=(CacheInfo *) image->cache;
1528 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001529 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00001530 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001531 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001532 return((Quantum *) NULL);
1533 if (cache_info->metacontent_extent != 0)
1534 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1535 return((Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00001536 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001537}
1538
1539/*
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541% %
1542% %
1543% %
1544+ 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 %
1545% %
1546% %
1547% %
1548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549%
1550% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1551% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1552%
1553% The format of the GetAuthenticPixelsFromCache() method is:
1554%
cristy4c08aed2011-07-01 19:47:50 +00001555% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001556%
1557% A description of each parameter follows:
1558%
1559% o image: the image.
1560%
1561*/
cristy4c08aed2011-07-01 19:47:50 +00001562static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001563{
1564 CacheInfo
1565 *cache_info;
1566
cristy5c9e6f22010-09-17 17:31:01 +00001567 const int
1568 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001569
cristye7cc7cf2010-09-21 13:26:47 +00001570 assert(image != (const Image *) NULL);
1571 assert(image->signature == MagickSignature);
1572 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001573 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001574 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001575 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001576 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001577}
1578
1579/*
1580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581% %
1582% %
1583% %
1584% G e t A u t h e n t i c P i x e l Q u e u e %
1585% %
1586% %
1587% %
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589%
cristy4c08aed2011-07-01 19:47:50 +00001590% GetAuthenticPixelQueue() returns the authentic pixels associated
1591% corresponding with the last call to QueueAuthenticPixels() or
1592% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001593%
1594% The format of the GetAuthenticPixelQueue() method is:
1595%
cristy4c08aed2011-07-01 19:47:50 +00001596% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001597%
1598% A description of each parameter follows:
1599%
1600% o image: the image.
1601%
1602*/
cristy4c08aed2011-07-01 19:47:50 +00001603MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001604{
1605 CacheInfo
1606 *cache_info;
1607
cristy2036f5c2010-09-19 21:18:17 +00001608 const int
1609 id = GetOpenMPThreadId();
1610
cristy3ed852e2009-09-05 21:47:34 +00001611 assert(image != (const Image *) NULL);
1612 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001613 assert(image->cache != (Cache) NULL);
1614 cache_info=(CacheInfo *) image->cache;
1615 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001616 if (cache_info->methods.get_authentic_pixels_from_handler !=
1617 (GetAuthenticPixelsFromHandler) NULL)
1618 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001619 assert(id < (int) cache_info->number_threads);
1620 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001621}
1622
1623/*
1624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625% %
1626% %
1627% %
1628% G e t A u t h e n t i c P i x e l s %
1629% %
1630% %
cristy4c08aed2011-07-01 19:47:50 +00001631% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001632%
1633% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001634% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001635% representing the region is returned, otherwise NULL is returned.
1636%
1637% The returned pointer may point to a temporary working copy of the pixels
1638% or it may point to the original pixels in memory. Performance is maximized
1639% if the selected region is part of one row, or one or more full rows, since
1640% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001641% if the image is in memory, or in a memory-mapped file. The returned pointer
1642% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001643%
1644% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001645% Quantum. If the image has corresponding metacontent,call
1646% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1647% meta-content corresponding to the region. Once the Quantum array has
1648% been updated, the changes must be saved back to the underlying image using
1649% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001650%
1651% The format of the GetAuthenticPixels() method is:
1652%
cristy4c08aed2011-07-01 19:47:50 +00001653% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001654% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001655% ExceptionInfo *exception)
1656%
1657% A description of each parameter follows:
1658%
1659% o image: the image.
1660%
1661% o x,y,columns,rows: These values define the perimeter of a region of
1662% pixels.
1663%
1664% o exception: return any errors or warnings in this structure.
1665%
1666*/
cristy4c08aed2011-07-01 19:47:50 +00001667MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001668 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001669 ExceptionInfo *exception)
1670{
1671 CacheInfo
1672 *cache_info;
1673
cristy2036f5c2010-09-19 21:18:17 +00001674 const int
1675 id = GetOpenMPThreadId();
1676
cristy4c08aed2011-07-01 19:47:50 +00001677 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001678 *q;
cristy4c08aed2011-07-01 19:47:50 +00001679
cristy3ed852e2009-09-05 21:47:34 +00001680 assert(image != (Image *) NULL);
1681 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001682 assert(image->cache != (Cache) NULL);
1683 cache_info=(CacheInfo *) image->cache;
1684 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001685 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001686 (GetAuthenticPixelsHandler) NULL)
1687 {
cristyacd2ed22011-08-30 01:44:23 +00001688 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1689 exception);
1690 return(q);
cristy4c08aed2011-07-01 19:47:50 +00001691 }
cristy2036f5c2010-09-19 21:18:17 +00001692 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001693 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001694 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001695 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001696}
1697
1698/*
1699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1700% %
1701% %
1702% %
1703+ G e t A u t h e n t i c P i x e l s C a c h e %
1704% %
1705% %
1706% %
1707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708%
1709% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1710% as defined by the geometry parameters. A pointer to the pixels is returned
1711% if the pixels are transferred, otherwise a NULL is returned.
1712%
1713% The format of the GetAuthenticPixelsCache() method is:
1714%
cristy4c08aed2011-07-01 19:47:50 +00001715% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001716% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001717% ExceptionInfo *exception)
1718%
1719% A description of each parameter follows:
1720%
1721% o image: the image.
1722%
1723% o x,y,columns,rows: These values define the perimeter of a region of
1724% pixels.
1725%
1726% o exception: return any errors or warnings in this structure.
1727%
1728*/
cristy4c08aed2011-07-01 19:47:50 +00001729static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001730 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001731 ExceptionInfo *exception)
1732{
1733 CacheInfo
1734 *cache_info;
1735
cristy5c9e6f22010-09-17 17:31:01 +00001736 const int
1737 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001738
cristy4c08aed2011-07-01 19:47:50 +00001739 Quantum
cristyacd2ed22011-08-30 01:44:23 +00001740 *q;
cristy4c08aed2011-07-01 19:47:50 +00001741
cristye7cc7cf2010-09-21 13:26:47 +00001742 assert(image != (const Image *) NULL);
1743 assert(image->signature == MagickSignature);
1744 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001745 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001746 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001747 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001748 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001749 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00001750 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00001751 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00001752 return(q);
cristy3ed852e2009-09-05 21:47:34 +00001753}
1754
1755/*
1756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1757% %
1758% %
1759% %
1760+ G e t I m a g e E x t e n t %
1761% %
1762% %
1763% %
1764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765%
cristy4c08aed2011-07-01 19:47:50 +00001766% GetImageExtent() returns the extent of the pixels associated corresponding
1767% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001768%
1769% The format of the GetImageExtent() method is:
1770%
1771% MagickSizeType GetImageExtent(const Image *image)
1772%
1773% A description of each parameter follows:
1774%
1775% o image: the image.
1776%
1777*/
1778MagickExport MagickSizeType GetImageExtent(const Image *image)
1779{
1780 CacheInfo
1781 *cache_info;
1782
cristy5c9e6f22010-09-17 17:31:01 +00001783 const int
1784 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001785
cristy3ed852e2009-09-05 21:47:34 +00001786 assert(image != (Image *) NULL);
1787 assert(image->signature == MagickSignature);
1788 if (image->debug != MagickFalse)
1789 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1790 assert(image->cache != (Cache) NULL);
1791 cache_info=(CacheInfo *) image->cache;
1792 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001793 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001794 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001795}
1796
1797/*
1798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1799% %
1800% %
1801% %
1802+ G e t I m a g e P i x e l C a c h e %
1803% %
1804% %
1805% %
1806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807%
1808% GetImagePixelCache() ensures that there is only a single reference to the
1809% pixel cache to be modified, updating the provided cache pointer to point to
1810% a clone of the original pixel cache if necessary.
1811%
1812% The format of the GetImagePixelCache method is:
1813%
1814% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1815% ExceptionInfo *exception)
1816%
1817% A description of each parameter follows:
1818%
1819% o image: the image.
1820%
1821% o clone: any value other than MagickFalse clones the cache pixels.
1822%
1823% o exception: return any errors or warnings in this structure.
1824%
1825*/
cristyaf894d72011-08-06 23:03:10 +00001826
cristy3ed852e2009-09-05 21:47:34 +00001827static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1828{
1829 CacheInfo
1830 *cache_info;
1831
cristy9e0719b2011-12-29 03:45:45 +00001832 PixelChannelMap
1833 *p,
1834 *q;
1835
cristy3ed852e2009-09-05 21:47:34 +00001836 /*
1837 Does the image match the pixel cache morphology?
1838 */
1839 cache_info=(CacheInfo *) image->cache;
cristy9e0719b2011-12-29 03:45:45 +00001840 p=image->channel_map;
1841 q=cache_info->channel_map;
cristy3ed852e2009-09-05 21:47:34 +00001842 if ((image->storage_class != cache_info->storage_class) ||
1843 (image->colorspace != cache_info->colorspace) ||
cristy222b19c2011-08-04 01:35:11 +00001844 (image->matte != cache_info->matte) ||
cristy183a5c72012-01-30 01:40:35 +00001845 (image->mask != cache_info->mask) ||
cristy3ed852e2009-09-05 21:47:34 +00001846 (image->columns != cache_info->columns) ||
1847 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001848 (image->number_channels != cache_info->number_channels) ||
cristy9e0719b2011-12-29 03:45:45 +00001849 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
cristy4c08aed2011-07-01 19:47:50 +00001850 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001851 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1852 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1853 return(MagickFalse);
1854 return(MagickTrue);
1855}
1856
cristycd01fae2011-08-06 23:52:42 +00001857static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1858 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001859{
1860 CacheInfo
1861 *cache_info;
1862
cristy3ed852e2009-09-05 21:47:34 +00001863 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001864 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001865 status;
1866
cristy50a10922010-02-15 18:35:25 +00001867 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001868 cpu_throttle = 0,
1869 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001870 time_limit = 0;
1871
cristy1ea34962010-07-01 19:49:21 +00001872 static time_t
cristy208b1002011-08-07 18:51:50 +00001873 cache_timestamp = 0;
cristy1ea34962010-07-01 19:49:21 +00001874
cristyc4f9f132010-03-04 18:50:01 +00001875 status=MagickTrue;
1876 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00001877 if (cpu_throttle == 0)
1878 {
1879 char
1880 *limit;
1881
1882 /*
1883 Set CPU throttle in milleseconds.
1884 */
1885 cpu_throttle=MagickResourceInfinity;
1886 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1887 if (limit == (char *) NULL)
1888 limit=GetPolicyValue("throttle");
1889 if (limit != (char *) NULL)
1890 {
1891 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1892 limit=DestroyString(limit);
1893 }
1894 }
1895 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1896 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00001897 if (time_limit == 0)
1898 {
cristy6ebe97c2010-07-03 01:17:28 +00001899 /*
1900 Set the exire time in seconds.
1901 */
cristy1ea34962010-07-01 19:49:21 +00001902 time_limit=GetMagickResourceLimit(TimeResource);
cristy208b1002011-08-07 18:51:50 +00001903 cache_timestamp=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00001904 }
1905 if ((time_limit != MagickResourceInfinity) &&
cristy208b1002011-08-07 18:51:50 +00001906 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00001907 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00001908 assert(image->cache != (Cache) NULL);
1909 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00001910 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00001911 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001912 {
cristyceb55ee2010-11-06 16:05:49 +00001913 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00001914 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00001915 {
cristyceb55ee2010-11-06 16:05:49 +00001916 Image
1917 clone_image;
1918
1919 CacheInfo
1920 *clone_info;
1921
1922 /*
1923 Clone pixel cache.
1924 */
1925 clone_image=(*image);
1926 clone_image.semaphore=AllocateSemaphoreInfo();
1927 clone_image.reference_count=1;
1928 clone_image.cache=ClonePixelCache(cache_info);
1929 clone_info=(CacheInfo *) clone_image.cache;
1930 status=OpenPixelCache(&clone_image,IOMode,exception);
1931 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001932 {
cristy5a7fbfb2010-11-06 16:10:59 +00001933 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00001934 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001935 if (status != MagickFalse)
1936 {
cristy979bf772011-08-08 00:04:15 +00001937 if (cache_info->mode == ReadMode)
1938 cache_info->nexus_info=(NexusInfo **) NULL;
cristyceb55ee2010-11-06 16:05:49 +00001939 destroy=MagickTrue;
1940 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00001941 }
1942 }
cristyceb55ee2010-11-06 16:05:49 +00001943 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001944 }
cristyceb55ee2010-11-06 16:05:49 +00001945 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001946 }
cristy4320e0e2009-09-10 15:00:08 +00001947 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00001948 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001949 if (status != MagickFalse)
1950 {
1951 /*
1952 Ensure the image matches the pixel cache morphology.
1953 */
1954 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00001955 image->type=UndefinedType;
cristy3ed852e2009-09-05 21:47:34 +00001956 if (ValidatePixelCacheMorphology(image) == MagickFalse)
cristyc11dace2012-01-24 16:39:46 +00001957 {
1958 status=OpenPixelCache(image,IOMode,exception);
1959 cache_info=(CacheInfo *) image->cache;
1960 if (cache_info->type == DiskCache)
1961 (void) ClosePixelCacheOnDisk(cache_info);
1962 }
cristy3ed852e2009-09-05 21:47:34 +00001963 }
cristyf84a1932010-01-03 18:00:18 +00001964 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001965 if (status == MagickFalse)
1966 return((Cache) NULL);
1967 return(image->cache);
1968}
1969
1970/*
1971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1972% %
1973% %
1974% %
1975% G e t O n e A u t h e n t i c P i x e l %
1976% %
1977% %
1978% %
1979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980%
1981% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1982% location. The image background color is returned if an error occurs.
1983%
1984% The format of the GetOneAuthenticPixel() method is:
1985%
cristybb503372010-05-27 20:51:26 +00001986% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00001987% const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001988%
1989% A description of each parameter follows:
1990%
1991% o image: the image.
1992%
1993% o x,y: These values define the location of the pixel to return.
1994%
1995% o pixel: return a pixel at the specified (x,y) location.
1996%
1997% o exception: return any errors or warnings in this structure.
1998%
1999*/
cristyacbbb7c2010-06-30 18:56:48 +00002000MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002001 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002002{
2003 CacheInfo
2004 *cache_info;
2005
cristy4c08aed2011-07-01 19:47:50 +00002006 register Quantum
2007 *q;
cristy2036f5c2010-09-19 21:18:17 +00002008
cristy2ed42f62011-10-02 19:49:57 +00002009 register ssize_t
2010 i;
2011
cristy3ed852e2009-09-05 21:47:34 +00002012 assert(image != (Image *) NULL);
2013 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002014 assert(image->cache != (Cache) NULL);
2015 cache_info=(CacheInfo *) image->cache;
2016 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002017 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002018 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2019 (GetOneAuthenticPixelFromHandler) NULL)
2020 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2021 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002022 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2023 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002024 {
cristy9e0719b2011-12-29 03:45:45 +00002025 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2026 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2027 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2028 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2029 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002030 return(MagickFalse);
2031 }
2032 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2033 {
2034 PixelChannel
2035 channel;
2036
cristye2a912b2011-12-05 20:02:07 +00002037 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002038 pixel[channel]=q[i];
2039 }
cristy2036f5c2010-09-19 21:18:17 +00002040 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002041}
2042
2043/*
2044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2045% %
2046% %
2047% %
2048+ 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 %
2049% %
2050% %
2051% %
2052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2053%
2054% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2055% location. The image background color is returned if an error occurs.
2056%
2057% The format of the GetOneAuthenticPixelFromCache() method is:
2058%
2059% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy2ed42f62011-10-02 19:49:57 +00002060% const ssize_t x,const ssize_t y,Quantum *pixel,
cristy5f959472010-05-27 22:19:46 +00002061% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002062%
2063% A description of each parameter follows:
2064%
2065% o image: the image.
2066%
2067% o x,y: These values define the location of the pixel to return.
2068%
2069% o pixel: return a pixel at the specified (x,y) location.
2070%
2071% o exception: return any errors or warnings in this structure.
2072%
2073*/
2074static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002075 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002076{
cristy098f78c2010-09-23 17:28:44 +00002077 CacheInfo
2078 *cache_info;
2079
2080 const int
2081 id = GetOpenMPThreadId();
2082
cristy4c08aed2011-07-01 19:47:50 +00002083 register Quantum
2084 *q;
cristy3ed852e2009-09-05 21:47:34 +00002085
cristy2ed42f62011-10-02 19:49:57 +00002086 register ssize_t
2087 i;
2088
cristy0158a4b2010-09-20 13:59:45 +00002089 assert(image != (const Image *) NULL);
2090 assert(image->signature == MagickSignature);
2091 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002092 cache_info=(CacheInfo *) image->cache;
2093 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002094 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002095 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002096 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2097 exception);
2098 if (q == (Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002099 {
cristy9e0719b2011-12-29 03:45:45 +00002100 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2101 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2102 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2103 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2104 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002105 return(MagickFalse);
2106 }
2107 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2108 {
2109 PixelChannel
2110 channel;
2111
cristye2a912b2011-12-05 20:02:07 +00002112 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002113 pixel[channel]=q[i];
2114 }
cristy3ed852e2009-09-05 21:47:34 +00002115 return(MagickTrue);
2116}
2117
2118/*
2119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2120% %
2121% %
2122% %
cristy3ed852e2009-09-05 21:47:34 +00002123% G e t O n e V i r t u a l P i x e l %
2124% %
2125% %
2126% %
2127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2128%
2129% GetOneVirtualPixel() returns a single virtual pixel at the specified
2130% (x,y) location. The image background color is returned if an error occurs.
2131% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2132%
2133% The format of the GetOneVirtualPixel() method is:
2134%
cristybb503372010-05-27 20:51:26 +00002135% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
cristy2ed42f62011-10-02 19:49:57 +00002136% const ssize_t y,Quantum *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002137%
2138% A description of each parameter follows:
2139%
2140% o image: the image.
2141%
2142% o x,y: These values define the location of the pixel to return.
2143%
2144% o pixel: return a pixel at the specified (x,y) location.
2145%
2146% o exception: return any errors or warnings in this structure.
2147%
2148*/
2149MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristy2ed42f62011-10-02 19:49:57 +00002150 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002151{
cristy3ed852e2009-09-05 21:47:34 +00002152 CacheInfo
2153 *cache_info;
2154
cristy0158a4b2010-09-20 13:59:45 +00002155 const int
2156 id = GetOpenMPThreadId();
2157
cristy4c08aed2011-07-01 19:47:50 +00002158 const Quantum
2159 *p;
cristy2036f5c2010-09-19 21:18:17 +00002160
cristy2ed42f62011-10-02 19:49:57 +00002161 register ssize_t
2162 i;
2163
cristy3ed852e2009-09-05 21:47:34 +00002164 assert(image != (const Image *) NULL);
2165 assert(image->signature == MagickSignature);
2166 assert(image->cache != (Cache) NULL);
2167 cache_info=(CacheInfo *) image->cache;
2168 assert(cache_info->signature == MagickSignature);
cristy2ed42f62011-10-02 19:49:57 +00002169 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristyd317f372010-09-18 01:42:20 +00002170 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2171 (GetOneVirtualPixelFromHandler) NULL)
2172 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2173 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002174 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002175 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002176 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002177 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002178 {
cristy9e0719b2011-12-29 03:45:45 +00002179 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2180 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2181 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2182 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2183 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002184 return(MagickFalse);
2185 }
2186 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2187 {
2188 PixelChannel
2189 channel;
2190
cristye2a912b2011-12-05 20:02:07 +00002191 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002192 pixel[channel]=p[i];
2193 }
cristy2036f5c2010-09-19 21:18:17 +00002194 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002195}
2196
2197/*
2198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2199% %
2200% %
2201% %
2202+ 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 %
2203% %
2204% %
2205% %
2206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2207%
2208% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2209% specified (x,y) location. The image background color is returned if an
2210% error occurs.
2211%
2212% The format of the GetOneVirtualPixelFromCache() method is:
2213%
2214% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002215% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002216% Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002217%
2218% A description of each parameter follows:
2219%
2220% o image: the image.
2221%
2222% o virtual_pixel_method: the virtual pixel method.
2223%
2224% o x,y: These values define the location of the pixel to return.
2225%
2226% o pixel: return a pixel at the specified (x,y) location.
2227%
2228% o exception: return any errors or warnings in this structure.
2229%
2230*/
2231static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002232 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy2ed42f62011-10-02 19:49:57 +00002233 Quantum *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002234{
cristy0158a4b2010-09-20 13:59:45 +00002235 CacheInfo
2236 *cache_info;
2237
2238 const int
2239 id = GetOpenMPThreadId();
2240
cristy4c08aed2011-07-01 19:47:50 +00002241 const Quantum
2242 *p;
cristy3ed852e2009-09-05 21:47:34 +00002243
cristy2ed42f62011-10-02 19:49:57 +00002244 register ssize_t
2245 i;
2246
cristye7cc7cf2010-09-21 13:26:47 +00002247 assert(image != (const Image *) NULL);
2248 assert(image->signature == MagickSignature);
2249 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002250 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002251 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002252 assert(id < (int) cache_info->number_threads);
cristy2ed42f62011-10-02 19:49:57 +00002253 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
cristy4c08aed2011-07-01 19:47:50 +00002254 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002255 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002256 if (p == (const Quantum *) NULL)
cristy2ed42f62011-10-02 19:49:57 +00002257 {
cristy9e0719b2011-12-29 03:45:45 +00002258 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2259 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2260 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2261 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2262 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
cristy2ed42f62011-10-02 19:49:57 +00002263 return(MagickFalse);
2264 }
2265 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2266 {
2267 PixelChannel
2268 channel;
2269
cristye2a912b2011-12-05 20:02:07 +00002270 channel=GetPixelChannelMapChannel(image,i);
cristy2ed42f62011-10-02 19:49:57 +00002271 pixel[channel]=p[i];
2272 }
cristy3ed852e2009-09-05 21:47:34 +00002273 return(MagickTrue);
2274}
2275
2276/*
2277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278% %
2279% %
2280% %
cristy3aa93752011-12-18 15:54:24 +00002281% G e t O n e V i r t u a l P i x e l I n f o %
2282% %
2283% %
2284% %
2285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2286%
2287% GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2288% location. The image background color is returned if an error occurs. If
2289% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2290%
2291% The format of the GetOneVirtualPixelInfo() method is:
2292%
2293% MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2294% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2295% const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2296%
2297% A description of each parameter follows:
2298%
2299% o image: the image.
2300%
2301% o virtual_pixel_method: the virtual pixel method.
2302%
2303% o x,y: these values define the location of the pixel to return.
2304%
2305% o pixel: return a pixel at the specified (x,y) location.
2306%
2307% o exception: return any errors or warnings in this structure.
2308%
2309*/
2310MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2311 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2312 PixelInfo *pixel,ExceptionInfo *exception)
2313{
2314 CacheInfo
2315 *cache_info;
2316
2317 const int
2318 id = GetOpenMPThreadId();
2319
2320 register const Quantum
2321 *p;
2322
2323 assert(image != (const Image *) NULL);
2324 assert(image->signature == MagickSignature);
2325 assert(image->cache != (Cache) NULL);
2326 cache_info=(CacheInfo *) image->cache;
2327 assert(cache_info->signature == MagickSignature);
2328 assert(id < (int) cache_info->number_threads);
cristyf82cff82012-04-16 16:54:17 +00002329 GetPixelInfo(image,pixel);
cristy3aa93752011-12-18 15:54:24 +00002330 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2331 cache_info->nexus_info[id],exception);
cristy3aa93752011-12-18 15:54:24 +00002332 if (p == (const Quantum *) NULL)
2333 return(MagickFalse);
2334 GetPixelInfoPixel(image,p,pixel);
2335 return(MagickTrue);
2336}
2337
2338/*
2339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2340% %
2341% %
2342% %
cristy3ed852e2009-09-05 21:47:34 +00002343+ G e t P i x e l C a c h e C o l o r s p a c e %
2344% %
2345% %
2346% %
2347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2348%
2349% GetPixelCacheColorspace() returns the class type of the pixel cache.
2350%
2351% The format of the GetPixelCacheColorspace() method is:
2352%
2353% Colorspace GetPixelCacheColorspace(Cache cache)
2354%
2355% A description of each parameter follows:
2356%
2357% o cache: the pixel cache.
2358%
2359*/
cristya6577ff2011-09-02 19:54:26 +00002360MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002361{
2362 CacheInfo
2363 *cache_info;
2364
2365 assert(cache != (Cache) NULL);
2366 cache_info=(CacheInfo *) cache;
2367 assert(cache_info->signature == MagickSignature);
2368 if (cache_info->debug != MagickFalse)
2369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2370 cache_info->filename);
2371 return(cache_info->colorspace);
2372}
2373
2374/*
2375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376% %
2377% %
2378% %
2379+ G e t P i x e l C a c h e M e t h o d s %
2380% %
2381% %
2382% %
2383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384%
2385% GetPixelCacheMethods() initializes the CacheMethods structure.
2386%
2387% The format of the GetPixelCacheMethods() method is:
2388%
2389% void GetPixelCacheMethods(CacheMethods *cache_methods)
2390%
2391% A description of each parameter follows:
2392%
2393% o cache_methods: Specifies a pointer to a CacheMethods structure.
2394%
2395*/
cristya6577ff2011-09-02 19:54:26 +00002396MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00002397{
2398 assert(cache_methods != (CacheMethods *) NULL);
2399 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2400 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2401 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002402 cache_methods->get_virtual_metacontent_from_handler=
2403 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002404 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2405 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002406 cache_methods->get_authentic_metacontent_from_handler=
2407 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002408 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2409 cache_methods->get_one_authentic_pixel_from_handler=
2410 GetOneAuthenticPixelFromCache;
2411 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2412 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2413 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2414}
2415
2416/*
2417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2418% %
2419% %
2420% %
2421+ G e t P i x e l C a c h e N e x u s E x t e n t %
2422% %
2423% %
2424% %
2425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2426%
cristy4c08aed2011-07-01 19:47:50 +00002427% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2428% corresponding with the last call to SetPixelCacheNexusPixels() or
2429% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002430%
2431% The format of the GetPixelCacheNexusExtent() method is:
2432%
2433% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2434% NexusInfo *nexus_info)
2435%
2436% A description of each parameter follows:
2437%
2438% o nexus_info: the nexus info.
2439%
2440*/
cristya6577ff2011-09-02 19:54:26 +00002441MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002442 NexusInfo *nexus_info)
2443{
2444 CacheInfo
2445 *cache_info;
2446
2447 MagickSizeType
2448 extent;
2449
cristy9f027d12011-09-21 01:17:17 +00002450 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002451 cache_info=(CacheInfo *) cache;
2452 assert(cache_info->signature == MagickSignature);
2453 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2454 if (extent == 0)
2455 return((MagickSizeType) cache_info->columns*cache_info->rows);
2456 return(extent);
2457}
2458
2459/*
2460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2461% %
2462% %
2463% %
cristy4c08aed2011-07-01 19:47:50 +00002464+ 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 +00002465% %
2466% %
2467% %
2468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2469%
cristy4c08aed2011-07-01 19:47:50 +00002470% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2471% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002472%
cristy4c08aed2011-07-01 19:47:50 +00002473% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002474%
cristy4c08aed2011-07-01 19:47:50 +00002475% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002476% NexusInfo *nexus_info)
2477%
2478% A description of each parameter follows:
2479%
2480% o cache: the pixel cache.
2481%
cristy4c08aed2011-07-01 19:47:50 +00002482% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002483%
2484*/
cristya6577ff2011-09-02 19:54:26 +00002485MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002486 NexusInfo *nexus_info)
2487{
2488 CacheInfo
2489 *cache_info;
2490
cristy9f027d12011-09-21 01:17:17 +00002491 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002492 cache_info=(CacheInfo *) cache;
2493 assert(cache_info->signature == MagickSignature);
2494 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002495 return((void *) NULL);
2496 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002497}
2498
2499/*
2500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501% %
2502% %
2503% %
2504+ G e t P i x e l C a c h e N e x u s P i x e l s %
2505% %
2506% %
2507% %
2508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509%
2510% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2511% cache nexus.
2512%
2513% The format of the GetPixelCacheNexusPixels() method is:
2514%
cristy4c08aed2011-07-01 19:47:50 +00002515% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002516% NexusInfo *nexus_info)
2517%
2518% A description of each parameter follows:
2519%
2520% o cache: the pixel cache.
2521%
2522% o nexus_info: the cache nexus to return the pixels.
2523%
2524*/
cristya6577ff2011-09-02 19:54:26 +00002525MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002526 NexusInfo *nexus_info)
2527{
2528 CacheInfo
2529 *cache_info;
2530
cristy9f027d12011-09-21 01:17:17 +00002531 assert(cache != NULL);
cristy3ed852e2009-09-05 21:47:34 +00002532 cache_info=(CacheInfo *) cache;
2533 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002534 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002535 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002536 return(nexus_info->pixels);
2537}
2538
2539/*
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541% %
2542% %
2543% %
cristy056ba772010-01-02 23:33:54 +00002544+ G e t P i x e l C a c h e P i x e l s %
2545% %
2546% %
2547% %
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549%
2550% GetPixelCachePixels() returns the pixels associated with the specified image.
2551%
2552% The format of the GetPixelCachePixels() method is:
2553%
cristyf84a1932010-01-03 18:00:18 +00002554% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2555% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002556%
2557% A description of each parameter follows:
2558%
2559% o image: the image.
2560%
2561% o length: the pixel cache length.
2562%
cristyf84a1932010-01-03 18:00:18 +00002563% o exception: return any errors or warnings in this structure.
2564%
cristy056ba772010-01-02 23:33:54 +00002565*/
cristyd1dd6e42011-09-04 01:46:08 +00002566MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
cristyf84a1932010-01-03 18:00:18 +00002567 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002568{
2569 CacheInfo
2570 *cache_info;
2571
2572 assert(image != (const Image *) NULL);
2573 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002574 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002575 assert(length != (MagickSizeType *) NULL);
2576 assert(exception != (ExceptionInfo *) NULL);
2577 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002578 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002579 assert(cache_info->signature == MagickSignature);
2580 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002581 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002582 return((void *) NULL);
2583 *length=cache_info->length;
2584 return((void *) cache_info->pixels);
2585}
2586
2587/*
2588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589% %
2590% %
2591% %
cristyb32b90a2009-09-07 21:45:48 +00002592+ 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 +00002593% %
2594% %
2595% %
2596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597%
2598% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2599%
2600% The format of the GetPixelCacheStorageClass() method is:
2601%
2602% ClassType GetPixelCacheStorageClass(Cache cache)
2603%
2604% A description of each parameter follows:
2605%
2606% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2607%
2608% o cache: the pixel cache.
2609%
2610*/
cristya6577ff2011-09-02 19:54:26 +00002611MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00002612{
2613 CacheInfo
2614 *cache_info;
2615
2616 assert(cache != (Cache) NULL);
2617 cache_info=(CacheInfo *) cache;
2618 assert(cache_info->signature == MagickSignature);
2619 if (cache_info->debug != MagickFalse)
2620 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2621 cache_info->filename);
2622 return(cache_info->storage_class);
2623}
2624
2625/*
2626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2627% %
2628% %
2629% %
cristyb32b90a2009-09-07 21:45:48 +00002630+ G e t P i x e l C a c h e T i l e S i z e %
2631% %
2632% %
2633% %
2634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635%
2636% GetPixelCacheTileSize() returns the pixel cache tile size.
2637%
2638% The format of the GetPixelCacheTileSize() method is:
2639%
cristybb503372010-05-27 20:51:26 +00002640% void GetPixelCacheTileSize(const Image *image,size_t *width,
2641% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002642%
2643% A description of each parameter follows:
2644%
2645% o image: the image.
2646%
2647% o width: the optimize cache tile width in pixels.
2648%
2649% o height: the optimize cache tile height in pixels.
2650%
2651*/
cristya6577ff2011-09-02 19:54:26 +00002652MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
cristybb503372010-05-27 20:51:26 +00002653 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002654{
cristy4c08aed2011-07-01 19:47:50 +00002655 CacheInfo
2656 *cache_info;
2657
cristyb32b90a2009-09-07 21:45:48 +00002658 assert(image != (Image *) NULL);
2659 assert(image->signature == MagickSignature);
2660 if (image->debug != MagickFalse)
2661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002662 cache_info=(CacheInfo *) image->cache;
2663 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002664 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002665 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002666 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002667 *height=(*width);
2668}
2669
2670/*
2671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2672% %
2673% %
2674% %
2675+ G e t P i x e l C a c h e T y p e %
2676% %
2677% %
2678% %
2679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2680%
2681% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2682%
2683% The format of the GetPixelCacheType() method is:
2684%
2685% CacheType GetPixelCacheType(const Image *image)
2686%
2687% A description of each parameter follows:
2688%
2689% o image: the image.
2690%
2691*/
cristya6577ff2011-09-02 19:54:26 +00002692MagickPrivate CacheType GetPixelCacheType(const Image *image)
cristyb32b90a2009-09-07 21:45:48 +00002693{
2694 CacheInfo
2695 *cache_info;
2696
2697 assert(image != (Image *) NULL);
2698 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002699 assert(image->cache != (Cache) NULL);
2700 cache_info=(CacheInfo *) image->cache;
2701 assert(cache_info->signature == MagickSignature);
2702 return(cache_info->type);
2703}
2704
2705/*
2706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2707% %
2708% %
2709% %
cristy3ed852e2009-09-05 21:47:34 +00002710+ 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 %
2711% %
2712% %
2713% %
2714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2715%
2716% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2717% pixel cache. A virtual pixel is any pixel access that is outside the
2718% boundaries of the image cache.
2719%
2720% The format of the GetPixelCacheVirtualMethod() method is:
2721%
2722% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2723%
2724% A description of each parameter follows:
2725%
2726% o image: the image.
2727%
2728*/
cristyd1dd6e42011-09-04 01:46:08 +00002729MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002730{
2731 CacheInfo
2732 *cache_info;
2733
2734 assert(image != (Image *) NULL);
2735 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002736 assert(image->cache != (Cache) NULL);
2737 cache_info=(CacheInfo *) image->cache;
2738 assert(cache_info->signature == MagickSignature);
2739 return(cache_info->virtual_pixel_method);
2740}
2741
2742/*
2743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2744% %
2745% %
2746% %
cristy4c08aed2011-07-01 19:47:50 +00002747+ 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 +00002748% %
2749% %
2750% %
2751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752%
cristy4c08aed2011-07-01 19:47:50 +00002753% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2754% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002755%
cristy4c08aed2011-07-01 19:47:50 +00002756% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002757%
cristy4c08aed2011-07-01 19:47:50 +00002758% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002759%
2760% A description of each parameter follows:
2761%
2762% o image: the image.
2763%
2764*/
cristy4c08aed2011-07-01 19:47:50 +00002765static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002766{
2767 CacheInfo
2768 *cache_info;
2769
cristy5c9e6f22010-09-17 17:31:01 +00002770 const int
2771 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002772
cristy4c08aed2011-07-01 19:47:50 +00002773 const void
2774 *metacontent;
2775
cristye7cc7cf2010-09-21 13:26:47 +00002776 assert(image != (const Image *) NULL);
2777 assert(image->signature == MagickSignature);
2778 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002779 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002780 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002781 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002782 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2783 cache_info->nexus_info[id]);
2784 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002785}
2786
2787/*
2788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2789% %
2790% %
2791% %
cristy4c08aed2011-07-01 19:47:50 +00002792+ 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 +00002793% %
2794% %
2795% %
2796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2797%
cristy4c08aed2011-07-01 19:47:50 +00002798% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2799% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002800%
cristy4c08aed2011-07-01 19:47:50 +00002801% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002802%
cristy4c08aed2011-07-01 19:47:50 +00002803% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002804% NexusInfo *nexus_info)
2805%
2806% A description of each parameter follows:
2807%
2808% o cache: the pixel cache.
2809%
cristy4c08aed2011-07-01 19:47:50 +00002810% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002811%
2812*/
cristya6577ff2011-09-02 19:54:26 +00002813MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy6162bb42011-07-18 11:34:09 +00002814 NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002815{
2816 CacheInfo
2817 *cache_info;
2818
cristye7cc7cf2010-09-21 13:26:47 +00002819 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002820 cache_info=(CacheInfo *) cache;
2821 assert(cache_info->signature == MagickSignature);
2822 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002823 return((void *) NULL);
2824 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002825}
2826
2827/*
2828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829% %
2830% %
2831% %
cristy4c08aed2011-07-01 19:47:50 +00002832% 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 +00002833% %
2834% %
2835% %
2836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837%
cristy4c08aed2011-07-01 19:47:50 +00002838% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2839% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2840% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002841%
cristy4c08aed2011-07-01 19:47:50 +00002842% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002843%
cristy4c08aed2011-07-01 19:47:50 +00002844% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002845%
2846% A description of each parameter follows:
2847%
2848% o image: the image.
2849%
2850*/
cristy4c08aed2011-07-01 19:47:50 +00002851MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002852{
2853 CacheInfo
2854 *cache_info;
2855
cristy2036f5c2010-09-19 21:18:17 +00002856 const int
2857 id = GetOpenMPThreadId();
2858
cristy4c08aed2011-07-01 19:47:50 +00002859 const void
2860 *metacontent;
2861
cristy3ed852e2009-09-05 21:47:34 +00002862 assert(image != (const Image *) NULL);
2863 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002864 assert(image->cache != (Cache) NULL);
2865 cache_info=(CacheInfo *) image->cache;
2866 assert(cache_info->signature == MagickSignature);
cristya26c6622012-02-14 14:00:20 +00002867 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2868 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2869 return(metacontent);
cristy2036f5c2010-09-19 21:18:17 +00002870 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002871 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2872 cache_info->nexus_info[id]);
2873 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002874}
2875
2876/*
2877%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878% %
2879% %
2880% %
2881+ 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 %
2882% %
2883% %
2884% %
2885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886%
2887% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2888% pixel cache as defined by the geometry parameters. A pointer to the pixels
2889% is returned if the pixels are transferred, otherwise a NULL is returned.
2890%
2891% The format of the GetVirtualPixelsFromNexus() method is:
2892%
cristy4c08aed2011-07-01 19:47:50 +00002893% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00002894% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00002895% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2896% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002897%
2898% A description of each parameter follows:
2899%
2900% o image: the image.
2901%
2902% o virtual_pixel_method: the virtual pixel method.
2903%
2904% o x,y,columns,rows: These values define the perimeter of a region of
2905% pixels.
2906%
2907% o nexus_info: the cache nexus to acquire.
2908%
2909% o exception: return any errors or warnings in this structure.
2910%
2911*/
2912
cristybb503372010-05-27 20:51:26 +00002913static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002914 DitherMatrix[64] =
2915 {
2916 0, 48, 12, 60, 3, 51, 15, 63,
2917 32, 16, 44, 28, 35, 19, 47, 31,
2918 8, 56, 4, 52, 11, 59, 7, 55,
2919 40, 24, 36, 20, 43, 27, 39, 23,
2920 2, 50, 14, 62, 1, 49, 13, 61,
2921 34, 18, 46, 30, 33, 17, 45, 29,
2922 10, 58, 6, 54, 9, 57, 5, 53,
2923 42, 26, 38, 22, 41, 25, 37, 21
2924 };
2925
cristybb503372010-05-27 20:51:26 +00002926static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002927{
cristybb503372010-05-27 20:51:26 +00002928 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002929 index;
2930
2931 index=x+DitherMatrix[x & 0x07]-32L;
2932 if (index < 0L)
2933 return(0L);
cristybb503372010-05-27 20:51:26 +00002934 if (index >= (ssize_t) columns)
2935 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00002936 return(index);
2937}
2938
cristybb503372010-05-27 20:51:26 +00002939static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002940{
cristybb503372010-05-27 20:51:26 +00002941 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002942 index;
2943
2944 index=y+DitherMatrix[y & 0x07]-32L;
2945 if (index < 0L)
2946 return(0L);
cristybb503372010-05-27 20:51:26 +00002947 if (index >= (ssize_t) rows)
2948 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00002949 return(index);
2950}
2951
cristybb503372010-05-27 20:51:26 +00002952static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002953{
2954 if (x < 0L)
2955 return(0L);
cristybb503372010-05-27 20:51:26 +00002956 if (x >= (ssize_t) columns)
2957 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00002958 return(x);
2959}
2960
cristybb503372010-05-27 20:51:26 +00002961static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002962{
2963 if (y < 0L)
2964 return(0L);
cristybb503372010-05-27 20:51:26 +00002965 if (y >= (ssize_t) rows)
2966 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00002967 return(y);
2968}
2969
cristybb503372010-05-27 20:51:26 +00002970static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00002971{
cristybb503372010-05-27 20:51:26 +00002972 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002973}
2974
cristybb503372010-05-27 20:51:26 +00002975static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00002976{
cristybb503372010-05-27 20:51:26 +00002977 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00002978}
2979
cristybb503372010-05-27 20:51:26 +00002980static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2981 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00002982{
2983 MagickModulo
2984 modulo;
2985
cristy6162bb42011-07-18 11:34:09 +00002986 /*
2987 Compute the remainder of dividing offset by extent. It returns not only
2988 the quotient (tile the offset falls in) but also the positive remainer
2989 within that tile such that 0 <= remainder < extent. This method is
2990 essentially a ldiv() using a floored modulo division rather than the
2991 normal default truncated modulo division.
2992 */
cristybb503372010-05-27 20:51:26 +00002993 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002994 if (offset < 0L)
2995 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00002996 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00002997 return(modulo);
2998}
2999
cristya6577ff2011-09-02 19:54:26 +00003000MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003001 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3002 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003003 ExceptionInfo *exception)
3004{
3005 CacheInfo
3006 *cache_info;
3007
3008 MagickOffsetType
3009 offset;
3010
3011 MagickSizeType
3012 length,
3013 number_pixels;
3014
3015 NexusInfo
3016 **virtual_nexus;
3017
cristy4c08aed2011-07-01 19:47:50 +00003018 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003019 *pixels,
cristy5f95f4f2011-10-23 01:01:01 +00003020 virtual_pixel[CompositePixelChannel];
cristy3ed852e2009-09-05 21:47:34 +00003021
3022 RectangleInfo
3023 region;
3024
cristy4c08aed2011-07-01 19:47:50 +00003025 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003026 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003027
cristy4c08aed2011-07-01 19:47:50 +00003028 register const void
3029 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003030
cristy4c08aed2011-07-01 19:47:50 +00003031 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003032 *restrict q;
3033
cristybb503372010-05-27 20:51:26 +00003034 register ssize_t
cristy105ba3c2011-07-18 02:28:38 +00003035 i,
3036 u;
cristy3ed852e2009-09-05 21:47:34 +00003037
cristy4c08aed2011-07-01 19:47:50 +00003038 register unsigned char
3039 *restrict s;
3040
cristy105ba3c2011-07-18 02:28:38 +00003041 ssize_t
3042 v;
3043
cristy4c08aed2011-07-01 19:47:50 +00003044 void
cristy105ba3c2011-07-18 02:28:38 +00003045 *virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003046
cristy3ed852e2009-09-05 21:47:34 +00003047 /*
3048 Acquire pixels.
3049 */
cristye7cc7cf2010-09-21 13:26:47 +00003050 assert(image != (const Image *) NULL);
3051 assert(image->signature == MagickSignature);
3052 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003053 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003054 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003055 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003056 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003057 region.x=x;
3058 region.y=y;
3059 region.width=columns;
3060 region.height=rows;
3061 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003062 if (pixels == (Quantum *) NULL)
3063 return((const Quantum *) NULL);
cristyacd2ed22011-08-30 01:44:23 +00003064 q=pixels;
cristydf415c82010-03-11 16:47:50 +00003065 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3066 nexus_info->region.x;
3067 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3068 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003069 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3070 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003071 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3072 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003073 {
3074 MagickBooleanType
3075 status;
3076
3077 /*
3078 Pixel request is inside cache extents.
3079 */
cristy4c08aed2011-07-01 19:47:50 +00003080 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristyacd2ed22011-08-30 01:44:23 +00003081 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003082 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3083 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003084 return((const Quantum *) NULL);
3085 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003086 {
cristy4c08aed2011-07-01 19:47:50 +00003087 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003088 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003089 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003090 }
cristyacd2ed22011-08-30 01:44:23 +00003091 return(q);
cristy3ed852e2009-09-05 21:47:34 +00003092 }
3093 /*
3094 Pixel request is outside cache extents.
3095 */
cristy4c08aed2011-07-01 19:47:50 +00003096 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003097 virtual_nexus=AcquirePixelCacheNexus(1);
3098 if (virtual_nexus == (NexusInfo **) NULL)
3099 {
cristy4c08aed2011-07-01 19:47:50 +00003100 if (virtual_nexus != (NexusInfo **) NULL)
3101 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003102 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3103 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003104 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003105 }
cristy105ba3c2011-07-18 02:28:38 +00003106 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3107 sizeof(*virtual_pixel));
3108 virtual_metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003109 switch (virtual_pixel_method)
3110 {
cristy4c08aed2011-07-01 19:47:50 +00003111 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003112 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003113 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003114 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003115 case MaskVirtualPixelMethod:
3116 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003117 case EdgeVirtualPixelMethod:
3118 case CheckerTileVirtualPixelMethod:
3119 case HorizontalTileVirtualPixelMethod:
3120 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003121 {
cristy4c08aed2011-07-01 19:47:50 +00003122 if (cache_info->metacontent_extent != 0)
3123 {
cristy6162bb42011-07-18 11:34:09 +00003124 /*
3125 Acquire a metacontent buffer.
3126 */
cristya64b85d2011-09-14 01:02:31 +00003127 virtual_metacontent=(void *) AcquireQuantumMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003128 cache_info->metacontent_extent);
cristy105ba3c2011-07-18 02:28:38 +00003129 if (virtual_metacontent == (void *) NULL)
cristy4c08aed2011-07-01 19:47:50 +00003130 {
cristy4c08aed2011-07-01 19:47:50 +00003131 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3132 (void) ThrowMagickException(exception,GetMagickModule(),
3133 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3134 return((const Quantum *) NULL);
3135 }
cristy105ba3c2011-07-18 02:28:38 +00003136 (void) ResetMagickMemory(virtual_metacontent,0,
cristy4c08aed2011-07-01 19:47:50 +00003137 cache_info->metacontent_extent);
3138 }
3139 switch (virtual_pixel_method)
3140 {
3141 case BlackVirtualPixelMethod:
3142 {
cristy30301712011-07-18 15:06:51 +00003143 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3144 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003145 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3146 break;
3147 }
3148 case GrayVirtualPixelMethod:
3149 {
cristy30301712011-07-18 15:06:51 +00003150 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
cristy208b1002011-08-07 18:51:50 +00003151 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3152 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003153 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3154 break;
3155 }
3156 case TransparentVirtualPixelMethod:
3157 {
cristy30301712011-07-18 15:06:51 +00003158 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3159 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003160 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3161 break;
3162 }
3163 case MaskVirtualPixelMethod:
3164 case WhiteVirtualPixelMethod:
3165 {
cristy30301712011-07-18 15:06:51 +00003166 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3167 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003168 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3169 break;
3170 }
3171 default:
3172 {
cristy9e0719b2011-12-29 03:45:45 +00003173 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3174 virtual_pixel);
3175 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3176 virtual_pixel);
3177 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3178 virtual_pixel);
cristy6cff7ae2012-02-07 02:26:02 +00003179 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3180 virtual_pixel);
cristy9e0719b2011-12-29 03:45:45 +00003181 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3182 virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003183 break;
3184 }
3185 }
cristy3ed852e2009-09-05 21:47:34 +00003186 break;
3187 }
3188 default:
cristy3ed852e2009-09-05 21:47:34 +00003189 break;
cristy3ed852e2009-09-05 21:47:34 +00003190 }
cristybb503372010-05-27 20:51:26 +00003191 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003192 {
cristybb503372010-05-27 20:51:26 +00003193 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003194 {
3195 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003196 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003197 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3198 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003199 {
3200 MagickModulo
3201 x_modulo,
3202 y_modulo;
3203
3204 /*
3205 Transfer a single pixel.
3206 */
3207 length=(MagickSizeType) 1;
3208 switch (virtual_pixel_method)
3209 {
cristy3ed852e2009-09-05 21:47:34 +00003210 default:
3211 {
3212 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003213 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003214 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003215 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003216 break;
3217 }
3218 case RandomVirtualPixelMethod:
3219 {
3220 if (cache_info->random_info == (RandomInfo *) NULL)
3221 cache_info->random_info=AcquireRandomInfo();
3222 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003223 RandomX(cache_info->random_info,cache_info->columns),
3224 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003225 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003226 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003227 break;
3228 }
3229 case DitherVirtualPixelMethod:
3230 {
3231 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003232 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003233 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003234 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003235 break;
3236 }
3237 case TileVirtualPixelMethod:
3238 {
3239 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3240 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3241 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003242 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003243 exception);
cristy4c08aed2011-07-01 19:47:50 +00003244 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003245 break;
3246 }
3247 case MirrorVirtualPixelMethod:
3248 {
3249 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3250 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003251 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003252 x_modulo.remainder-1L;
3253 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3254 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003255 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003256 y_modulo.remainder-1L;
3257 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003258 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003259 exception);
cristy4c08aed2011-07-01 19:47:50 +00003260 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003261 break;
3262 }
3263 case HorizontalTileEdgeVirtualPixelMethod:
3264 {
3265 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3266 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003267 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003268 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003269 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003270 break;
3271 }
3272 case VerticalTileEdgeVirtualPixelMethod:
3273 {
3274 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3275 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003276 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003277 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003278 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3279 break;
3280 }
3281 case BackgroundVirtualPixelMethod:
3282 case BlackVirtualPixelMethod:
3283 case GrayVirtualPixelMethod:
3284 case TransparentVirtualPixelMethod:
3285 case MaskVirtualPixelMethod:
3286 case WhiteVirtualPixelMethod:
3287 {
3288 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003289 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003290 break;
3291 }
3292 case EdgeVirtualPixelMethod:
3293 case CheckerTileVirtualPixelMethod:
3294 {
3295 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3296 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3297 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3298 {
3299 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003300 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003301 break;
3302 }
3303 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3304 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3305 exception);
3306 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3307 break;
3308 }
3309 case HorizontalTileVirtualPixelMethod:
3310 {
3311 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3312 {
3313 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003314 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003315 break;
3316 }
3317 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3318 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3319 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3320 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3321 exception);
3322 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3323 break;
3324 }
3325 case VerticalTileVirtualPixelMethod:
3326 {
3327 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3328 {
3329 p=virtual_pixel;
cristy105ba3c2011-07-18 02:28:38 +00003330 r=virtual_metacontent;
cristy4c08aed2011-07-01 19:47:50 +00003331 break;
3332 }
3333 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3334 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3335 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3336 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3337 exception);
3338 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003339 break;
3340 }
3341 }
cristy4c08aed2011-07-01 19:47:50 +00003342 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003343 break;
cristyed231572011-07-14 02:18:59 +00003344 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003345 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003346 q+=cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003347 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy4c08aed2011-07-01 19:47:50 +00003348 {
3349 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3350 s+=cache_info->metacontent_extent;
3351 }
cristy3ed852e2009-09-05 21:47:34 +00003352 continue;
3353 }
3354 /*
3355 Transfer a run of pixels.
3356 */
cristy4c08aed2011-07-01 19:47:50 +00003357 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3358 length,1UL,*virtual_nexus,exception);
3359 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003360 break;
cristy4c08aed2011-07-01 19:47:50 +00003361 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003362 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3363 q+=length*cache_info->number_channels;
cristy105ba3c2011-07-18 02:28:38 +00003364 if ((r != (void *) NULL) && (s != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003365 {
cristy4c08aed2011-07-01 19:47:50 +00003366 (void) memcpy(s,r,(size_t) length);
3367 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003368 }
3369 }
3370 }
cristy4c08aed2011-07-01 19:47:50 +00003371 /*
3372 Free resources.
3373 */
cristy105ba3c2011-07-18 02:28:38 +00003374 if (virtual_metacontent != (void *) NULL)
3375 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003376 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3377 return(pixels);
3378}
3379
3380/*
3381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3382% %
3383% %
3384% %
3385+ G e t V i r t u a l P i x e l C a c h e %
3386% %
3387% %
3388% %
3389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3390%
3391% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3392% cache as defined by the geometry parameters. A pointer to the pixels
3393% is returned if the pixels are transferred, otherwise a NULL is returned.
3394%
3395% The format of the GetVirtualPixelCache() method is:
3396%
cristy4c08aed2011-07-01 19:47:50 +00003397% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003398% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3399% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003400% ExceptionInfo *exception)
3401%
3402% A description of each parameter follows:
3403%
3404% o image: the image.
3405%
3406% o virtual_pixel_method: the virtual pixel method.
3407%
3408% o x,y,columns,rows: These values define the perimeter of a region of
3409% pixels.
3410%
3411% o exception: return any errors or warnings in this structure.
3412%
3413*/
cristy4c08aed2011-07-01 19:47:50 +00003414static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003415 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3416 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003417{
3418 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003419 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003420
cristy5c9e6f22010-09-17 17:31:01 +00003421 const int
3422 id = GetOpenMPThreadId();
3423
cristy4c08aed2011-07-01 19:47:50 +00003424 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003425 *p;
cristy4c08aed2011-07-01 19:47:50 +00003426
cristye7cc7cf2010-09-21 13:26:47 +00003427 assert(image != (const Image *) NULL);
3428 assert(image->signature == MagickSignature);
3429 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003430 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003431 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003432 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003433 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
cristy4c08aed2011-07-01 19:47:50 +00003434 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003435 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003436}
3437
3438/*
3439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3440% %
3441% %
3442% %
3443% G e t V i r t u a l P i x e l Q u e u e %
3444% %
3445% %
3446% %
3447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3448%
cristy4c08aed2011-07-01 19:47:50 +00003449% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3450% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003451%
3452% The format of the GetVirtualPixelQueue() method is:
3453%
cristy4c08aed2011-07-01 19:47:50 +00003454% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003455%
3456% A description of each parameter follows:
3457%
3458% o image: the image.
3459%
3460*/
cristy4c08aed2011-07-01 19:47:50 +00003461MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003462{
3463 CacheInfo
3464 *cache_info;
3465
cristy2036f5c2010-09-19 21:18:17 +00003466 const int
3467 id = GetOpenMPThreadId();
3468
cristy3ed852e2009-09-05 21:47:34 +00003469 assert(image != (const Image *) NULL);
3470 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003471 assert(image->cache != (Cache) NULL);
3472 cache_info=(CacheInfo *) image->cache;
3473 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003474 if (cache_info->methods.get_virtual_pixels_handler !=
3475 (GetVirtualPixelsHandler) NULL)
3476 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003477 assert(id < (int) cache_info->number_threads);
3478 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003479}
3480
3481/*
3482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3483% %
3484% %
3485% %
3486% G e t V i r t u a l P i x e l s %
3487% %
3488% %
3489% %
3490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3491%
3492% GetVirtualPixels() returns an immutable pixel region. If the
3493% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003494% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003495% copy of the pixels or it may point to the original pixels in memory.
3496% Performance is maximized if the selected region is part of one row, or one
3497% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003498% (without a copy) if the image is in memory, or in a memory-mapped file. The
3499% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003500%
3501% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003502% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3503% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3504% access the meta-content (of type void) corresponding to the the
3505% region.
cristy3ed852e2009-09-05 21:47:34 +00003506%
3507% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3508%
3509% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3510% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3511% GetCacheViewAuthenticPixels() instead.
3512%
3513% The format of the GetVirtualPixels() method is:
3514%
cristy4c08aed2011-07-01 19:47:50 +00003515% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003516% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003517% ExceptionInfo *exception)
3518%
3519% A description of each parameter follows:
3520%
3521% o image: the image.
3522%
3523% o x,y,columns,rows: These values define the perimeter of a region of
3524% pixels.
3525%
3526% o exception: return any errors or warnings in this structure.
3527%
3528*/
cristy4c08aed2011-07-01 19:47:50 +00003529MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003530 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3531 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003532{
3533 CacheInfo
3534 *cache_info;
3535
cristy2036f5c2010-09-19 21:18:17 +00003536 const int
3537 id = GetOpenMPThreadId();
3538
cristy4c08aed2011-07-01 19:47:50 +00003539 const Quantum
cristyacd2ed22011-08-30 01:44:23 +00003540 *p;
cristy4c08aed2011-07-01 19:47:50 +00003541
cristy3ed852e2009-09-05 21:47:34 +00003542 assert(image != (const Image *) NULL);
3543 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003544 assert(image->cache != (Cache) NULL);
3545 cache_info=(CacheInfo *) image->cache;
3546 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003547 if (cache_info->methods.get_virtual_pixel_handler !=
3548 (GetVirtualPixelHandler) NULL)
3549 return(cache_info->methods.get_virtual_pixel_handler(image,
3550 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003551 assert(id < (int) cache_info->number_threads);
cristyacd2ed22011-08-30 01:44:23 +00003552 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy4c08aed2011-07-01 19:47:50 +00003553 columns,rows,cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00003554 return(p);
cristy3ed852e2009-09-05 21:47:34 +00003555}
3556
3557/*
3558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3559% %
3560% %
3561% %
3562+ 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 %
3563% %
3564% %
3565% %
3566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3567%
cristy4c08aed2011-07-01 19:47:50 +00003568% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3569% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003570%
3571% The format of the GetVirtualPixelsCache() method is:
3572%
cristy4c08aed2011-07-01 19:47:50 +00003573% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003574%
3575% A description of each parameter follows:
3576%
3577% o image: the image.
3578%
3579*/
cristy4c08aed2011-07-01 19:47:50 +00003580static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003581{
3582 CacheInfo
3583 *cache_info;
3584
cristy5c9e6f22010-09-17 17:31:01 +00003585 const int
3586 id = GetOpenMPThreadId();
3587
cristye7cc7cf2010-09-21 13:26:47 +00003588 assert(image != (const Image *) NULL);
3589 assert(image->signature == MagickSignature);
3590 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003591 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003592 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003593 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003594 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003595}
3596
3597/*
3598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3599% %
3600% %
3601% %
3602+ G e t V i r t u a l P i x e l s N e x u s %
3603% %
3604% %
3605% %
3606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3607%
3608% GetVirtualPixelsNexus() returns the pixels associated with the specified
3609% cache nexus.
3610%
3611% The format of the GetVirtualPixelsNexus() method is:
3612%
cristy4c08aed2011-07-01 19:47:50 +00003613% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003614% NexusInfo *nexus_info)
3615%
3616% A description of each parameter follows:
3617%
3618% o cache: the pixel cache.
3619%
3620% o nexus_info: the cache nexus to return the colormap pixels.
3621%
3622*/
cristya6577ff2011-09-02 19:54:26 +00003623MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003624 NexusInfo *nexus_info)
3625{
3626 CacheInfo
3627 *cache_info;
3628
cristye7cc7cf2010-09-21 13:26:47 +00003629 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003630 cache_info=(CacheInfo *) cache;
3631 assert(cache_info->signature == MagickSignature);
3632 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003633 return((Quantum *) NULL);
3634 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003635}
3636
3637/*
3638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3639% %
3640% %
3641% %
cristy3ed852e2009-09-05 21:47:34 +00003642+ O p e n P i x e l C a c h e %
3643% %
3644% %
3645% %
3646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647%
3648% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3649% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003650% metacontent, and memory mapping the cache if it is disk based. The cache
3651% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003652%
3653% The format of the OpenPixelCache() method is:
3654%
3655% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3656% ExceptionInfo *exception)
3657%
3658% A description of each parameter follows:
3659%
3660% o image: the image.
3661%
3662% o mode: ReadMode, WriteMode, or IOMode.
3663%
3664% o exception: return any errors or warnings in this structure.
3665%
3666*/
3667
cristyd43a46b2010-01-21 02:13:41 +00003668static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003669{
3670 cache_info->mapped=MagickFalse;
cristya64b85d2011-09-14 01:02:31 +00003671 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003672 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003673 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003674 {
3675 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003676 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003677 cache_info->length);
3678 }
3679}
3680
3681static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3682{
3683 CacheInfo
3684 *cache_info;
3685
3686 MagickOffsetType
3687 count,
3688 extent,
3689 offset;
3690
3691 cache_info=(CacheInfo *) image->cache;
3692 if (image->debug != MagickFalse)
3693 {
3694 char
3695 format[MaxTextExtent],
3696 message[MaxTextExtent];
3697
cristyb9080c92009-12-01 20:13:26 +00003698 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003699 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003700 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003701 cache_info->cache_filename,cache_info->file,format);
3702 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3703 }
3704 if (length != (MagickSizeType) ((MagickOffsetType) length))
3705 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003706 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003707 if (extent < 0)
3708 return(MagickFalse);
3709 if ((MagickSizeType) extent >= length)
3710 return(MagickTrue);
3711 offset=(MagickOffsetType) length-1;
3712 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3713 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3714}
3715
3716static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3717 ExceptionInfo *exception)
3718{
cristy3ed852e2009-09-05 21:47:34 +00003719 CacheInfo
3720 *cache_info,
3721 source_info;
3722
cristyf3a6a9d2010-11-07 21:02:56 +00003723 char
3724 format[MaxTextExtent],
3725 message[MaxTextExtent];
3726
cristy4c08aed2011-07-01 19:47:50 +00003727 MagickBooleanType
3728 status;
3729
cristy3ed852e2009-09-05 21:47:34 +00003730 MagickSizeType
3731 length,
3732 number_pixels;
3733
cristy3ed852e2009-09-05 21:47:34 +00003734 size_t
cristye076a6e2010-08-15 19:59:43 +00003735 columns,
cristy3ed852e2009-09-05 21:47:34 +00003736 packet_size;
3737
cristye7cc7cf2010-09-21 13:26:47 +00003738 assert(image != (const Image *) NULL);
3739 assert(image->signature == MagickSignature);
3740 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003741 if (image->debug != MagickFalse)
3742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3743 if ((image->columns == 0) || (image->rows == 0))
3744 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3745 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003746 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003747 source_info=(*cache_info);
3748 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00003749 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00003750 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00003751 cache_info->storage_class=image->storage_class;
3752 cache_info->colorspace=image->colorspace;
cristy222b19c2011-08-04 01:35:11 +00003753 cache_info->matte=image->matte;
cristy183a5c72012-01-30 01:40:35 +00003754 cache_info->mask=image->mask;
cristy3ed852e2009-09-05 21:47:34 +00003755 cache_info->rows=image->rows;
3756 cache_info->columns=image->columns;
cristybd5a96c2011-08-21 00:04:26 +00003757 InitializePixelChannelMap(image);
cristyed231572011-07-14 02:18:59 +00003758 cache_info->number_channels=GetPixelChannels(image);
cristy3b8fe922011-12-29 18:56:23 +00003759 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3760 sizeof(*image->channel_map));
cristy4c08aed2011-07-01 19:47:50 +00003761 cache_info->metacontent_extent=image->metacontent_extent;
cristy222b19c2011-08-04 01:35:11 +00003762 cache_info->mode=mode;
cristy73724512010-04-12 14:43:14 +00003763 if (image->ping != MagickFalse)
3764 {
cristy73724512010-04-12 14:43:14 +00003765 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00003766 cache_info->pixels=(Quantum *) NULL;
3767 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00003768 cache_info->length=0;
3769 return(MagickTrue);
3770 }
cristy3ed852e2009-09-05 21:47:34 +00003771 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00003772 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00003773 if (image->metacontent_extent != 0)
3774 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003775 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003776 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003777 if (cache_info->columns != columns)
3778 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3779 image->filename);
3780 cache_info->length=length;
3781 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00003782 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003783 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00003784 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3785 {
3786 status=AcquireMagickResource(MemoryResource,cache_info->length);
3787 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3788 (cache_info->type == MemoryCache))
3789 {
cristyd43a46b2010-01-21 02:13:41 +00003790 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00003791 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003792 cache_info->pixels=source_info.pixels;
3793 else
3794 {
3795 /*
3796 Create memory pixel cache.
3797 */
cristy4c08aed2011-07-01 19:47:50 +00003798 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003799 if (image->debug != MagickFalse)
3800 {
cristy32cacff2011-12-31 03:36:27 +00003801 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003802 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003803 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3804 cache_info->filename,cache_info->mapped != MagickFalse ?
3805 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003806 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00003807 format);
cristy3ed852e2009-09-05 21:47:34 +00003808 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3809 message);
3810 }
cristy3ed852e2009-09-05 21:47:34 +00003811 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00003812 cache_info->metacontent=(void *) NULL;
3813 if (cache_info->metacontent_extent != 0)
3814 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003815 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003816 if ((source_info.storage_class != UndefinedClass) &&
3817 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003818 {
cristy4c08aed2011-07-01 19:47:50 +00003819 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00003820 exception);
3821 RelinquishPixelCachePixels(&source_info);
3822 }
cristy4c08aed2011-07-01 19:47:50 +00003823 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003824 }
3825 }
3826 RelinquishMagickResource(MemoryResource,cache_info->length);
3827 }
3828 /*
3829 Create pixel cache on disk.
3830 */
3831 status=AcquireMagickResource(DiskResource,cache_info->length);
3832 if (status == MagickFalse)
3833 {
3834 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3835 "CacheResourcesExhausted","`%s'",image->filename);
3836 return(MagickFalse);
3837 }
cristy413f1302012-01-01 17:48:27 +00003838 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3839 {
3840 (void) ClosePixelCacheOnDisk(cache_info);
3841 *cache_info->cache_filename='\0';
3842 }
cristy3ed852e2009-09-05 21:47:34 +00003843 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3844 {
3845 RelinquishMagickResource(DiskResource,cache_info->length);
3846 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3847 image->filename);
3848 return(MagickFalse);
3849 }
3850 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3851 cache_info->length);
3852 if (status == MagickFalse)
3853 {
3854 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3855 image->filename);
3856 return(MagickFalse);
3857 }
cristyed231572011-07-14 02:18:59 +00003858 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00003859 cache_info->metacontent_extent);
cristya0b40ff2011-10-06 18:17:58 +00003860 if (length != (MagickSizeType) ((size_t) length))
cristy3ed852e2009-09-05 21:47:34 +00003861 cache_info->type=DiskCache;
3862 else
3863 {
3864 status=AcquireMagickResource(MapResource,cache_info->length);
3865 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3866 (cache_info->type != MemoryCache))
3867 cache_info->type=DiskCache;
3868 else
3869 {
cristy4c08aed2011-07-01 19:47:50 +00003870 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00003871 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003872 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003873 {
cristy3ed852e2009-09-05 21:47:34 +00003874 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00003875 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00003876 }
3877 else
3878 {
3879 /*
3880 Create file-backed memory-mapped pixel cache.
3881 */
cristy4c08aed2011-07-01 19:47:50 +00003882 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00003883 (void) ClosePixelCacheOnDisk(cache_info);
3884 cache_info->type=MapCache;
3885 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003886 cache_info->metacontent=(void *) NULL;
3887 if (cache_info->metacontent_extent != 0)
3888 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00003889 number_pixels*cache_info->number_channels);
cristy413f1302012-01-01 17:48:27 +00003890 if ((source_info.storage_class != UndefinedClass) &&
3891 (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003892 {
3893 status=ClonePixelCachePixels(cache_info,&source_info,
3894 exception);
3895 RelinquishPixelCachePixels(&source_info);
3896 }
3897 if (image->debug != MagickFalse)
3898 {
cristy413f1302012-01-01 17:48:27 +00003899 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
cristyb51dff52011-05-19 16:55:47 +00003900 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003901 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00003902 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00003903 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00003904 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00003905 format);
cristy3ed852e2009-09-05 21:47:34 +00003906 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3907 message);
3908 }
cristy4c08aed2011-07-01 19:47:50 +00003909 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003910 }
3911 }
3912 RelinquishMagickResource(MapResource,cache_info->length);
3913 }
cristy4c08aed2011-07-01 19:47:50 +00003914 status=MagickTrue;
cristy413f1302012-01-01 17:48:27 +00003915 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00003916 {
3917 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3918 RelinquishPixelCachePixels(&source_info);
3919 }
3920 if (image->debug != MagickFalse)
3921 {
cristyb9080c92009-12-01 20:13:26 +00003922 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003923 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00003924 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00003925 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00003926 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00003927 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00003928 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3929 }
cristy4c08aed2011-07-01 19:47:50 +00003930 return(status);
cristy3ed852e2009-09-05 21:47:34 +00003931}
3932
3933/*
3934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3935% %
3936% %
3937% %
3938+ P e r s i s t P i x e l C a c h e %
3939% %
3940% %
3941% %
3942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3943%
3944% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3945% persistent pixel cache is one that resides on disk and is not destroyed
3946% when the program exits.
3947%
3948% The format of the PersistPixelCache() method is:
3949%
3950% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3951% const MagickBooleanType attach,MagickOffsetType *offset,
3952% ExceptionInfo *exception)
3953%
3954% A description of each parameter follows:
3955%
3956% o image: the image.
3957%
3958% o filename: the persistent pixel cache filename.
3959%
cristyf3a6a9d2010-11-07 21:02:56 +00003960% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00003961%
cristy3ed852e2009-09-05 21:47:34 +00003962% o initialize: A value other than zero initializes the persistent pixel
3963% cache.
3964%
3965% o offset: the offset in the persistent cache to store pixels.
3966%
3967% o exception: return any errors or warnings in this structure.
3968%
3969*/
3970MagickExport MagickBooleanType PersistPixelCache(Image *image,
3971 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3972 ExceptionInfo *exception)
3973{
3974 CacheInfo
3975 *cache_info,
3976 *clone_info;
3977
3978 Image
3979 clone_image;
3980
cristy3ed852e2009-09-05 21:47:34 +00003981 MagickBooleanType
3982 status;
3983
cristye076a6e2010-08-15 19:59:43 +00003984 ssize_t
3985 page_size;
3986
cristy3ed852e2009-09-05 21:47:34 +00003987 assert(image != (Image *) NULL);
3988 assert(image->signature == MagickSignature);
3989 if (image->debug != MagickFalse)
3990 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3991 assert(image->cache != (void *) NULL);
3992 assert(filename != (const char *) NULL);
3993 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00003994 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00003995 cache_info=(CacheInfo *) image->cache;
3996 assert(cache_info->signature == MagickSignature);
3997 if (attach != MagickFalse)
3998 {
3999 /*
cristy01b7eb02009-09-10 23:10:14 +00004000 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004001 */
4002 if (image->debug != MagickFalse)
4003 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004004 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004005 (void) CopyMagickString(cache_info->cache_filename,filename,
4006 MaxTextExtent);
4007 cache_info->type=DiskCache;
4008 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004009 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004010 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004011 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004012 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004013 }
cristy01b7eb02009-09-10 23:10:14 +00004014 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4015 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004016 {
cristyf84a1932010-01-03 18:00:18 +00004017 LockSemaphoreInfo(cache_info->semaphore);
cristyaf894d72011-08-06 23:03:10 +00004018 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004019 (cache_info->reference_count == 1))
4020 {
4021 int
4022 status;
4023
4024 /*
cristy01b7eb02009-09-10 23:10:14 +00004025 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004026 */
cristy320684d2011-09-23 14:55:47 +00004027 status=rename_utf8(cache_info->cache_filename,filename);
cristy3ed852e2009-09-05 21:47:34 +00004028 if (status == 0)
4029 {
4030 (void) CopyMagickString(cache_info->cache_filename,filename,
4031 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004032 *offset+=cache_info->length+page_size-(cache_info->length %
4033 page_size);
cristyf84a1932010-01-03 18:00:18 +00004034 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004035 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004036 if (image->debug != MagickFalse)
4037 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4038 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004039 return(MagickTrue);
4040 }
4041 }
cristyf84a1932010-01-03 18:00:18 +00004042 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004043 }
4044 /*
cristy01b7eb02009-09-10 23:10:14 +00004045 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004046 */
4047 clone_image=(*image);
4048 clone_info=(CacheInfo *) clone_image.cache;
4049 image->cache=ClonePixelCache(cache_info);
4050 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4051 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4052 cache_info->type=DiskCache;
4053 cache_info->offset=(*offset);
4054 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004055 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004056 if (status != MagickFalse)
cristyc82a27b2011-10-21 01:07:16 +00004057 status=ClonePixelCachePixels(cache_info,clone_info,exception);
cristy688f07b2009-09-27 15:19:13 +00004058 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004059 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4060 return(status);
4061}
4062
4063/*
4064%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4065% %
4066% %
4067% %
cristyc11dace2012-01-24 16:39:46 +00004068+ 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 +00004069% %
4070% %
4071% %
4072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4073%
cristyc11dace2012-01-24 16:39:46 +00004074% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4075% defined by the region rectangle and returns a pointer to the region. This
4076% region is subsequently transferred from the pixel cache with
cristy3ed852e2009-09-05 21:47:34 +00004077% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4078% pixels are transferred, otherwise a NULL is returned.
4079%
cristyc11dace2012-01-24 16:39:46 +00004080% The format of the QueueAuthenticPixelCacheNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00004081%
cristyc11dace2012-01-24 16:39:46 +00004082% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004083% const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004084% const MagickBooleanType clone,NexusInfo *nexus_info,
4085% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004086%
4087% A description of each parameter follows:
4088%
4089% o image: the image.
4090%
4091% o x,y,columns,rows: These values define the perimeter of a region of
4092% pixels.
4093%
4094% o nexus_info: the cache nexus to set.
4095%
cristy65dbf172011-10-06 17:32:04 +00004096% o clone: clone the pixel cache.
4097%
cristy3ed852e2009-09-05 21:47:34 +00004098% o exception: return any errors or warnings in this structure.
4099%
4100*/
cristyc11dace2012-01-24 16:39:46 +00004101MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4102 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy65dbf172011-10-06 17:32:04 +00004103 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004104{
4105 CacheInfo
4106 *cache_info;
4107
4108 MagickOffsetType
4109 offset;
4110
4111 MagickSizeType
4112 number_pixels;
4113
4114 RectangleInfo
4115 region;
4116
4117 /*
4118 Validate pixel cache geometry.
4119 */
cristye7cc7cf2010-09-21 13:26:47 +00004120 assert(image != (const Image *) NULL);
4121 assert(image->signature == MagickSignature);
4122 assert(image->cache != (Cache) NULL);
cristy65dbf172011-10-06 17:32:04 +00004123 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
cristy77ff0282010-09-13 00:51:10 +00004124 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004125 return((Quantum *) NULL);
cristye27517a2011-09-04 23:02:10 +00004126 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004127 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4128 {
4129 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4130 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004131 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004132 }
cristybb503372010-05-27 20:51:26 +00004133 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4134 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004135 {
4136 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4137 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004138 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004139 }
4140 offset=(MagickOffsetType) y*cache_info->columns+x;
4141 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004142 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004143 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4144 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4145 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004146 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004147 /*
4148 Return pixel cache.
4149 */
4150 region.x=x;
4151 region.y=y;
4152 region.width=columns;
4153 region.height=rows;
4154 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4155}
4156
4157/*
4158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4159% %
4160% %
4161% %
4162+ 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 %
4163% %
4164% %
4165% %
4166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4167%
4168% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4169% defined by the region rectangle and returns a pointer to the region. This
4170% region is subsequently transferred from the pixel cache with
4171% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4172% pixels are transferred, otherwise a NULL is returned.
4173%
4174% The format of the QueueAuthenticPixelsCache() method is:
4175%
cristy4c08aed2011-07-01 19:47:50 +00004176% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004177% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004178% ExceptionInfo *exception)
4179%
4180% A description of each parameter follows:
4181%
4182% o image: the image.
4183%
4184% o x,y,columns,rows: These values define the perimeter of a region of
4185% pixels.
4186%
4187% o exception: return any errors or warnings in this structure.
4188%
4189*/
cristy4c08aed2011-07-01 19:47:50 +00004190static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004191 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004192 ExceptionInfo *exception)
4193{
4194 CacheInfo
4195 *cache_info;
4196
cristy5c9e6f22010-09-17 17:31:01 +00004197 const int
4198 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004199
cristy4c08aed2011-07-01 19:47:50 +00004200 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004201 *q;
cristy4c08aed2011-07-01 19:47:50 +00004202
cristye7cc7cf2010-09-21 13:26:47 +00004203 assert(image != (const Image *) NULL);
4204 assert(image->signature == MagickSignature);
4205 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004206 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004207 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004208 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004209 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004210 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004211 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004212}
4213
4214/*
4215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4216% %
4217% %
4218% %
4219% Q u e u e A u t h e n t i c P i x e l s %
4220% %
4221% %
4222% %
4223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4224%
4225% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004226% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004227% region is returned, otherwise NULL is returned. The returned pointer may
4228% point to a temporary working buffer for the pixels or it may point to the
4229% final location of the pixels in memory.
4230%
4231% Write-only access means that any existing pixel values corresponding to
4232% the region are ignored. This is useful if the initial image is being
4233% created from scratch, or if the existing pixel values are to be
4234% completely replaced without need to refer to their pre-existing values.
4235% The application is free to read and write the pixel buffer returned by
4236% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4237% initialize the pixel array values. Initializing pixel array values is the
4238% application's responsibility.
4239%
4240% Performance is maximized if the selected region is part of one row, or
4241% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004242% pixels in-place (without a copy) if the image is in memory, or in a
4243% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004244% by the user.
4245%
4246% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004247% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4248% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4249% obtain the meta-content (of type void) corresponding to the region.
4250% Once the Quantum (and/or Quantum) array has been updated, the
4251% changes must be saved back to the underlying image using
4252% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004253%
4254% The format of the QueueAuthenticPixels() method is:
4255%
cristy4c08aed2011-07-01 19:47:50 +00004256% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004257% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004258% ExceptionInfo *exception)
4259%
4260% A description of each parameter follows:
4261%
4262% o image: the image.
4263%
4264% o x,y,columns,rows: These values define the perimeter of a region of
4265% pixels.
4266%
4267% o exception: return any errors or warnings in this structure.
4268%
4269*/
cristy4c08aed2011-07-01 19:47:50 +00004270MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004271 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004272 ExceptionInfo *exception)
4273{
4274 CacheInfo
4275 *cache_info;
4276
cristy2036f5c2010-09-19 21:18:17 +00004277 const int
4278 id = GetOpenMPThreadId();
4279
cristy4c08aed2011-07-01 19:47:50 +00004280 Quantum
cristyacd2ed22011-08-30 01:44:23 +00004281 *q;
cristy4c08aed2011-07-01 19:47:50 +00004282
cristy3ed852e2009-09-05 21:47:34 +00004283 assert(image != (Image *) NULL);
4284 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004285 assert(image->cache != (Cache) NULL);
4286 cache_info=(CacheInfo *) image->cache;
4287 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004288 if (cache_info->methods.queue_authentic_pixels_handler !=
cristyc36c8822012-02-14 14:02:36 +00004289 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004290 {
cristyc36c8822012-02-14 14:02:36 +00004291 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4292 rows,exception);
cristyacd2ed22011-08-30 01:44:23 +00004293 return(q);
cristy4c08aed2011-07-01 19:47:50 +00004294 }
cristy2036f5c2010-09-19 21:18:17 +00004295 assert(id < (int) cache_info->number_threads);
cristyc11dace2012-01-24 16:39:46 +00004296 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
cristy65dbf172011-10-06 17:32:04 +00004297 cache_info->nexus_info[id],exception);
cristyacd2ed22011-08-30 01:44:23 +00004298 return(q);
cristy3ed852e2009-09-05 21:47:34 +00004299}
4300
4301/*
4302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4303% %
4304% %
4305% %
cristy4c08aed2011-07-01 19:47:50 +00004306+ 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 +00004307% %
4308% %
4309% %
4310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4311%
cristy4c08aed2011-07-01 19:47:50 +00004312% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004313% the pixel cache.
4314%
cristy4c08aed2011-07-01 19:47:50 +00004315% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004316%
cristy4c08aed2011-07-01 19:47:50 +00004317% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004318% NexusInfo *nexus_info,ExceptionInfo *exception)
4319%
4320% A description of each parameter follows:
4321%
4322% o cache_info: the pixel cache.
4323%
cristy4c08aed2011-07-01 19:47:50 +00004324% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004325%
4326% o exception: return any errors or warnings in this structure.
4327%
4328*/
cristy4c08aed2011-07-01 19:47:50 +00004329static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004330 NexusInfo *nexus_info,ExceptionInfo *exception)
4331{
4332 MagickOffsetType
4333 count,
4334 offset;
4335
4336 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004337 extent,
4338 length;
cristy3ed852e2009-09-05 21:47:34 +00004339
cristybb503372010-05-27 20:51:26 +00004340 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004341 y;
4342
cristy4c08aed2011-07-01 19:47:50 +00004343 register unsigned char
4344 *restrict q;
4345
cristybb503372010-05-27 20:51:26 +00004346 size_t
cristy3ed852e2009-09-05 21:47:34 +00004347 rows;
4348
cristy4c08aed2011-07-01 19:47:50 +00004349 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004350 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004351 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004352 return(MagickTrue);
4353 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4354 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004355 length=(MagickSizeType) nexus_info->region.width*
4356 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004357 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004358 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004359 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004360 switch (cache_info->type)
4361 {
4362 case MemoryCache:
4363 case MapCache:
4364 {
cristy4c08aed2011-07-01 19:47:50 +00004365 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004366 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004367
4368 /*
cristy4c08aed2011-07-01 19:47:50 +00004369 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004370 */
cristydd341db2010-03-04 19:06:38 +00004371 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004372 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004373 {
cristy48078b12010-09-23 17:11:01 +00004374 length=extent;
cristydd341db2010-03-04 19:06:38 +00004375 rows=1UL;
4376 }
cristy4c08aed2011-07-01 19:47:50 +00004377 p=(unsigned char *) cache_info->metacontent+offset*
4378 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004379 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004380 {
cristy8f036fe2010-09-18 02:02:00 +00004381 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004382 p+=cache_info->metacontent_extent*cache_info->columns;
4383 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004384 }
4385 break;
4386 }
4387 case DiskCache:
4388 {
4389 /*
cristy4c08aed2011-07-01 19:47:50 +00004390 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004391 */
4392 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4393 {
4394 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4395 cache_info->cache_filename);
4396 return(MagickFalse);
4397 }
cristydd341db2010-03-04 19:06:38 +00004398 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004399 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004400 {
cristy48078b12010-09-23 17:11:01 +00004401 length=extent;
cristydd341db2010-03-04 19:06:38 +00004402 rows=1UL;
4403 }
cristy48078b12010-09-23 17:11:01 +00004404 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004405 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004406 {
cristy48078b12010-09-23 17:11:01 +00004407 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004408 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004409 cache_info->metacontent_extent,length,(unsigned char *) q);
4410 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004411 break;
4412 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004413 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004414 }
cristyc11dace2012-01-24 16:39:46 +00004415 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4416 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004417 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004418 {
4419 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4420 cache_info->cache_filename);
4421 return(MagickFalse);
4422 }
4423 break;
4424 }
4425 default:
4426 break;
4427 }
4428 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004429 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004430 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004431 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004432 nexus_info->region.width,(double) nexus_info->region.height,(double)
4433 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004434 return(MagickTrue);
4435}
4436
4437/*
4438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4439% %
4440% %
4441% %
4442+ R e a d P i x e l C a c h e P i x e l s %
4443% %
4444% %
4445% %
4446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447%
4448% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4449% cache.
4450%
4451% The format of the ReadPixelCachePixels() method is:
4452%
4453% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4454% NexusInfo *nexus_info,ExceptionInfo *exception)
4455%
4456% A description of each parameter follows:
4457%
4458% o cache_info: the pixel cache.
4459%
4460% o nexus_info: the cache nexus to read the pixels.
4461%
4462% o exception: return any errors or warnings in this structure.
4463%
4464*/
4465static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4466 NexusInfo *nexus_info,ExceptionInfo *exception)
4467{
4468 MagickOffsetType
4469 count,
4470 offset;
4471
4472 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004473 extent,
4474 length;
cristy3ed852e2009-09-05 21:47:34 +00004475
cristy4c08aed2011-07-01 19:47:50 +00004476 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004477 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004478
cristye076a6e2010-08-15 19:59:43 +00004479 register ssize_t
4480 y;
4481
cristybb503372010-05-27 20:51:26 +00004482 size_t
cristy3ed852e2009-09-05 21:47:34 +00004483 rows;
4484
cristy4c08aed2011-07-01 19:47:50 +00004485 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004486 return(MagickTrue);
4487 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4488 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004489 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004490 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004491 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004492 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004493 q=nexus_info->pixels;
4494 switch (cache_info->type)
4495 {
4496 case MemoryCache:
4497 case MapCache:
4498 {
cristy4c08aed2011-07-01 19:47:50 +00004499 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004500 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004501
4502 /*
4503 Read pixels from memory.
4504 */
cristydd341db2010-03-04 19:06:38 +00004505 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004506 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004507 {
cristy48078b12010-09-23 17:11:01 +00004508 length=extent;
cristydd341db2010-03-04 19:06:38 +00004509 rows=1UL;
4510 }
cristyed231572011-07-14 02:18:59 +00004511 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004512 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004513 {
cristy8f036fe2010-09-18 02:02:00 +00004514 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004515 p+=cache_info->number_channels*cache_info->columns;
4516 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004517 }
4518 break;
4519 }
4520 case DiskCache:
4521 {
4522 /*
4523 Read pixels from disk.
4524 */
4525 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4526 {
4527 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4528 cache_info->cache_filename);
4529 return(MagickFalse);
4530 }
cristydd341db2010-03-04 19:06:38 +00004531 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004532 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004533 {
cristy48078b12010-09-23 17:11:01 +00004534 length=extent;
cristydd341db2010-03-04 19:06:38 +00004535 rows=1UL;
4536 }
cristybb503372010-05-27 20:51:26 +00004537 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004538 {
4539 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004540 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004541 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004542 break;
4543 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004544 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004545 }
cristyc11dace2012-01-24 16:39:46 +00004546 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4547 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00004548 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004549 {
4550 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4551 cache_info->cache_filename);
4552 return(MagickFalse);
4553 }
4554 break;
4555 }
4556 default:
4557 break;
4558 }
4559 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004560 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004561 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004562 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004563 nexus_info->region.width,(double) nexus_info->region.height,(double)
4564 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004565 return(MagickTrue);
4566}
4567
4568/*
4569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4570% %
4571% %
4572% %
4573+ R e f e r e n c e P i x e l C a c h e %
4574% %
4575% %
4576% %
4577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4578%
4579% ReferencePixelCache() increments the reference count associated with the
4580% pixel cache returning a pointer to the cache.
4581%
4582% The format of the ReferencePixelCache method is:
4583%
4584% Cache ReferencePixelCache(Cache cache_info)
4585%
4586% A description of each parameter follows:
4587%
4588% o cache_info: the pixel cache.
4589%
4590*/
cristya6577ff2011-09-02 19:54:26 +00004591MagickPrivate Cache ReferencePixelCache(Cache cache)
cristy3ed852e2009-09-05 21:47:34 +00004592{
4593 CacheInfo
4594 *cache_info;
4595
4596 assert(cache != (Cache *) NULL);
4597 cache_info=(CacheInfo *) cache;
4598 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004599 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004600 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004601 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004602 return(cache_info);
4603}
4604
4605/*
4606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4607% %
4608% %
4609% %
4610+ S e t P i x e l C a c h e M e t h o d s %
4611% %
4612% %
4613% %
4614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4615%
4616% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4617%
4618% The format of the SetPixelCacheMethods() method is:
4619%
4620% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4621%
4622% A description of each parameter follows:
4623%
4624% o cache: the pixel cache.
4625%
4626% o cache_methods: Specifies a pointer to a CacheMethods structure.
4627%
4628*/
cristya6577ff2011-09-02 19:54:26 +00004629MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
cristy3ed852e2009-09-05 21:47:34 +00004630{
4631 CacheInfo
4632 *cache_info;
4633
4634 GetOneAuthenticPixelFromHandler
4635 get_one_authentic_pixel_from_handler;
4636
4637 GetOneVirtualPixelFromHandler
4638 get_one_virtual_pixel_from_handler;
4639
4640 /*
4641 Set cache pixel methods.
4642 */
4643 assert(cache != (Cache) NULL);
4644 assert(cache_methods != (CacheMethods *) NULL);
4645 cache_info=(CacheInfo *) cache;
4646 assert(cache_info->signature == MagickSignature);
4647 if (cache_info->debug != MagickFalse)
4648 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4649 cache_info->filename);
4650 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4651 cache_info->methods.get_virtual_pixel_handler=
4652 cache_methods->get_virtual_pixel_handler;
4653 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4654 cache_info->methods.destroy_pixel_handler=
4655 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004656 if (cache_methods->get_virtual_metacontent_from_handler !=
4657 (GetVirtualMetacontentFromHandler) NULL)
4658 cache_info->methods.get_virtual_metacontent_from_handler=
4659 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004660 if (cache_methods->get_authentic_pixels_handler !=
4661 (GetAuthenticPixelsHandler) NULL)
4662 cache_info->methods.get_authentic_pixels_handler=
4663 cache_methods->get_authentic_pixels_handler;
4664 if (cache_methods->queue_authentic_pixels_handler !=
4665 (QueueAuthenticPixelsHandler) NULL)
4666 cache_info->methods.queue_authentic_pixels_handler=
4667 cache_methods->queue_authentic_pixels_handler;
4668 if (cache_methods->sync_authentic_pixels_handler !=
4669 (SyncAuthenticPixelsHandler) NULL)
4670 cache_info->methods.sync_authentic_pixels_handler=
4671 cache_methods->sync_authentic_pixels_handler;
4672 if (cache_methods->get_authentic_pixels_from_handler !=
4673 (GetAuthenticPixelsFromHandler) NULL)
4674 cache_info->methods.get_authentic_pixels_from_handler=
4675 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004676 if (cache_methods->get_authentic_metacontent_from_handler !=
4677 (GetAuthenticMetacontentFromHandler) NULL)
4678 cache_info->methods.get_authentic_metacontent_from_handler=
4679 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004680 get_one_virtual_pixel_from_handler=
4681 cache_info->methods.get_one_virtual_pixel_from_handler;
4682 if (get_one_virtual_pixel_from_handler !=
4683 (GetOneVirtualPixelFromHandler) NULL)
4684 cache_info->methods.get_one_virtual_pixel_from_handler=
4685 cache_methods->get_one_virtual_pixel_from_handler;
4686 get_one_authentic_pixel_from_handler=
4687 cache_methods->get_one_authentic_pixel_from_handler;
4688 if (get_one_authentic_pixel_from_handler !=
4689 (GetOneAuthenticPixelFromHandler) NULL)
4690 cache_info->methods.get_one_authentic_pixel_from_handler=
4691 cache_methods->get_one_authentic_pixel_from_handler;
4692}
4693
4694/*
4695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4696% %
4697% %
4698% %
4699+ S e t P i x e l C a c h e N e x u s P i x e l s %
4700% %
4701% %
4702% %
4703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4704%
4705% SetPixelCacheNexusPixels() defines the region of the cache for the
4706% specified cache nexus.
4707%
4708% The format of the SetPixelCacheNexusPixels() method is:
4709%
cristy4c08aed2011-07-01 19:47:50 +00004710% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004711% const RectangleInfo *region,NexusInfo *nexus_info,
4712% ExceptionInfo *exception)
4713%
4714% A description of each parameter follows:
4715%
4716% o image: the image.
4717%
4718% o region: A pointer to the RectangleInfo structure that defines the
4719% region of this particular cache nexus.
4720%
4721% o nexus_info: the cache nexus to set.
4722%
4723% o exception: return any errors or warnings in this structure.
4724%
4725*/
cristyabd6e372010-09-15 19:11:26 +00004726
4727static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4728 NexusInfo *nexus_info,ExceptionInfo *exception)
4729{
4730 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4731 return(MagickFalse);
4732 nexus_info->mapped=MagickFalse;
cristy64c3edf2012-04-13 18:50:13 +00004733 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00004734 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004735 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004736 {
4737 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004738 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00004739 nexus_info->length);
4740 }
cristy4c08aed2011-07-01 19:47:50 +00004741 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00004742 {
4743 (void) ThrowMagickException(exception,GetMagickModule(),
4744 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4745 cache_info->filename);
4746 return(MagickFalse);
4747 }
4748 return(MagickTrue);
4749}
4750
cristy4c08aed2011-07-01 19:47:50 +00004751static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004752 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4753{
4754 CacheInfo
4755 *cache_info;
4756
4757 MagickBooleanType
4758 status;
4759
cristy3ed852e2009-09-05 21:47:34 +00004760 MagickSizeType
4761 length,
4762 number_pixels;
4763
cristy3ed852e2009-09-05 21:47:34 +00004764 cache_info=(CacheInfo *) image->cache;
4765 assert(cache_info->signature == MagickSignature);
4766 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00004767 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004768 nexus_info->region=(*region);
cristy10a6c612012-01-29 21:41:05 +00004769 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
cristy3ed852e2009-09-05 21:47:34 +00004770 {
cristybb503372010-05-27 20:51:26 +00004771 ssize_t
cristybad067a2010-02-15 17:20:55 +00004772 x,
4773 y;
cristy3ed852e2009-09-05 21:47:34 +00004774
cristyeaedf062010-05-29 22:36:02 +00004775 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4776 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004777 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4778 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004779 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004780 ((nexus_info->region.width == cache_info->columns) ||
4781 ((nexus_info->region.width % cache_info->columns) == 0)))))
4782 {
4783 MagickOffsetType
4784 offset;
4785
4786 /*
4787 Pixels are accessed directly from memory.
4788 */
4789 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4790 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004791 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004792 offset;
4793 nexus_info->metacontent=(void *) NULL;
4794 if (cache_info->metacontent_extent != 0)
4795 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4796 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00004797 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004798 }
4799 }
4800 /*
4801 Pixels are stored in a cache region until they are synced to the cache.
4802 */
4803 number_pixels=(MagickSizeType) nexus_info->region.width*
4804 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00004805 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004806 if (cache_info->metacontent_extent != 0)
4807 length+=number_pixels*cache_info->metacontent_extent;
4808 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004809 {
4810 nexus_info->length=length;
4811 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4812 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004813 {
4814 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004815 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004816 }
cristy3ed852e2009-09-05 21:47:34 +00004817 }
4818 else
4819 if (nexus_info->length != length)
4820 {
4821 RelinquishCacheNexusPixels(nexus_info);
4822 nexus_info->length=length;
4823 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4824 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004825 {
4826 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00004827 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00004828 }
cristy3ed852e2009-09-05 21:47:34 +00004829 }
4830 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00004831 nexus_info->metacontent=(void *) NULL;
4832 if (cache_info->metacontent_extent != 0)
4833 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00004834 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004835 return(nexus_info->pixels);
4836}
4837
4838/*
4839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4840% %
4841% %
4842% %
4843% 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 %
4844% %
4845% %
4846% %
4847%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4848%
4849% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4850% pixel cache and returns the previous setting. A virtual pixel is any pixel
4851% access that is outside the boundaries of the image cache.
4852%
4853% The format of the SetPixelCacheVirtualMethod() method is:
4854%
cristy387430f2012-02-07 13:09:46 +00004855% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4856% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004857%
4858% A description of each parameter follows:
4859%
4860% o image: the image.
4861%
4862% o virtual_pixel_method: choose the type of virtual pixel.
4863%
cristy387430f2012-02-07 13:09:46 +00004864% o exception: return any errors or warnings in this structure.
4865%
cristy3ed852e2009-09-05 21:47:34 +00004866*/
cristy3d4cb882012-02-07 19:11:26 +00004867
4868static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4869 ExceptionInfo *exception)
4870{
cristy23d198a2012-03-13 13:48:08 +00004871 CacheView
4872 *image_view;
4873
cristy3d4cb882012-02-07 19:11:26 +00004874 CacheInfo
4875 *cache_info;
4876
4877 MagickBooleanType
4878 status;
4879
4880 ssize_t
4881 y;
4882
4883 assert(image != (Image *) NULL);
4884 assert(image->signature == MagickSignature);
4885 if (image->debug != MagickFalse)
4886 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4887 assert(image->cache != (Cache) NULL);
4888 cache_info=(CacheInfo *) image->cache;
4889 assert(cache_info->signature == MagickSignature);
4890 image->matte=MagickTrue;
4891 status=MagickTrue;
cristy23d198a2012-03-13 13:48:08 +00004892 image_view=AcquireCacheView(image);
cristy3d4cb882012-02-07 19:11:26 +00004893#if defined(MAGICKCORE_OPENMP_SUPPORT)
4894 #pragma omp parallel for schedule(static,4) shared(status)
4895#endif
4896 for (y=0; y < (ssize_t) image->rows; y++)
4897 {
cristy3d4cb882012-02-07 19:11:26 +00004898 register Quantum
4899 *restrict q;
4900
4901 register ssize_t
4902 x;
4903
4904 if (status == MagickFalse)
4905 continue;
cristy23d198a2012-03-13 13:48:08 +00004906 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristy3d4cb882012-02-07 19:11:26 +00004907 if (q == (Quantum *) NULL)
4908 {
4909 status=MagickFalse;
4910 continue;
4911 }
4912 for (x=0; x < (ssize_t) image->columns; x++)
4913 {
4914 SetPixelAlpha(image,alpha,q);
4915 q+=GetPixelChannels(image);
4916 }
cristy23d198a2012-03-13 13:48:08 +00004917 status=SyncCacheViewAuthenticPixels(image_view,exception);
cristy3d4cb882012-02-07 19:11:26 +00004918 }
cristy23d198a2012-03-13 13:48:08 +00004919 image_view=DestroyCacheView(image_view);
cristy3d4cb882012-02-07 19:11:26 +00004920 return(status);
4921}
4922
cristy387430f2012-02-07 13:09:46 +00004923MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4924 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004925{
4926 CacheInfo
4927 *cache_info;
4928
4929 VirtualPixelMethod
4930 method;
4931
4932 assert(image != (Image *) NULL);
4933 assert(image->signature == MagickSignature);
4934 if (image->debug != MagickFalse)
4935 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4936 assert(image->cache != (Cache) NULL);
4937 cache_info=(CacheInfo *) image->cache;
4938 assert(cache_info->signature == MagickSignature);
4939 method=cache_info->virtual_pixel_method;
4940 cache_info->virtual_pixel_method=virtual_pixel_method;
cristy387430f2012-02-07 13:09:46 +00004941 switch (virtual_pixel_method)
4942 {
4943 case BackgroundVirtualPixelMethod:
4944 {
4945 if ((image->background_color.matte != MagickFalse) &&
4946 (image->matte == MagickFalse))
cristy3d4cb882012-02-07 19:11:26 +00004947 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004948 break;
4949 }
4950 case TransparentVirtualPixelMethod:
4951 {
4952 if (image->matte == MagickFalse)
cristy3d4cb882012-02-07 19:11:26 +00004953 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
cristy387430f2012-02-07 13:09:46 +00004954 break;
4955 }
4956 default:
4957 break;
4958 }
cristy3ed852e2009-09-05 21:47:34 +00004959 return(method);
4960}
4961
4962/*
4963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4964% %
4965% %
4966% %
4967+ 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 %
4968% %
4969% %
4970% %
4971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4972%
4973% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4974% in-memory or disk cache. The method returns MagickTrue if the pixel region
4975% is synced, otherwise MagickFalse.
4976%
4977% The format of the SyncAuthenticPixelCacheNexus() method is:
4978%
4979% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4980% NexusInfo *nexus_info,ExceptionInfo *exception)
4981%
4982% A description of each parameter follows:
4983%
4984% o image: the image.
4985%
4986% o nexus_info: the cache nexus to sync.
4987%
4988% o exception: return any errors or warnings in this structure.
4989%
4990*/
cristya6577ff2011-09-02 19:54:26 +00004991MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004992 NexusInfo *nexus_info,ExceptionInfo *exception)
4993{
4994 CacheInfo
4995 *cache_info;
4996
4997 MagickBooleanType
4998 status;
4999
5000 /*
5001 Transfer pixels to the cache.
5002 */
5003 assert(image != (Image *) NULL);
5004 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005005 if (image->cache == (Cache) NULL)
5006 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5007 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005008 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005009 if (cache_info->type == UndefinedCache)
5010 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005011 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005012 return(MagickTrue);
5013 assert(cache_info->signature == MagickSignature);
5014 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005015 if ((cache_info->metacontent_extent != 0) &&
5016 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005017 return(MagickFalse);
5018 return(status);
5019}
5020
5021/*
5022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5023% %
5024% %
5025% %
5026+ S y n c A u t h e n t i c P i x e l C a c h e %
5027% %
5028% %
5029% %
5030%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5031%
5032% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5033% or disk cache. The method returns MagickTrue if the pixel region is synced,
5034% otherwise MagickFalse.
5035%
5036% The format of the SyncAuthenticPixelsCache() method is:
5037%
5038% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5039% ExceptionInfo *exception)
5040%
5041% A description of each parameter follows:
5042%
5043% o image: the image.
5044%
5045% o exception: return any errors or warnings in this structure.
5046%
5047*/
5048static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5049 ExceptionInfo *exception)
5050{
5051 CacheInfo
5052 *cache_info;
5053
cristy5c9e6f22010-09-17 17:31:01 +00005054 const int
5055 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005056
cristy4c08aed2011-07-01 19:47:50 +00005057 MagickBooleanType
5058 status;
5059
cristye7cc7cf2010-09-21 13:26:47 +00005060 assert(image != (Image *) NULL);
5061 assert(image->signature == MagickSignature);
5062 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005063 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005064 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005065 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005066 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5067 exception);
5068 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005069}
5070
5071/*
5072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5073% %
5074% %
5075% %
5076% S y n c A u t h e n t i c P i x e l s %
5077% %
5078% %
5079% %
5080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5081%
5082% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5083% The method returns MagickTrue if the pixel region is flushed, otherwise
5084% MagickFalse.
5085%
5086% The format of the SyncAuthenticPixels() method is:
5087%
5088% MagickBooleanType SyncAuthenticPixels(Image *image,
5089% ExceptionInfo *exception)
5090%
5091% A description of each parameter follows:
5092%
5093% o image: the image.
5094%
5095% o exception: return any errors or warnings in this structure.
5096%
5097*/
5098MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5099 ExceptionInfo *exception)
5100{
5101 CacheInfo
5102 *cache_info;
5103
cristy2036f5c2010-09-19 21:18:17 +00005104 const int
5105 id = GetOpenMPThreadId();
5106
cristy4c08aed2011-07-01 19:47:50 +00005107 MagickBooleanType
5108 status;
5109
cristy3ed852e2009-09-05 21:47:34 +00005110 assert(image != (Image *) NULL);
5111 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005112 assert(image->cache != (Cache) NULL);
5113 cache_info=(CacheInfo *) image->cache;
5114 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005115 if (cache_info->methods.sync_authentic_pixels_handler !=
5116 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005117 {
5118 status=cache_info->methods.sync_authentic_pixels_handler(image,
5119 exception);
5120 return(status);
5121 }
cristy2036f5c2010-09-19 21:18:17 +00005122 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005123 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5124 exception);
5125 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005126}
5127
5128/*
5129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5130% %
5131% %
5132% %
cristyd1dd6e42011-09-04 01:46:08 +00005133+ 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 +00005134% %
5135% %
5136% %
5137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5138%
5139% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5140% The method returns MagickTrue if the pixel region is flushed, otherwise
5141% MagickFalse.
5142%
5143% The format of the SyncImagePixelCache() method is:
5144%
5145% MagickBooleanType SyncImagePixelCache(Image *image,
5146% ExceptionInfo *exception)
5147%
5148% A description of each parameter follows:
5149%
5150% o image: the image.
5151%
5152% o exception: return any errors or warnings in this structure.
5153%
5154*/
cristyd1dd6e42011-09-04 01:46:08 +00005155MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
cristy6e437132011-08-12 13:02:19 +00005156 ExceptionInfo *exception)
5157{
5158 CacheInfo
5159 *cache_info;
5160
5161 assert(image != (Image *) NULL);
5162 assert(exception != (ExceptionInfo *) NULL);
5163 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5164 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5165}
5166
5167/*
5168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5169% %
5170% %
5171% %
cristy4c08aed2011-07-01 19:47:50 +00005172+ 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 +00005173% %
5174% %
5175% %
5176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5177%
cristy4c08aed2011-07-01 19:47:50 +00005178% WritePixelCacheMetacontent() writes the meta-content to the specified region
5179% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005180%
cristy4c08aed2011-07-01 19:47:50 +00005181% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005182%
cristy4c08aed2011-07-01 19:47:50 +00005183% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005184% NexusInfo *nexus_info,ExceptionInfo *exception)
5185%
5186% A description of each parameter follows:
5187%
5188% o cache_info: the pixel cache.
5189%
cristy4c08aed2011-07-01 19:47:50 +00005190% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005191%
5192% o exception: return any errors or warnings in this structure.
5193%
5194*/
cristy4c08aed2011-07-01 19:47:50 +00005195static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005196 NexusInfo *nexus_info,ExceptionInfo *exception)
5197{
5198 MagickOffsetType
5199 count,
5200 offset;
5201
5202 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005203 extent,
5204 length;
cristy3ed852e2009-09-05 21:47:34 +00005205
cristy4c08aed2011-07-01 19:47:50 +00005206 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005207 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005208
cristybb503372010-05-27 20:51:26 +00005209 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005210 y;
5211
cristybb503372010-05-27 20:51:26 +00005212 size_t
cristy3ed852e2009-09-05 21:47:34 +00005213 rows;
5214
cristy4c08aed2011-07-01 19:47:50 +00005215 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005216 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005217 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005218 return(MagickTrue);
5219 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5220 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005221 length=(MagickSizeType) nexus_info->region.width*
5222 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005223 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005224 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005225 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005226 switch (cache_info->type)
5227 {
5228 case MemoryCache:
5229 case MapCache:
5230 {
cristy4c08aed2011-07-01 19:47:50 +00005231 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005232 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005233
5234 /*
cristy4c08aed2011-07-01 19:47:50 +00005235 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005236 */
cristydd341db2010-03-04 19:06:38 +00005237 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005238 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005239 {
cristy48078b12010-09-23 17:11:01 +00005240 length=extent;
cristydd341db2010-03-04 19:06:38 +00005241 rows=1UL;
5242 }
cristy4c08aed2011-07-01 19:47:50 +00005243 q=(unsigned char *) cache_info->metacontent+offset*
5244 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005245 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005246 {
cristy8f036fe2010-09-18 02:02:00 +00005247 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005248 p+=nexus_info->region.width*cache_info->metacontent_extent;
5249 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005250 }
5251 break;
5252 }
5253 case DiskCache:
5254 {
5255 /*
cristy4c08aed2011-07-01 19:47:50 +00005256 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005257 */
5258 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5259 {
5260 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5261 cache_info->cache_filename);
5262 return(MagickFalse);
5263 }
cristydd341db2010-03-04 19:06:38 +00005264 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005265 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005266 {
cristy48078b12010-09-23 17:11:01 +00005267 length=extent;
cristydd341db2010-03-04 19:06:38 +00005268 rows=1UL;
5269 }
cristy48078b12010-09-23 17:11:01 +00005270 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005271 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005272 {
cristy48078b12010-09-23 17:11:01 +00005273 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005274 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005275 cache_info->metacontent_extent,length,(const unsigned char *) p);
5276 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005277 break;
cristy4c08aed2011-07-01 19:47:50 +00005278 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005279 offset+=cache_info->columns;
5280 }
cristyc11dace2012-01-24 16:39:46 +00005281 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5282 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005283 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005284 {
5285 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5286 cache_info->cache_filename);
5287 return(MagickFalse);
5288 }
5289 break;
5290 }
5291 default:
5292 break;
5293 }
5294 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005295 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005296 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005297 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005298 nexus_info->region.width,(double) nexus_info->region.height,(double)
5299 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005300 return(MagickTrue);
5301}
5302
5303/*
5304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5305% %
5306% %
5307% %
5308+ W r i t e C a c h e P i x e l s %
5309% %
5310% %
5311% %
5312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5313%
5314% WritePixelCachePixels() writes image pixels to the specified region of the
5315% pixel cache.
5316%
5317% The format of the WritePixelCachePixels() method is:
5318%
5319% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5320% NexusInfo *nexus_info,ExceptionInfo *exception)
5321%
5322% A description of each parameter follows:
5323%
5324% o cache_info: the pixel cache.
5325%
5326% o nexus_info: the cache nexus to write the pixels.
5327%
5328% o exception: return any errors or warnings in this structure.
5329%
5330*/
5331static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5332 NexusInfo *nexus_info,ExceptionInfo *exception)
5333{
5334 MagickOffsetType
5335 count,
5336 offset;
5337
5338 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005339 extent,
5340 length;
cristy3ed852e2009-09-05 21:47:34 +00005341
cristy4c08aed2011-07-01 19:47:50 +00005342 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005343 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005344
cristybb503372010-05-27 20:51:26 +00005345 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005346 y;
5347
cristybb503372010-05-27 20:51:26 +00005348 size_t
cristy3ed852e2009-09-05 21:47:34 +00005349 rows;
5350
cristy4c08aed2011-07-01 19:47:50 +00005351 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005352 return(MagickTrue);
5353 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5354 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005355 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005356 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005357 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005358 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005359 p=nexus_info->pixels;
5360 switch (cache_info->type)
5361 {
5362 case MemoryCache:
5363 case MapCache:
5364 {
cristy4c08aed2011-07-01 19:47:50 +00005365 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005366 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005367
5368 /*
5369 Write pixels to memory.
5370 */
cristydd341db2010-03-04 19:06:38 +00005371 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005372 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005373 {
cristy48078b12010-09-23 17:11:01 +00005374 length=extent;
cristydd341db2010-03-04 19:06:38 +00005375 rows=1UL;
5376 }
cristyed231572011-07-14 02:18:59 +00005377 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005378 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005379 {
cristy8f036fe2010-09-18 02:02:00 +00005380 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005381 p+=nexus_info->region.width*cache_info->number_channels;
5382 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005383 }
5384 break;
5385 }
5386 case DiskCache:
5387 {
5388 /*
5389 Write pixels to disk.
5390 */
5391 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5392 {
5393 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5394 cache_info->cache_filename);
5395 return(MagickFalse);
5396 }
cristydd341db2010-03-04 19:06:38 +00005397 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005398 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005399 {
cristy48078b12010-09-23 17:11:01 +00005400 length=extent;
cristydd341db2010-03-04 19:06:38 +00005401 rows=1UL;
5402 }
cristybb503372010-05-27 20:51:26 +00005403 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005404 {
5405 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005406 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005407 p);
5408 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005409 break;
cristyed231572011-07-14 02:18:59 +00005410 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005411 offset+=cache_info->columns;
5412 }
cristyc11dace2012-01-24 16:39:46 +00005413 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5414 (void) ClosePixelCacheOnDisk(cache_info);
cristybb503372010-05-27 20:51:26 +00005415 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005416 {
5417 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5418 cache_info->cache_filename);
5419 return(MagickFalse);
5420 }
5421 break;
5422 }
5423 default:
5424 break;
5425 }
5426 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005427 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005428 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005429 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005430 nexus_info->region.width,(double) nexus_info->region.height,(double)
5431 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005432 return(MagickTrue);
5433}